* Improved block allocation.

* Made the block_cache KDL command dump a bit more useful info (number of
  referenced and dirty blocks).
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23540 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-01-15 18:03:33 +00:00
parent 86914dfa8e
commit 8264ebf6b7
2 changed files with 65 additions and 25 deletions
+59 -23
View File
@@ -463,25 +463,52 @@ block_cache::FreeBlock(cached_block *block)
} }
cached_block *
block_cache::_GetUnusedBlock()
{
TRACE(("block_cache: get unused block\n"));
for (block_list::Iterator iterator = unused_blocks.GetIterator();
cached_block *block = iterator.Next();) {
// this can only happen if no transactions are used
if (block->is_dirty)
write_cached_block(this, block, false);
// remove block from lists
iterator.Remove();
hash_remove(hash, block);
return block;
}
return NULL;
}
/*! Allocates a new block for \a blockNumber, ready for use */ /*! Allocates a new block for \a blockNumber, ready for use */
cached_block * cached_block *
block_cache::NewBlock(off_t blockNumber) block_cache::NewBlock(off_t blockNumber)
{ {
cached_block *block = new(nothrow) cached_block; cached_block *block = new(nothrow) cached_block;
if (block != NULL) {
block_range *range = GetFreeRange();
if (range == NULL) {
delete block;
block = NULL;
} else
range->Allocate(this, block);
}
if (block == NULL) { if (block == NULL) {
FATAL(("could not allocate block!\n")); dprintf("block allocation failed, unused list is %sempty.\n",
return NULL; unused_blocks.IsEmpty() ? "" : "not ");
}
block_range *range = GetFreeRange(); // allocation failed, try to reuse an unused block
if (range == NULL) { block = _GetUnusedBlock();
FATAL(("could not get range!\n")); if (block == NULL) {
delete block; FATAL(("could not allocate block!\n"));
return NULL; return NULL;
}
} }
range->Allocate(this, block);
block->block_number = blockNumber; block->block_number = blockNumber;
block->ref_count = 0; block->ref_count = 0;
block->accessed = 0; block->accessed = 0;
@@ -504,9 +531,8 @@ block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
{ {
TRACE(("block_cache: remove up to %ld unused blocks\n", count)); TRACE(("block_cache: remove up to %ld unused blocks\n", count));
for (block_list::Iterator it = unused_blocks.GetIterator(); for (block_list::Iterator iterator = unused_blocks.GetIterator();
cached_block *block = it.Next();) { cached_block *block = iterator.Next();) {
if (maxAccessed < block->accessed) if (maxAccessed < block->accessed)
continue; continue;
@@ -518,7 +544,7 @@ block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
write_cached_block(this, block, false); write_cached_block(this, block, false);
// remove block from lists // remove block from lists
it.Remove(); iterator.Remove();
hash_remove(hash, block); hash_remove(hash, block);
FreeBlock(block); FreeBlock(block);
@@ -946,27 +972,37 @@ dump_cache(int argc, char **argv)
if (showBlocks) { if (showBlocks) {
kprintf(" blocks:\n"); kprintf(" blocks:\n");
kprintf("address block no. current original parent refs access flags transact prev. trans\n"); kprintf("address block no. current original parent refs access "
"flags transact prev. trans\n");
} }
uint32 referenced = 0;
uint32 count = 0; uint32 count = 0;
uint32 dirty = 0;
hash_iterator iterator; hash_iterator iterator;
hash_open(cache->hash, &iterator); hash_open(cache->hash, &iterator);
cached_block *block; cached_block *block;
while ((block = (cached_block *)hash_next(cache->hash, &iterator)) != NULL) { while ((block = (cached_block *)hash_next(cache->hash, &iterator)) != NULL) {
if (showBlocks) { if (showBlocks) {
kprintf("%08lx %9Ld %08lx %08lx %08lx %5ld %6ld %c%c%c%c%c %08lx %08lx\n", kprintf("%08lx %9Ld %08lx %08lx %08lx %5ld %6ld %c%c%c%c%c %08lx "
(addr_t)block, block->block_number, (addr_t)block->current_data, "%08lx\n", (addr_t)block, block->block_number,
(addr_t)block->original_data, (addr_t)block->parent_data, (addr_t)block->current_data, (addr_t)block->original_data,
block->ref_count, block->accessed, block->busy ? 'B' : '-', (addr_t)block->parent_data, block->ref_count, block->accessed,
block->is_writing ? 'W' : '-', block->is_dirty ? 'B' : '-', block->busy ? 'B' : '-', block->is_writing ? 'W' : '-',
block->unused ? 'U' : '-', block->unmapped ? 'M' : '-', block->is_dirty ? 'B' : '-', block->unused ? 'U' : '-',
(addr_t)block->transaction, (addr_t)block->previous_transaction); block->unmapped ? 'M' : '-', (addr_t)block->transaction,
(addr_t)block->previous_transaction);
} }
if (block->is_dirty)
dirty++;
if (block->ref_count)
referenced++;
count++; count++;
} }
kprintf(" %ld blocks.\n", count); kprintf(" %ld blocks total, %ld dirty, %ld referenced.\n", count, dirty,
referenced);
hash_close(cache->hash, &iterator, false); hash_close(cache->hash, &iterator, false);
return 0; return 0;
+6 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2006, Axel Dörfler, [email protected]. All rights reserved. * Copyright 2004-2008, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef BLOCK_CACHE_PRIVATE_H #ifndef BLOCK_CACHE_PRIVATE_H
@@ -125,13 +125,17 @@ struct block_cache : DoublyLinkedListLinkImpl<block_cache> {
block_range *GetFreeRange(); block_range *GetFreeRange();
block_range *GetRange(void *address); block_range *GetRange(void *address);
void RemoveUnusedBlocks(int32 maxAccessed = LONG_MAX, 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); static void LowMemoryHandler(void *data, int32 level);
private:
cached_block *_GetUnusedBlock();
}; };