From ca7c5a9e131cb2b1623f2bab9e3bfab65d9561cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 19 Oct 2005 16:46:17 +0000 Subject: [PATCH] Implemented cache_detach_sub_transaction() - not tested yet, though. Added and implemented new functions cache_blocks_in_[sub_]transaction(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14431 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/drivers/fs_cache.h | 4 +- src/system/kernel/cache/block_cache.cpp | 124 ++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 11 deletions(-) diff --git a/headers/os/drivers/fs_cache.h b/headers/os/drivers/fs_cache.h index 9fe253cf2c..8f8cb0b3f3 100644 --- a/headers/os/drivers/fs_cache.h +++ b/headers/os/drivers/fs_cache.h @@ -21,11 +21,13 @@ extern int32 cache_start_transaction(void *_cache); extern status_t cache_sync_transaction(void *_cache, int32 id); extern status_t cache_end_transaction(void *_cache, int32 id, transaction_notification_hook hook, void *data); extern status_t cache_abort_transaction(void *_cache, int32 id); -extern int32 cache_detach_sub_transaction(void *_cache, int32 id); +extern int32 cache_detach_sub_transaction(void *_cache, int32 id, transaction_notification_hook hook, void *data); extern status_t cache_abort_sub_transaction(void *_cache, int32 id); extern status_t cache_start_sub_transaction(void *_cache, int32 id); extern status_t cache_next_block_in_transaction(void *_cache, int32 id, uint32 *_cookie, off_t *_blockNumber, void **_data, void **_unchangedData); +extern int32 cache_blocks_in_transaction(void *_cache, int32 id); +extern int32 cache_blocks_in_sub_transaction(void *_cache, int32 id); /* block cache */ extern void block_cache_delete(void *_cache, bool allowWrites); diff --git a/src/system/kernel/cache/block_cache.cpp b/src/system/kernel/cache/block_cache.cpp index c9e557eeba..c47cd99380 100644 --- a/src/system/kernel/cache/block_cache.cpp +++ b/src/system/kernel/cache/block_cache.cpp @@ -39,9 +39,12 @@ struct cache_transaction { + cache_transaction(); + cache_transaction *next; int32 id; int32 num_blocks; + int32 sub_num_blocks; cached_block *first_block; block_list blocks; transaction_notification_hook notification_hook; @@ -56,6 +59,17 @@ static status_t write_cached_block(block_cache *cache, cached_block *block, bool // #pragma mark - private transaction +cache_transaction::cache_transaction() +{ + num_blocks = 0; + sub_num_blocks = 0; + first_block = NULL; + notification_hook = NULL; + notification_data = NULL; + open = true; +} + + static int transaction_compare(void *_transaction, const void *_id) { @@ -476,6 +490,7 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off } memcpy(block->parent_data, block->data, cache->block_size); + block->transaction->sub_num_blocks++; } if (cleared) @@ -551,11 +566,6 @@ cache_start_transaction(void *_cache) return B_NO_MEMORY; transaction->id = atomic_add(&cache->next_transaction_id, 1); - transaction->num_blocks = 0; - transaction->first_block = NULL; - transaction->notification_hook = NULL; - transaction->notification_data = NULL; - transaction->open = true; cache->last_transaction = transaction; TRACE(("cache_transaction_start(): id %ld started\n", transaction->id)); @@ -629,8 +639,9 @@ cache_end_transaction(void *_cache, int32 id, transaction_notification_hook hook cache->Free(block->original); block->original = NULL; } - if (transaction->has_sub_transaction && block->parent_data != block->data) { - cache->Free(block->parent_data); + if (transaction->has_sub_transaction) { + if (block->parent_data != block->data) + cache->Free(block->parent_data); block->parent_data = NULL; } @@ -690,10 +701,73 @@ cache_abort_transaction(void *_cache, int32 id) extern "C" int32 -cache_detach_sub_transaction(void *_cache, int32 id) +cache_detach_sub_transaction(void *_cache, int32 id, + transaction_notification_hook hook, void *data) { - // ToDo: implement me! - return B_ERROR; + block_cache *cache = (block_cache *)_cache; + BenaphoreLocker locker(&cache->lock); + + TRACE(("cache_end_transaction(id = %ld)\n", id)); + + cache_transaction *transaction = lookup_transaction(cache, id); + if (transaction == NULL) { + panic("cache_end_transaction(): invalid transaction ID\n"); + return B_BAD_VALUE; + } + if (!transaction->has_sub_transaction) + return B_BAD_VALUE; + + // create a new transaction for the sub transaction + cache_transaction *newTransaction = new cache_transaction; + if (transaction == NULL) + return B_NO_MEMORY; + + newTransaction->id = atomic_add(&cache->next_transaction_id, 1); + + transaction->notification_hook = hook; + transaction->notification_data = data; + + // iterate through all blocks and free the unchanged original contents + + cached_block *block = transaction->first_block, *next, *last = NULL; + for (; block != NULL; block = next) { + next = block->transaction_next; + + if (block->previous_transaction != NULL) { + // need to write back pending changes + write_cached_block(cache, block); + } + + if (block->original != NULL) { + cache->Free(block->original); + block->original = NULL; + } + if (block->parent_data != block->data) { + // we need to move this block over to the new transaction + block->original = block->parent_data; + if (last == NULL) + newTransaction->first_block = block; + else + last->transaction_next = block; + + last = block; + } + block->parent_data = NULL; + + // move the block to the previous transaction list + transaction->blocks.Add(block); + + block->previous_transaction = transaction; + block->transaction_next = NULL; + block->transaction = newTransaction; + } + + transaction->open = false; + + hash_insert(cache->transaction_hash, newTransaction); + cache->last_transaction = newTransaction; + + return B_OK; } @@ -781,6 +855,8 @@ panic("unchanged block in transaction!"); // all subsequent changes will go into the sub transaction transaction->has_sub_transaction = true; + transaction->sub_num_blocks = 0; + return B_OK; } @@ -818,6 +894,34 @@ cache_next_block_in_transaction(void *_cache, int32 id, uint32 *_cookie, off_t * } +extern "C" int32 +cache_blocks_in_transaction(void *_cache, int32 id) +{ + block_cache *cache = (block_cache *)_cache; + BenaphoreLocker locker(&cache->lock); + + cache_transaction *transaction = lookup_transaction(cache, id); + if (transaction == NULL) + return B_BAD_VALUE; + + return transaction->num_blocks; +} + + +extern "C" int32 +cache_blocks_in_sub_transaction(void *_cache, int32 id) +{ + block_cache *cache = (block_cache *)_cache; + BenaphoreLocker locker(&cache->lock); + + cache_transaction *transaction = lookup_transaction(cache, id); + if (transaction == NULL) + return B_BAD_VALUE; + + return transaction->sub_num_blocks; +} + + // #pragma mark - public block cache // public interface