* cache_detach_sub_transaction(), and cache_abort_sub_transaction() now support

discarded blocks correctly as well.
* cache_detach_sub_transaction() left cached_block::original_data unchanged even
  if the parent data was to become current (in case the sub transaction didn't
  change the block yet). This could cause outdated blocks to be written back.
* cache_detach_sub_transaction() also set cached_block::previous_transaction
  for all blocks, not just the ones with a previous transaction. This could
  cause blocks to be written twice for no reason.
* cache_start_sub_transaction() did not change the num_blocks count for
  discarded blocks.
* block_cache_discard() now panics if the block was already changed in the
  current transaction.
* Improved test application, added more tests, revealing the above bugs in
  cache_detach_sub_transaction().
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28514 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-11-05 13:52:34 +00:00
parent 2ecc2162bb
commit a26045b7a6
2 changed files with 289 additions and 69 deletions
+21 -7
View File
@@ -566,6 +566,8 @@ notify_transaction_listeners(block_cache* cache, cache_transaction* transaction,
static void
flush_pending_notifications(block_cache* cache)
{
ASSERT_LOCKED_MUTEX(&sCachesLock);
while (true) {
MutexLocker locker(sNotificationsLock);
@@ -1203,11 +1205,11 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
if (cleared)
memset(block->current_data, 0, cache->block_size);
if (!block->is_dirty)
if (!block->is_dirty) {
cache->num_dirty_blocks++;
block->is_dirty = true;
// mark the block as dirty
block->is_dirty = true;
// mark the block as dirty
}
TB(Get(cache, block));
return block->current_data;
@@ -2112,9 +2114,13 @@ cache_detach_sub_transaction(void* _cache, int32 id,
// need to write back pending changes
write_cached_block(cache, block);
}
if (block->discard) {
cache->DiscardBlock(block);
transaction->main_num_blocks--;
continue;
}
if (block->original_data != NULL && block->parent_data != NULL
&& block->parent_data != block->current_data) {
if (block->original_data != NULL && block->parent_data != NULL) {
// free the original data if the parent data of the transaction
// will be made current - but keep them otherwise
cache->Free(block->original_data);
@@ -2137,10 +2143,10 @@ cache_detach_sub_transaction(void* _cache, int32 id,
if (block->parent_data != NULL) {
// move the block to the previous transaction list
transaction->blocks.Add(block);
block->previous_transaction = transaction;
block->parent_data = NULL;
}
block->previous_transaction = transaction;
block->transaction_next = NULL;
}
@@ -2200,6 +2206,7 @@ cache_abort_sub_transaction(void* _cache, int32 id)
}
block->parent_data = NULL;
block->discard = false;
}
// all subsequent changes will go into the main transaction
@@ -2242,6 +2249,7 @@ cache_start_sub_transaction(void* _cache, int32 id)
transaction->first_block = next;
cache->DiscardBlock(block);
transaction->num_blocks--;
continue;
}
if (transaction->has_sub_transaction
@@ -2556,6 +2564,12 @@ block_cache_discard(void* _cache, off_t blockNumber, size_t numBlocks)
cache->unused_blocks.Remove(block);
cache->RemoveBlock(block);
} else {
if (block->transaction != NULL && block->parent_data != NULL
&& block->parent_data != block->current_data) {
panic("Discarded block %Ld has already been changed in this "
"transaction!", blockNumber);
}
// mark it as discarded (in the current transaction only, if any)
block->discard = true;
}