* While reading in a block, the block is now marked busy, and the cache

unlocked, allowing for more parallel access.
* Writing is still done synchronously, though.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34611 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-12-10 10:29:37 +00:00
parent d470839990
commit 33c82a30c0
+53 -5
View File
@@ -109,6 +109,9 @@ struct block_cache : DoublyLinkedListLinkImpl<block_cache> {
object_cache* buffer_cache;
block_list unused_blocks;
ConditionVariable busy_condition;
uint32 busy_count;
uint32 num_dirty_blocks;
bool read_only;
@@ -929,6 +932,7 @@ block_cache::block_cache(int _fd, off_t numBlocks, size_t blockSize,
last_transaction(NULL),
transaction_hash(NULL),
buffer_cache(NULL),
busy_count(0),
num_dirty_blocks(0),
read_only(readOnly)
{
@@ -952,6 +956,7 @@ block_cache::~block_cache()
status_t
block_cache::Init()
{
busy_condition.Init(this, "cache block busy");
condition_variable.Init(this, "cache transaction sync");
mutex_init(&lock, "block cache");
@@ -1058,6 +1063,8 @@ block_cache::NewBlock(off_t blockNumber)
block->transaction = block->previous_transaction = NULL;
block->original_data = NULL;
block->parent_data = NULL;
block->busy = false;
block->is_writing = false;
block->is_dirty = false;
block->unused = false;
block->discard = false;
@@ -1287,40 +1294,61 @@ put_cached_block(block_cache* cache, off_t blockNumber)
/*! Retrieves the block \a blockNumber from the hash table, if it's already
there, or reads it from the disk.
You need to have the cache locked when calling this function.
\param _allocated tells you wether or not a new block has been allocated
to satisfy your request.
\param readBlock if \c false, the block will not be read in case it was
not already in the cache. The block you retrieve may contain random
data.
data. If \c true, the cache will be temporarily unlocked while the
block is read in.
*/
static cached_block*
get_cached_block(block_cache* cache, off_t blockNumber, bool* _allocated,
bool readBlock = true)
{
ASSERT_LOCKED_MUTEX(&cache->lock);
if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
panic("get_cached_block: invalid block number %lld (max %lld)",
blockNumber, cache->max_blocks - 1);
return NULL;
}
retry:
cached_block* block = (cached_block*)hash_lookup(cache->hash,
&blockNumber);
*_allocated = false;
if (block == NULL) {
// read block into cache
// put block into cache
block = cache->NewBlock(blockNumber);
if (block == NULL)
return NULL;
hash_insert_grow(cache->hash, block);
*_allocated = true;
} else if (block->busy) {
// The block is currently busy - wait and try again later
ConditionVariableEntry entry;
cache->busy_condition.Add(&entry);
mutex_unlock(&cache->lock);
entry.Wait();
mutex_lock(&cache->lock);
goto retry;
}
if (*_allocated && readBlock) {
// read block into cache
int32 blockSize = cache->block_size;
cache->busy_count++;
block->busy = true;
mutex_unlock(&cache->lock);
ssize_t bytesRead = read_pos(cache->fd, blockNumber * blockSize,
block->current_data, blockSize);
if (bytesRead < blockSize) {
@@ -1332,6 +1360,12 @@ get_cached_block(block_cache* cache, off_t blockNumber, bool* _allocated,
return NULL;
}
TB(Read(cache, block));
mutex_lock(&cache->lock);
block->busy = false;
cache->busy_count--;
cache->busy_condition.NotifyAll();
}
if (block->unused) {
@@ -1602,6 +1636,8 @@ dump_cache(int argc, char** argv)
kprintf(" ref_count: %ld\n", block->ref_count);
kprintf(" accessed: %ld\n", block->accessed);
kprintf(" flags: ");
if (block->busy)
kprintf(" busy");
if (block->is_writing)
kprintf(" is-writing");
if (block->is_dirty)
@@ -1698,8 +1734,8 @@ dump_cache(int argc, char** argv)
}
kprintf(" %ld blocks total, %ld dirty, %ld discarded, %ld referenced, %ld "
"in unused.\n", count, dirty, discarded, referenced,
cache->unused_blocks.Count());
"busy, %ld in unused.\n", count, dirty, discarded, referenced,
cache->busy_count, cache->unused_blocks.Count());
hash_close(cache->hash, &iterator, false);
return 0;
@@ -1980,7 +2016,7 @@ block_notifier_and_writer(void* /*data*/)
while (count < kMaxCount
&& (block = (cached_block*)hash_next(cache->hash,
&iterator)) != NULL) {
if (block->is_dirty)
if (block->is_dirty && !block->is_writing)
blocks[count++] = block;
}
@@ -2740,6 +2776,18 @@ block_cache_delete(void* _cache, bool allowWrites)
mutex_lock(&cache->lock);
while (cache->busy_count != 0) {
// wait for all blocks to be read in/written back
ConditionVariableEntry entry;
cache->busy_condition.Add(&entry);
mutex_unlock(&cache->lock);
entry.Wait();
mutex_lock(&cache->lock);
}
// free all blocks
uint32 cookie = 0;