* Added a transaction listener mechanism to be notified when a

transaction ends or has been aborted.
* BFS now listens for transactions when it created an inode to see if 
  the transaction will be aborted without freeing the inode (in which 
  case it will panic for now).
* Started implementing tracing support, but it's not working yet.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23492 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-01-13 17:18:29 +00:00
parent 5276dad057
commit 4fc4f2c8ae
9 changed files with 298 additions and 17 deletions
+93 -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.
*/
@@ -45,6 +45,12 @@ namespace FSShell {
static const int32_t kMaxBlockCount = 1024;
struct cache_hook : DoublyLinkedListLinkImpl<cache_hook> {
fssh_transaction_notification_hook hook;
void *data;
};
typedef DoublyLinkedList<cache_hook> HookList;
struct cache_transaction {
cache_transaction();
@@ -57,6 +63,7 @@ struct cache_transaction {
block_list blocks;
fssh_transaction_notification_hook notification_hook;
void *notification_data;
HookList listeners;
bool open;
bool has_sub_transaction;
};
@@ -102,6 +109,24 @@ transaction_hash(void *_transaction, const void *_id, uint32_t range)
}
/*! Notifies all listeners of this transaction, and removes them
afterwards.
*/
static void
notify_transaction_listeners(cache_transaction *transaction, int32_t event)
{
HookList::Iterator iterator = transaction->listeners.GetIterator();
while (iterator.HasNext()) {
cache_hook *hook = iterator.Next();
hook->hook(transaction->id, event, hook->data);
iterator.Remove();
delete hook;
}
}
static void
delete_transaction(block_cache *cache, cache_transaction *transaction)
{
@@ -570,7 +595,7 @@ write_cached_block(block_cache *cache, cached_block *block,
if (previous->notification_hook != NULL) {
previous->notification_hook(previous->id,
previous->notification_data);
FSSH_TRANSACTION_WRITTEN, previous->notification_data);
}
if (deleteTransaction) {
@@ -678,6 +703,8 @@ fssh_cache_end_transaction(void *_cache, int32_t id,
transaction->notification_hook = hook;
transaction->notification_data = data;
notify_transaction_listeners(transaction, FSSH_TRANSACTION_ENDED);
// iterate through all blocks and free the unchanged original contents
cached_block *block = transaction->first_block, *next;
@@ -727,6 +754,8 @@ fssh_cache_abort_transaction(void *_cache, int32_t id)
return FSSH_B_BAD_VALUE;
}
notify_transaction_listeners(transaction, FSSH_TRANSACTION_ABORTED);
// iterate through all blocks and restore their original contents
cached_block *block = transaction->first_block, *next;
@@ -788,6 +817,8 @@ fssh_cache_detach_sub_transaction(void *_cache, int32_t id,
transaction->notification_hook = hook;
transaction->notification_data = data;
notify_transaction_listeners(transaction, FSSH_TRANSACTION_ENDED);
// iterate through all blocks and free the unchanged original contents
cached_block *block = transaction->first_block, *next, *last = NULL;
@@ -852,6 +883,8 @@ fssh_cache_abort_sub_transaction(void *_cache, int32_t id)
if (!transaction->has_sub_transaction)
return FSSH_B_BAD_VALUE;
notify_transaction_listeners(transaction, FSSH_TRANSACTION_ABORTED);
// revert all changes back to the version of the parent
cached_block *block = transaction->first_block, *next;
@@ -896,6 +929,8 @@ fssh_cache_start_sub_transaction(void *_cache, int32_t id)
return FSSH_B_BAD_VALUE;
}
notify_transaction_listeners(transaction, FSSH_TRANSACTION_ENDED);
// move all changed blocks up to the parent
cached_block *block = transaction->first_block, *next;
@@ -923,6 +958,62 @@ fssh_cache_start_sub_transaction(void *_cache, int32_t id)
}
/*! Adds a transaction listener that gets notified when the transaction
is ended or aborted.
The listener gets automatically removed in this case.
*/
fssh_status_t
fssh_cache_add_transaction_listener(void *_cache, int32_t id,
fssh_transaction_notification_hook hookFunction, void *data)
{
block_cache *cache = (block_cache *)_cache;
cache_hook *hook = new(std::nothrow) cache_hook;
if (hook == NULL)
return FSSH_B_NO_MEMORY;
BenaphoreLocker locker(&cache->lock);
cache_transaction *transaction = lookup_transaction(cache, id);
if (transaction == NULL) {
delete hook;
return FSSH_B_BAD_VALUE;
}
hook->hook = hookFunction;
hook->data = data;
transaction->listeners.Add(hook);
return FSSH_B_OK;
}
fssh_status_t
fssh_cache_remove_transaction_listener(void *_cache, int32_t id,
fssh_transaction_notification_hook hookFunction, void *data)
{
block_cache *cache = (block_cache *)_cache;
BenaphoreLocker locker(&cache->lock);
cache_transaction *transaction = lookup_transaction(cache, id);
if (transaction == NULL)
return FSSH_B_BAD_VALUE;
HookList::Iterator iterator = transaction->listeners.GetIterator();
while (iterator.HasNext()) {
cache_hook *hook = iterator.Next();
if (hook->data == data && hook->hook == hookFunction) {
iterator.Remove();
delete hook;
return FSSH_B_OK;
}
}
return FSSH_B_ENTRY_NOT_FOUND;
}
fssh_status_t
fssh_cache_next_block_in_transaction(void *_cache, int32_t id, uint32_t *_cookie,
fssh_off_t *_blockNumber, void **_data, void **_unchangedData)