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
This commit is contained in:
Axel Dörfler 2005-10-19 16:46:17 +00:00
parent 6ded062819
commit ca7c5a9e13
2 changed files with 117 additions and 11 deletions

View File

@ -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_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_end_transaction(void *_cache, int32 id, transaction_notification_hook hook, void *data);
extern status_t cache_abort_transaction(void *_cache, int32 id); 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_abort_sub_transaction(void *_cache, int32 id);
extern status_t cache_start_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, extern status_t cache_next_block_in_transaction(void *_cache, int32 id, uint32 *_cookie,
off_t *_blockNumber, void **_data, void **_unchangedData); 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 */ /* block cache */
extern void block_cache_delete(void *_cache, bool allowWrites); extern void block_cache_delete(void *_cache, bool allowWrites);

View File

@ -39,9 +39,12 @@
struct cache_transaction { struct cache_transaction {
cache_transaction();
cache_transaction *next; cache_transaction *next;
int32 id; int32 id;
int32 num_blocks; int32 num_blocks;
int32 sub_num_blocks;
cached_block *first_block; cached_block *first_block;
block_list blocks; block_list blocks;
transaction_notification_hook notification_hook; 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 // #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 static int
transaction_compare(void *_transaction, const void *_id) 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); memcpy(block->parent_data, block->data, cache->block_size);
block->transaction->sub_num_blocks++;
} }
if (cleared) if (cleared)
@ -551,11 +566,6 @@ cache_start_transaction(void *_cache)
return B_NO_MEMORY; return B_NO_MEMORY;
transaction->id = atomic_add(&cache->next_transaction_id, 1); 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; cache->last_transaction = transaction;
TRACE(("cache_transaction_start(): id %ld started\n", transaction->id)); 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); cache->Free(block->original);
block->original = NULL; block->original = NULL;
} }
if (transaction->has_sub_transaction && block->parent_data != block->data) { if (transaction->has_sub_transaction) {
cache->Free(block->parent_data); if (block->parent_data != block->data)
cache->Free(block->parent_data);
block->parent_data = NULL; block->parent_data = NULL;
} }
@ -690,10 +701,73 @@ cache_abort_transaction(void *_cache, int32 id)
extern "C" int32 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! block_cache *cache = (block_cache *)_cache;
return B_ERROR; 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 // all subsequent changes will go into the sub transaction
transaction->has_sub_transaction = true; transaction->has_sub_transaction = true;
transaction->sub_num_blocks = 0;
return B_OK; 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 // #pragma mark - public block cache
// public interface // public interface