cache_abort_sub_transaction() did not maintain num_blocks.

* When a block was only used in a sub-transaction, it was thrown away,
  but the transaction::num_blocks field was not decremented.
* This caused transactions never considered finished which eventually
  led to bug #8942. This does not explain the disk corruption occurring
  in #8969, though.
This commit is contained in:
Axel Dörfler
2012-09-19 20:06:19 +02:00
parent d4cc0de33e
commit 8c3a938fc3
2 changed files with 37 additions and 3 deletions
+2
View File
@@ -3059,6 +3059,8 @@ cache_abort_sub_transaction(void* _cache, int32 id)
block->transaction_next = NULL;
block->transaction = NULL;
transaction->num_blocks--;
if (block->previous_transaction == NULL) {
cache->Free(block->original_data);
block->original_data = NULL;
+35 -3
View File
@@ -20,6 +20,8 @@
#define TEST_BLOCKS(number, count) \
test_blocks(number, count, __LINE__)
#define TEST_TRANSACTION(id, num, mainNum, subNum) \
test_transaction(id, num, mainNum, subNum, __LINE__)
#define TEST_BLOCK_DATA(block, number, type) \
if ((block)->type ## _data != NULL && gBlocks[(number)]. type == 0) \
@@ -157,6 +159,28 @@ init_test_blocks()
}
void
test_transaction(int32 id, int32 numBlocks, int32 numMainBlocks,
int32 numSubBlocks, int32 line)
{
MutexLocker locker(&gCache->lock);
cache_transaction* transaction = lookup_transaction(gCache, id);
if (numBlocks != transaction->num_blocks) {
error(line, "Transaction %d has wrong num_blocks (is %d, should be "
"%d)!", id, transaction->num_blocks, numBlocks);
}
if (numMainBlocks != transaction->main_num_blocks) {
error(line, "Transaction %d has wrong num_blocks (is %d, should be "
"%d)!", id, transaction->main_num_blocks, numMainBlocks);
}
if (numSubBlocks != transaction->sub_num_blocks) {
error(line, "Transaction %d has wrong num_blocks (is %d, should be "
"%d)!", id, transaction->sub_num_blocks, numSubBlocks);
}
}
void
test_blocks(off_t number, int32 count, int32 line)
{
@@ -391,7 +415,9 @@ test_abort_sub_transaction()
block_cache_put(gCache, 1);
TEST_TRANSACTION(id, 2, 2, 1);
cache_abort_sub_transaction(gCache, id);
TEST_TRANSACTION(id, 2, 2, 0);
gBlocks[0].write = true;
gBlocks[0].is_dirty = false;
@@ -417,7 +443,9 @@ test_abort_sub_transaction()
gBlocks[1].is_dirty = true;
TEST_BLOCKS(1, 1);
TEST_TRANSACTION(id, 1, 0, 0);
cache_start_sub_transaction(gCache, id);
TEST_TRANSACTION(id, 1, 1, 0);
gBlocks[0].present = true;
@@ -427,7 +455,9 @@ test_abort_sub_transaction()
block_cache_put(gCache, 0);
TEST_TRANSACTION(id, 2, 1, 1);
cache_abort_sub_transaction(gCache, id);
TEST_TRANSACTION(id, 1, 1, 0);
gBlocks[0].write = false;
gBlocks[0].is_dirty = false;
@@ -445,9 +475,6 @@ test_abort_sub_transaction()
void
test_block_cache_discard()
{
// TODO: test transaction-less block caches
// TODO: test read-only block caches
// Test transactions and block caches
start_test("Discard in main");
@@ -469,11 +496,14 @@ test_block_cache_discard()
gBlocks[2].present = false;
TEST_TRANSACTION(id, 1, 0, 0);
block = block_cache_get_empty(gCache, 2, id);
TEST_TRANSACTION(id, 2, 0, 0);
block_cache_discard(gCache, 2, 1);
block_cache_put(gCache, 2);
cache_end_transaction(gCache, id, NULL, NULL);
TEST_TRANSACTION(id, 1, 0, 0);
cache_sync_transaction(gCache, id);
start_test("Discard in sub");
@@ -606,6 +636,8 @@ main(int argc, char** argv)
{
block_cache_init();
// TODO: test transaction-less block caches
// TODO: test read-only block caches
test_abort_transaction();
test_abort_sub_transaction();
test_block_cache_discard();