The block cache now registers and uses a low memory handler that will flush
unused blocks when needed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15561 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+2
@@ -212,6 +212,8 @@ block_range::New(block_cache *cache, block_range **_range)
|
|||||||
void
|
void
|
||||||
block_range::Delete(block_cache *cache, block_range *range)
|
block_range::Delete(block_cache *cache, block_range *range)
|
||||||
{
|
{
|
||||||
|
TRACE(("delete block range %p, base = %p!\n", range, (void *)range->base));
|
||||||
|
|
||||||
// unmap the memory
|
// unmap the memory
|
||||||
|
|
||||||
vm_address_space *addressSpace = vm_get_kernel_aspace();
|
vm_address_space *addressSpace = vm_get_kernel_aspace();
|
||||||
|
|||||||
+60
-4
@@ -175,11 +175,15 @@ block_cache::block_cache(int _fd, off_t numBlocks, size_t blockSize)
|
|||||||
chunks_per_range = kBlockRangeSize / chunk_size;
|
chunks_per_range = kBlockRangeSize / chunk_size;
|
||||||
range_mask = (1UL << chunks_per_range) - 1;
|
range_mask = (1UL << chunks_per_range) - 1;
|
||||||
chunk_mask = (1UL << (chunk_size / blockSize)) - 1;
|
chunk_mask = (1UL << (chunk_size / blockSize)) - 1;
|
||||||
|
|
||||||
|
register_low_memory_handler(&block_cache::LowMemoryHandler, this, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
block_cache::~block_cache()
|
block_cache::~block_cache()
|
||||||
{
|
{
|
||||||
|
unregister_low_memory_handler(&block_cache::LowMemoryHandler, this);
|
||||||
|
|
||||||
benaphore_destroy(&lock);
|
benaphore_destroy(&lock);
|
||||||
|
|
||||||
hash_uninit(ranges_hash);
|
hash_uninit(ranges_hash);
|
||||||
@@ -291,6 +295,7 @@ block_cache::NewBlock(off_t blockNumber)
|
|||||||
|
|
||||||
block->block_number = blockNumber;
|
block->block_number = blockNumber;
|
||||||
block->ref_count = 0;
|
block->ref_count = 0;
|
||||||
|
block->accessed = 0;
|
||||||
block->transaction_next = NULL;
|
block->transaction_next = NULL;
|
||||||
block->transaction = block->previous_transaction = NULL;
|
block->transaction = block->previous_transaction = NULL;
|
||||||
block->original = NULL;
|
block->original = NULL;
|
||||||
@@ -308,22 +313,71 @@ block_cache::NewBlock(off_t blockNumber)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
block_cache::RemoveUnusedBlocks(int32 count)
|
block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
|
||||||
{
|
{
|
||||||
while (count-- >= 0) {
|
dprintf("block_cache: remove up to %ld unused blocks\n", count);
|
||||||
cached_block *block = unused_blocks.First();
|
|
||||||
|
cached_block *next = NULL;
|
||||||
|
for (cached_block *block = unused_blocks.First(); block != NULL; block = next) {
|
||||||
|
next = block->next;
|
||||||
|
|
||||||
if (block == NULL)
|
if (block == NULL)
|
||||||
break;
|
break;
|
||||||
|
if (maxAccessed < block->accessed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dprintf(" remove block %Ld, accessed %ld times\n",
|
||||||
|
block->block_number, block->accessed);
|
||||||
|
|
||||||
// remove block from lists
|
// remove block from lists
|
||||||
unused_blocks.Remove(block);
|
unused_blocks.Remove(block);
|
||||||
hash_remove(hash, block);
|
hash_remove(hash, block);
|
||||||
|
|
||||||
FreeBlock(block);
|
FreeBlock(block);
|
||||||
|
|
||||||
|
if (--count <= 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
block_cache::LowMemoryHandler(void *data, int32 level)
|
||||||
|
{
|
||||||
|
block_cache *cache = (block_cache *)data;
|
||||||
|
BenaphoreLocker locker(&cache->lock);
|
||||||
|
|
||||||
|
dprintf("block_cache: low memory handler called with level %ld\n", level);
|
||||||
|
|
||||||
|
// free some blocks according to the low memory state
|
||||||
|
// (if there is enough memory left, we don't free any)
|
||||||
|
|
||||||
|
int32 free = 1;
|
||||||
|
int32 accessed = 1;
|
||||||
|
switch (vm_low_memory_state()) {
|
||||||
|
case B_NO_LOW_MEMORY:
|
||||||
|
return;
|
||||||
|
case B_LOW_MEMORY_NOTE:
|
||||||
|
free = 10;
|
||||||
|
accessed = 2;
|
||||||
|
break;
|
||||||
|
case B_LOW_MEMORY_WARNING:
|
||||||
|
free = 50;
|
||||||
|
accessed = 10;
|
||||||
|
break;
|
||||||
|
case B_LOW_MEMORY_CRITICAL:
|
||||||
|
free = LONG_MAX;
|
||||||
|
accessed = LONG_MAX;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->RemoveUnusedBlocks(accessed, free);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_CHANGED
|
#ifdef DEBUG_CHANGED
|
||||||
|
|
||||||
#define DUMPED_BLOCK_SIZE 16
|
#define DUMPED_BLOCK_SIZE 16
|
||||||
@@ -409,7 +463,7 @@ put_cached_block(block_cache *cache, cached_block *block)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->RemoveUnusedBlocks(free);
|
cache->RemoveUnusedBlocks(LONG_MAX, free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -469,6 +523,8 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool &allocated, bool re
|
|||||||
}
|
}
|
||||||
|
|
||||||
block->ref_count++;
|
block->ref_count++;
|
||||||
|
block->accessed++;
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -42,6 +42,7 @@ struct cached_block {
|
|||||||
void *compare;
|
void *compare;
|
||||||
#endif
|
#endif
|
||||||
int32 ref_count;
|
int32 ref_count;
|
||||||
|
int32 accessed;
|
||||||
bool busy : 1;
|
bool busy : 1;
|
||||||
bool is_writing : 1;
|
bool is_writing : 1;
|
||||||
bool is_dirty : 1;
|
bool is_dirty : 1;
|
||||||
@@ -89,8 +90,6 @@ struct block_range {
|
|||||||
|
|
||||||
static int Compare(void *_blockRange, const void *_address);
|
static int Compare(void *_blockRange, const void *_address);
|
||||||
static uint32 Hash(void *_blockRange, const void *_address, uint32 range);
|
static uint32 Hash(void *_blockRange, const void *_address, uint32 range);
|
||||||
|
|
||||||
//bool HasFreeBlocks() const { return (1L << num_chunks) - 1 != used_mask; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct block_cache {
|
struct block_cache {
|
||||||
@@ -119,11 +118,13 @@ struct block_cache {
|
|||||||
|
|
||||||
block_range *GetFreeRange();
|
block_range *GetFreeRange();
|
||||||
block_range *GetRange(void *address);
|
block_range *GetRange(void *address);
|
||||||
void RemoveUnusedBlocks(int32 count = LONG_MAX);
|
void RemoveUnusedBlocks(int32 maxAccessed = LONG_MAX, int32 count = LONG_MAX);
|
||||||
void FreeBlock(cached_block *block);
|
void FreeBlock(cached_block *block);
|
||||||
cached_block *NewBlock(off_t blockNumber);
|
cached_block *NewBlock(off_t blockNumber);
|
||||||
void Free(void *address);
|
void Free(void *address);
|
||||||
void *Allocate();
|
void *Allocate();
|
||||||
|
|
||||||
|
static void LowMemoryHandler(void *data, int32 level);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2753,6 +2753,8 @@ vm_try_reserve_memory(size_t amount)
|
|||||||
status_t status;
|
status_t status;
|
||||||
benaphore_lock(&sAvailableMemoryLock);
|
benaphore_lock(&sAvailableMemoryLock);
|
||||||
|
|
||||||
|
//dprintf("try to reserve %lu bytes, %Lu left\n", amount, sAvailableMemory);
|
||||||
|
|
||||||
if (sAvailableMemory > amount) {
|
if (sAvailableMemory > amount) {
|
||||||
sAvailableMemory -= amount;
|
sAvailableMemory -= amount;
|
||||||
status = B_OK;
|
status = B_OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user