|
|
|
@ -201,7 +201,7 @@ TEST(WriteBatchWithIndex, SubBatchCnt) { |
|
|
|
|
Options options; |
|
|
|
|
options.create_if_missing = true; |
|
|
|
|
const std::string dbname = test::PerThreadDBPath("transaction_testdb"); |
|
|
|
|
DestroyDB(dbname, options); |
|
|
|
|
EXPECT_OK(DestroyDB(dbname, options)); |
|
|
|
|
ASSERT_OK(DB::Open(options, dbname, &db)); |
|
|
|
|
ColumnFamilyHandle* cf_handle = nullptr; |
|
|
|
|
ASSERT_OK(db->CreateColumnFamily(cf_options, cf_name, &cf_handle)); |
|
|
|
@ -215,18 +215,18 @@ TEST(WriteBatchWithIndex, SubBatchCnt) { |
|
|
|
|
batch_cnt_at.push_back(batch_cnt); |
|
|
|
|
batch.SetSavePoint(); |
|
|
|
|
save_points++; |
|
|
|
|
batch.Put(Slice("key"), Slice("value")); |
|
|
|
|
ASSERT_OK(batch.Put(Slice("key"), Slice("value"))); |
|
|
|
|
ASSERT_EQ(batch_cnt, batch.SubBatchCnt()); |
|
|
|
|
batch_cnt_at.push_back(batch_cnt); |
|
|
|
|
batch.SetSavePoint(); |
|
|
|
|
save_points++; |
|
|
|
|
batch.Put(Slice("key2"), Slice("value2")); |
|
|
|
|
ASSERT_OK(batch.Put(Slice("key2"), Slice("value2"))); |
|
|
|
|
ASSERT_EQ(batch_cnt, batch.SubBatchCnt()); |
|
|
|
|
// duplicate the keys
|
|
|
|
|
batch_cnt_at.push_back(batch_cnt); |
|
|
|
|
batch.SetSavePoint(); |
|
|
|
|
save_points++; |
|
|
|
|
batch.Put(Slice("key"), Slice("value3")); |
|
|
|
|
ASSERT_OK(batch.Put(Slice("key"), Slice("value3"))); |
|
|
|
|
batch_cnt++; |
|
|
|
|
ASSERT_EQ(batch_cnt, batch.SubBatchCnt()); |
|
|
|
|
// duplicate the 2nd key. It should not be counted duplicate since a
|
|
|
|
@ -234,14 +234,14 @@ TEST(WriteBatchWithIndex, SubBatchCnt) { |
|
|
|
|
batch_cnt_at.push_back(batch_cnt); |
|
|
|
|
batch.SetSavePoint(); |
|
|
|
|
save_points++; |
|
|
|
|
batch.Put(Slice("key2"), Slice("value4")); |
|
|
|
|
ASSERT_OK(batch.Put(Slice("key2"), Slice("value4"))); |
|
|
|
|
ASSERT_EQ(batch_cnt, batch.SubBatchCnt()); |
|
|
|
|
// duplicate the keys but in a different cf. It should not be counted as
|
|
|
|
|
// duplicate keys
|
|
|
|
|
batch_cnt_at.push_back(batch_cnt); |
|
|
|
|
batch.SetSavePoint(); |
|
|
|
|
save_points++; |
|
|
|
|
batch.Put(cf_handle, Slice("key"), Slice("value5")); |
|
|
|
|
ASSERT_OK(batch.Put(cf_handle, Slice("key"), Slice("value5"))); |
|
|
|
|
ASSERT_EQ(batch_cnt, batch.SubBatchCnt()); |
|
|
|
|
|
|
|
|
|
// Test that the number of sub-batches matches what we count with
|
|
|
|
@ -256,7 +256,7 @@ TEST(WriteBatchWithIndex, SubBatchCnt) { |
|
|
|
|
// Test that RollbackToSavePoint will properly resets the number of
|
|
|
|
|
// sub-batches
|
|
|
|
|
for (size_t i = save_points; i > 0; i--) { |
|
|
|
|
batch.RollbackToSavePoint(); |
|
|
|
|
ASSERT_OK(batch.RollbackToSavePoint()); |
|
|
|
|
ASSERT_EQ(batch_cnt_at[i - 1], batch.SubBatchCnt()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -277,7 +277,7 @@ TEST(WriteBatchWithIndex, SubBatchCnt) { |
|
|
|
|
Slice key = Slice(keys[ki]); |
|
|
|
|
std::string tmp = rnd.RandomString(16); |
|
|
|
|
Slice value = Slice(tmp); |
|
|
|
|
rndbatch.Put(key, value); |
|
|
|
|
ASSERT_OK(rndbatch.Put(key, value)); |
|
|
|
|
} |
|
|
|
|
SubBatchCounter batch_counter(comparators); |
|
|
|
|
ASSERT_OK(rndbatch.GetWriteBatch()->Iterate(&batch_counter)); |
|
|
|
@ -526,7 +526,7 @@ class WritePreparedTransactionTestBase : public TransactionTestBase { |
|
|
|
|
ASSERT_EQ(expected_versions[i].value, versions[i].value); |
|
|
|
|
} |
|
|
|
|
// Range delete not supported.
|
|
|
|
|
assert(expected_versions[i].type != kTypeRangeDeletion); |
|
|
|
|
ASSERT_NE(expected_versions[i].type, kTypeRangeDeletion); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
@ -702,8 +702,8 @@ INSTANTIATE_TEST_CASE_P( |
|
|
|
|
|
|
|
|
|
TEST_P(WritePreparedTransactionTest, CommitMap) { |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
assert(wp_db); |
|
|
|
|
assert(wp_db->db_impl_); |
|
|
|
|
ASSERT_NE(wp_db, nullptr); |
|
|
|
|
ASSERT_NE(wp_db->db_impl_, nullptr); |
|
|
|
|
size_t size = wp_db->COMMIT_CACHE_SIZE; |
|
|
|
|
CommitEntry c = {5, 12}, e; |
|
|
|
|
bool evicted = wp_db->AddCommitEntry(c.prep_seq % size, c, &e); |
|
|
|
@ -797,14 +797,13 @@ TEST_P(WritePreparedTransactionTest, CheckKeySkipOldMemtable) { |
|
|
|
|
for (int attempt = kAttemptHistoryMemtable; attempt <= kAttemptImmMemTable; |
|
|
|
|
attempt++) { |
|
|
|
|
options.max_write_buffer_number_to_maintain = 3; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
WriteOptions write_options; |
|
|
|
|
ReadOptions read_options; |
|
|
|
|
TransactionOptions txn_options; |
|
|
|
|
txn_options.set_snapshot = true; |
|
|
|
|
string value; |
|
|
|
|
Status s; |
|
|
|
|
|
|
|
|
|
ASSERT_OK(db->Put(write_options, Slice("foo"), Slice("bar"))); |
|
|
|
|
ASSERT_OK(db->Put(write_options, Slice("foo2"), Slice("bar"))); |
|
|
|
@ -841,9 +840,9 @@ TEST_P(WritePreparedTransactionTest, CheckKeySkipOldMemtable) { |
|
|
|
|
if (attempt == kAttemptHistoryMemtable) { |
|
|
|
|
ASSERT_OK(db->Flush(flush_ops)); |
|
|
|
|
} else { |
|
|
|
|
assert(attempt == kAttemptImmMemTable); |
|
|
|
|
ASSERT_EQ(attempt, kAttemptImmMemTable); |
|
|
|
|
DBImpl* db_impl = static_cast<DBImpl*>(db->GetRootDB()); |
|
|
|
|
db_impl->TEST_SwitchMemtable(); |
|
|
|
|
ASSERT_OK(db_impl->TEST_SwitchMemtable()); |
|
|
|
|
} |
|
|
|
|
uint64_t num_imm_mems; |
|
|
|
|
ASSERT_TRUE(db->GetIntProperty(DB::Properties::kNumImmutableMemTable, |
|
|
|
@ -851,7 +850,7 @@ TEST_P(WritePreparedTransactionTest, CheckKeySkipOldMemtable) { |
|
|
|
|
if (attempt == kAttemptHistoryMemtable) { |
|
|
|
|
ASSERT_EQ(0, num_imm_mems); |
|
|
|
|
} else { |
|
|
|
|
assert(attempt == kAttemptImmMemTable); |
|
|
|
|
ASSERT_EQ(attempt, kAttemptImmMemTable); |
|
|
|
|
ASSERT_EQ(1, num_imm_mems); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -893,7 +892,7 @@ TEST_P(WritePreparedTransactionTest, CheckKeySkipOldMemtable) { |
|
|
|
|
if (attempt == kAttemptHistoryMemtable) { |
|
|
|
|
ASSERT_EQ(3, get_perf_context()->get_from_memtable_count); |
|
|
|
|
} else { |
|
|
|
|
assert(attempt == kAttemptImmMemTable); |
|
|
|
|
ASSERT_EQ(attempt, kAttemptImmMemTable); |
|
|
|
|
ASSERT_EQ(4, get_perf_context()->get_from_memtable_count); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -910,7 +909,7 @@ TEST_P(WritePreparedTransactionTest, CheckKeySkipOldMemtable) { |
|
|
|
|
// Only active memtable will be checked in snapshot validation but
|
|
|
|
|
// both of active and immutable snapshot will be queried when
|
|
|
|
|
// getting the value.
|
|
|
|
|
assert(attempt == kAttemptImmMemTable); |
|
|
|
|
ASSERT_EQ(attempt, kAttemptImmMemTable); |
|
|
|
|
ASSERT_EQ(3, get_perf_context()->get_from_memtable_count); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1091,7 +1090,7 @@ TEST_P(WritePreparedTransactionTest, CheckAgainstSnapshots) { |
|
|
|
|
const uint64_t cache_size = 1ul << snapshot_cache_bits; |
|
|
|
|
// Safety check to express the intended size in the test. Can be adjusted if
|
|
|
|
|
// the snapshots lists changed.
|
|
|
|
|
assert((1ul << snapshot_cache_bits) * 2 + 1 == snapshots.size()); |
|
|
|
|
ASSERT_EQ((1ul << snapshot_cache_bits) * 2 + 1, snapshots.size()); |
|
|
|
|
DBImpl* mock_db = new DBImpl(options, dbname); |
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits); |
|
|
|
|
std::unique_ptr<WritePreparedTxnDBMock> wp_db( |
|
|
|
@ -1106,7 +1105,7 @@ TEST_P(WritePreparedTransactionTest, CheckAgainstSnapshots) { |
|
|
|
|
std::vector<SequenceNumber> seqs = {50l, 55l, 150l, 155l, 250l, 255l, 350l, |
|
|
|
|
355l, 450l, 455l, 550l, 555l, 650l, 655l, |
|
|
|
|
750l, 755l, 850l, 855l, 950l, 955l}; |
|
|
|
|
assert(seqs.size() > 1); |
|
|
|
|
ASSERT_GT(seqs.size(), 1); |
|
|
|
|
for (size_t i = 0; i + 1 < seqs.size(); i++) { |
|
|
|
|
wp_db->old_commit_map_empty_ = true; // reset
|
|
|
|
|
CommitEntry commit_entry = {seqs[i], seqs[i + 1]}; |
|
|
|
@ -1184,7 +1183,7 @@ TEST_P(SnapshotConcurrentAccessTest, SnapshotConcurrentAccess) { |
|
|
|
|
const size_t snapshot_cache_bits = 2; |
|
|
|
|
// Safety check to express the intended size in the test. Can be adjusted if
|
|
|
|
|
// the snapshots lists changed.
|
|
|
|
|
assert((1ul << snapshot_cache_bits) * 2 + 2 == snapshots.size()); |
|
|
|
|
ASSERT_EQ((1ul << snapshot_cache_bits) * 2 + 2, snapshots.size()); |
|
|
|
|
SequenceNumber version = 1000l; |
|
|
|
|
// Choose the cache size so that the new snapshot list could replace all the
|
|
|
|
|
// existing items in the cache and also have some overflow.
|
|
|
|
@ -1365,7 +1364,7 @@ TEST_P(WritePreparedTransactionTest, MaxCatchupWithNewSnapshot) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 0; // only 1 entry => frequent eviction
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WriteOptions woptions; |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
|
|
|
|
@ -1378,9 +1377,9 @@ TEST_P(WritePreparedTransactionTest, MaxCatchupWithNewSnapshot) { |
|
|
|
|
// is not published yet, thus causing max evicted seq go higher than last
|
|
|
|
|
// published.
|
|
|
|
|
for (int b = 0; b < batch_cnt; b++) { |
|
|
|
|
batch.Put("foo", "foo"); |
|
|
|
|
ASSERT_OK(batch.Put("foo", "foo")); |
|
|
|
|
} |
|
|
|
|
db->Write(woptions, &batch); |
|
|
|
|
ASSERT_OK(db->Write(woptions, &batch)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
@ -1415,7 +1414,7 @@ TEST_P(WritePreparedTransactionTest, MaxCatchupWithUnbackedSnapshot) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 0; // only 1 entry => frequent eviction
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WriteOptions woptions; |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
|
|
|
|
@ -1423,8 +1422,8 @@ TEST_P(WritePreparedTransactionTest, MaxCatchupWithUnbackedSnapshot) { |
|
|
|
|
ROCKSDB_NAMESPACE::port::Thread t1([&]() { |
|
|
|
|
for (int i = 0; i < writes; i++) { |
|
|
|
|
WriteBatch batch; |
|
|
|
|
batch.Put("key", "foo"); |
|
|
|
|
db->Write(woptions, &batch); |
|
|
|
|
ASSERT_OK(batch.Put("key", "foo")); |
|
|
|
|
ASSERT_OK(db->Write(woptions, &batch)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
@ -1474,7 +1473,7 @@ TEST_P(WritePreparedTransactionTest, CleanupSnapshotEqualToMax) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 0; // only 1 entry => frequent eviction
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WriteOptions woptions; |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
// Insert something to increase seq
|
|
|
|
@ -1534,8 +1533,8 @@ TEST_P(WritePreparedTransactionTest, TxnInitialize) { |
|
|
|
|
// udpated
|
|
|
|
|
ASSERT_GT(snap_impl->min_uncommitted_, kMinUnCommittedSeq); |
|
|
|
|
|
|
|
|
|
txn0->Rollback(); |
|
|
|
|
txn1->Rollback(); |
|
|
|
|
ASSERT_OK(txn0->Rollback()); |
|
|
|
|
ASSERT_OK(txn1->Rollback()); |
|
|
|
|
delete txn0; |
|
|
|
|
delete txn1; |
|
|
|
|
} |
|
|
|
@ -1548,7 +1547,7 @@ TEST_P(WritePreparedTransactionTest, AdvanceMaxEvictedSeqWithDuplicates) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 1; // disable commit cache
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
ReadOptions ropt; |
|
|
|
|
PinnableSlice pinnable_val; |
|
|
|
@ -1569,10 +1568,10 @@ TEST_P(WritePreparedTransactionTest, AdvanceMaxEvictedSeqWithDuplicates) { |
|
|
|
|
delete txn0; |
|
|
|
|
|
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
wp_db->db_impl_->FlushWAL(true); |
|
|
|
|
ASSERT_OK(wp_db->db_impl_->FlushWAL(true)); |
|
|
|
|
wp_db->TEST_Crash(); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
assert(db != nullptr); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
ASSERT_NE(db, nullptr); |
|
|
|
|
s = db->Get(ropt, db->DefaultColumnFamily(), "key", &pinnable_val); |
|
|
|
|
ASSERT_TRUE(s.IsNotFound()); |
|
|
|
|
|
|
|
|
@ -1589,7 +1588,7 @@ TEST_P(WritePreparedTransactionTest, SmallestUnCommittedSeq) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 1; // disable commit cache
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
ReadOptions ropt; |
|
|
|
|
PinnableSlice pinnable_val; |
|
|
|
@ -1622,7 +1621,7 @@ TEST_P(WritePreparedTransactionTest, SmallestUnCommittedSeq) { |
|
|
|
|
// Since commit cache is practically disabled, commit results in immediate
|
|
|
|
|
// advance in max_evicted_seq_ and subsequently moving some prepared txns
|
|
|
|
|
// to delayed_prepared_.
|
|
|
|
|
txn->Commit(); |
|
|
|
|
ASSERT_OK(txn->Commit()); |
|
|
|
|
committed_txns.push_back(txn); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
@ -1651,7 +1650,7 @@ TEST_P(SeqAdvanceConcurrentTest, SeqAdvanceConcurrent) { |
|
|
|
|
// almost infeasible.
|
|
|
|
|
txn_db_options.transaction_lock_timeout = 1000; |
|
|
|
|
txn_db_options.default_lock_timeout = 1000; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
FlushOptions fopt; |
|
|
|
|
|
|
|
|
|
// Number of different txn types we use in this test
|
|
|
|
@ -1671,7 +1670,11 @@ TEST_P(SeqAdvanceConcurrentTest, SeqAdvanceConcurrent) { |
|
|
|
|
} |
|
|
|
|
const size_t max_n = static_cast<size_t>(std::pow(type_cnt, txn_cnt)); |
|
|
|
|
printf("Number of cases being tested is %" ROCKSDB_PRIszt "\n", max_n); |
|
|
|
|
for (size_t n = 0; n < max_n; n++, ReOpen()) { |
|
|
|
|
for (size_t n = 0; n < max_n; n++) { |
|
|
|
|
if (n > 0) { |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (n % split_cnt_ != split_id_) continue; |
|
|
|
|
if (n % 1000 == 0) { |
|
|
|
|
printf("Tested %" ROCKSDB_PRIszt " cases so far\n", n); |
|
|
|
@ -1731,7 +1734,7 @@ TEST_P(SeqAdvanceConcurrentTest, SeqAdvanceConcurrent) { |
|
|
|
|
threads.emplace_back(txn_t3, bi); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
assert(false); |
|
|
|
|
FAIL(); |
|
|
|
|
} |
|
|
|
|
// wait to be linked
|
|
|
|
|
while (linked.load() <= bi) { |
|
|
|
@ -1765,22 +1768,22 @@ TEST_P(SeqAdvanceConcurrentTest, SeqAdvanceConcurrent) { |
|
|
|
|
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks(); |
|
|
|
|
|
|
|
|
|
// Check if recovery preserves the last sequence number
|
|
|
|
|
db_impl->FlushWAL(true); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
assert(db != nullptr); |
|
|
|
|
ASSERT_OK(db_impl->FlushWAL(true)); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
ASSERT_NE(db, nullptr); |
|
|
|
|
db_impl = static_cast_with_check<DBImpl>(db->GetRootDB()); |
|
|
|
|
seq = db_impl->TEST_GetLastVisibleSequence(); |
|
|
|
|
ASSERT_LE(exp_seq, seq + with_empty_commits); |
|
|
|
|
|
|
|
|
|
// Check if flush preserves the last sequence number
|
|
|
|
|
db_impl->Flush(fopt); |
|
|
|
|
ASSERT_OK(db_impl->Flush(fopt)); |
|
|
|
|
seq = db_impl->GetLatestSequenceNumber(); |
|
|
|
|
ASSERT_LE(exp_seq, seq + with_empty_commits); |
|
|
|
|
|
|
|
|
|
// Check if recovery after flush preserves the last sequence number
|
|
|
|
|
db_impl->FlushWAL(true); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
assert(db != nullptr); |
|
|
|
|
ASSERT_OK(db_impl->FlushWAL(true)); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
ASSERT_NE(db, nullptr); |
|
|
|
|
db_impl = static_cast_with_check<DBImpl>(db->GetRootDB()); |
|
|
|
|
seq = db_impl->GetLatestSequenceNumber(); |
|
|
|
|
ASSERT_LE(exp_seq, seq + with_empty_commits); |
|
|
|
@ -1792,7 +1795,7 @@ TEST_P(SeqAdvanceConcurrentTest, SeqAdvanceConcurrent) { |
|
|
|
|
// properly.
|
|
|
|
|
TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
options.disable_auto_compactions = true; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
|
|
|
|
|
txn_t0(0); |
|
|
|
@ -1807,6 +1810,7 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
s = txn0->Put(Slice("foo0" + istr0), Slice("bar0" + istr0)); |
|
|
|
|
ASSERT_OK(s); |
|
|
|
|
s = txn0->Prepare(); |
|
|
|
|
ASSERT_OK(s); |
|
|
|
|
auto prep_seq_0 = txn0->GetId(); |
|
|
|
|
|
|
|
|
|
txn_t1(0); |
|
|
|
@ -1819,6 +1823,7 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
s = txn1->Put(Slice("foo1" + istr1), Slice("bar")); |
|
|
|
|
ASSERT_OK(s); |
|
|
|
|
s = txn1->Prepare(); |
|
|
|
|
ASSERT_OK(s); |
|
|
|
|
auto prep_seq_1 = txn1->GetId(); |
|
|
|
|
|
|
|
|
|
txn_t2(0); |
|
|
|
@ -1832,10 +1837,10 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
|
|
|
|
|
delete txn0; |
|
|
|
|
delete txn1; |
|
|
|
|
wp_db->db_impl_->FlushWAL(true); |
|
|
|
|
ASSERT_OK(wp_db->db_impl_->FlushWAL(true)); |
|
|
|
|
wp_db->TEST_Crash(); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
assert(db != nullptr); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
ASSERT_NE(db, nullptr); |
|
|
|
|
wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
// After recovery, all the uncommitted txns (0 and 1) should be inserted into
|
|
|
|
|
// delayed_prepared_
|
|
|
|
@ -1863,7 +1868,7 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
// recovery
|
|
|
|
|
txn1 = db->GetTransactionByName("xid" + istr1); |
|
|
|
|
ASSERT_NE(txn1, nullptr); |
|
|
|
|
txn1->Commit(); |
|
|
|
|
ASSERT_OK(txn1->Commit()); |
|
|
|
|
delete txn1; |
|
|
|
|
|
|
|
|
|
index++; |
|
|
|
@ -1874,13 +1879,14 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
s = txn2->Put(Slice("foo2" + istr2), Slice("bar")); |
|
|
|
|
ASSERT_OK(s); |
|
|
|
|
s = txn2->Prepare(); |
|
|
|
|
ASSERT_OK(s); |
|
|
|
|
auto prep_seq_2 = txn2->GetId(); |
|
|
|
|
|
|
|
|
|
delete txn2; |
|
|
|
|
wp_db->db_impl_->FlushWAL(true); |
|
|
|
|
ASSERT_OK(wp_db->db_impl_->FlushWAL(true)); |
|
|
|
|
wp_db->TEST_Crash(); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
assert(db != nullptr); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
ASSERT_NE(db, nullptr); |
|
|
|
|
wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
ASSERT_TRUE(wp_db->prepared_txns_.empty()); |
|
|
|
|
ASSERT_FALSE(wp_db->delayed_prepared_empty_); |
|
|
|
@ -1900,10 +1906,10 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
// Commit all the remaining txns
|
|
|
|
|
txn0 = db->GetTransactionByName("xid" + istr0); |
|
|
|
|
ASSERT_NE(txn0, nullptr); |
|
|
|
|
txn0->Commit(); |
|
|
|
|
ASSERT_OK(txn0->Commit()); |
|
|
|
|
txn2 = db->GetTransactionByName("xid" + istr2); |
|
|
|
|
ASSERT_NE(txn2, nullptr); |
|
|
|
|
txn2->Commit(); |
|
|
|
|
ASSERT_OK(txn2->Commit()); |
|
|
|
|
|
|
|
|
|
// Check the value is committed after commit
|
|
|
|
|
s = db->Get(ropt, db->DefaultColumnFamily(), "foo0" + istr0, &pinnable_val); |
|
|
|
@ -1913,9 +1919,9 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
|
|
|
|
|
delete txn0; |
|
|
|
|
delete txn2; |
|
|
|
|
wp_db->db_impl_->FlushWAL(true); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
assert(db != nullptr); |
|
|
|
|
ASSERT_OK(wp_db->db_impl_->FlushWAL(true)); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
ASSERT_NE(db, nullptr); |
|
|
|
|
wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
ASSERT_TRUE(wp_db->prepared_txns_.empty()); |
|
|
|
|
ASSERT_TRUE(wp_db->delayed_prepared_empty_); |
|
|
|
@ -1932,7 +1938,7 @@ TEST_P(WritePreparedTransactionTest, BasicRecovery) { |
|
|
|
|
// committed data before the restart is visible to all snapshots.
|
|
|
|
|
TEST_P(WritePreparedTransactionTest, IsInSnapshotEmptyMap) { |
|
|
|
|
for (bool end_with_prepare : {false, true}) { |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WriteOptions woptions; |
|
|
|
|
ASSERT_OK(db->Put(woptions, "key", "value")); |
|
|
|
|
ASSERT_OK(db->Put(woptions, "key", "value")); |
|
|
|
@ -1948,10 +1954,10 @@ TEST_P(WritePreparedTransactionTest, IsInSnapshotEmptyMap) { |
|
|
|
|
} |
|
|
|
|
dynamic_cast<WritePreparedTxnDB*>(db)->TEST_Crash(); |
|
|
|
|
auto db_impl = static_cast_with_check<DBImpl>(db->GetRootDB()); |
|
|
|
|
db_impl->FlushWAL(true); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
ASSERT_OK(db_impl->FlushWAL(true)); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
assert(wp_db != nullptr); |
|
|
|
|
ASSERT_NE(wp_db, nullptr); |
|
|
|
|
ASSERT_GT(wp_db->max_evicted_seq_, 0); // max after recovery
|
|
|
|
|
// Take a snapshot right after recovery
|
|
|
|
|
const Snapshot* snap = db->GetSnapshot(); |
|
|
|
@ -2190,7 +2196,7 @@ void ASSERT_SAME(ReadOptions roptions, TransactionDB* db, Status exp_s, |
|
|
|
|
Status s; |
|
|
|
|
PinnableSlice v; |
|
|
|
|
s = db->Get(roptions, db->DefaultColumnFamily(), key, &v); |
|
|
|
|
ASSERT_TRUE(exp_s == s); |
|
|
|
|
ASSERT_EQ(exp_s, s); |
|
|
|
|
ASSERT_TRUE(s.ok() || s.IsNotFound()); |
|
|
|
|
if (s.ok()) { |
|
|
|
|
ASSERT_TRUE(exp_v == v); |
|
|
|
@ -2203,7 +2209,7 @@ void ASSERT_SAME(ReadOptions roptions, TransactionDB* db, Status exp_s, |
|
|
|
|
ASSERT_EQ(1, values.size()); |
|
|
|
|
ASSERT_EQ(1, s_vec.size()); |
|
|
|
|
s = s_vec[0]; |
|
|
|
|
ASSERT_TRUE(exp_s == s); |
|
|
|
|
ASSERT_EQ(exp_s, s); |
|
|
|
|
ASSERT_TRUE(s.ok() || s.IsNotFound()); |
|
|
|
|
if (s.ok()) { |
|
|
|
|
ASSERT_TRUE(exp_v == values[0]); |
|
|
|
@ -2224,7 +2230,7 @@ TEST_P(WritePreparedTransactionTest, Rollback) { |
|
|
|
|
for (size_t ikey = 1; ikey <= num_keys; ikey++) { |
|
|
|
|
for (size_t ivalue = 0; ivalue < num_values; ivalue++) { |
|
|
|
|
for (bool crash : {false, true}) { |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
std::string key_str = "key" + ToString(ikey); |
|
|
|
|
switch (ivalue) { |
|
|
|
@ -2243,7 +2249,7 @@ TEST_P(WritePreparedTransactionTest, Rollback) { |
|
|
|
|
ASSERT_OK(db->SingleDelete(woptions, key_str)); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
assert(0); |
|
|
|
|
FAIL(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PinnableSlice v1; |
|
|
|
@ -2286,10 +2292,10 @@ TEST_P(WritePreparedTransactionTest, Rollback) { |
|
|
|
|
if (crash) { |
|
|
|
|
delete txn; |
|
|
|
|
auto db_impl = static_cast_with_check<DBImpl>(db->GetRootDB()); |
|
|
|
|
db_impl->FlushWAL(true); |
|
|
|
|
ASSERT_OK(db_impl->FlushWAL(true)); |
|
|
|
|
dynamic_cast<WritePreparedTxnDB*>(db)->TEST_Crash(); |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
assert(db != nullptr); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
ASSERT_NE(db, nullptr); |
|
|
|
|
wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
txn = db->GetTransactionByName("xid0"); |
|
|
|
|
ASSERT_FALSE(wp_db->delayed_prepared_empty_); |
|
|
|
@ -2328,7 +2334,7 @@ TEST_P(WritePreparedTransactionTest, Rollback) { |
|
|
|
|
TEST_P(WritePreparedTransactionTest, DisableGCDuringRecovery) { |
|
|
|
|
// Use large buffer to avoid memtable flush after 1024 insertions
|
|
|
|
|
options.write_buffer_size = 1024 * 1024; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
std::vector<KeyVersion> versions; |
|
|
|
|
uint64_t seq = 0; |
|
|
|
|
for (uint64_t i = 1; i <= 1024; i++) { |
|
|
|
@ -2345,10 +2351,10 @@ TEST_P(WritePreparedTransactionTest, DisableGCDuringRecovery) { |
|
|
|
|
std::reverse(std::begin(versions), std::end(versions)); |
|
|
|
|
VerifyInternalKeys(versions); |
|
|
|
|
DBImpl* db_impl = static_cast_with_check<DBImpl>(db->GetRootDB()); |
|
|
|
|
db_impl->FlushWAL(true); |
|
|
|
|
ASSERT_OK(db_impl->FlushWAL(true)); |
|
|
|
|
// Use small buffer to ensure memtable flush during recovery
|
|
|
|
|
options.write_buffer_size = 1024; |
|
|
|
|
ReOpenNoDelete(); |
|
|
|
|
ASSERT_OK(ReOpenNoDelete()); |
|
|
|
|
VerifyInternalKeys(versions); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2375,7 +2381,7 @@ TEST_P(WritePreparedTransactionTest, SequenceNumberZero) { |
|
|
|
|
// proceed with older versions of the key as-if the new version doesn't exist.
|
|
|
|
|
TEST_P(WritePreparedTransactionTest, CompactionShouldKeepUncommittedKeys) { |
|
|
|
|
options.disable_auto_compactions = true; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
DBImpl* db_impl = static_cast_with_check<DBImpl>(db->GetRootDB()); |
|
|
|
|
// Snapshots to avoid keys get evicted.
|
|
|
|
|
std::vector<const Snapshot*> snapshots; |
|
|
|
@ -2466,7 +2472,7 @@ TEST_P(WritePreparedTransactionTest, CompactionShouldKeepUncommittedKeys) { |
|
|
|
|
// not just prepare sequence.
|
|
|
|
|
TEST_P(WritePreparedTransactionTest, CompactionShouldKeepSnapshotVisibleKeys) { |
|
|
|
|
options.disable_auto_compactions = true; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
// Keep track of expected sequence number.
|
|
|
|
|
SequenceNumber expected_seq = 0; |
|
|
|
|
auto* txn1 = db->BeginTransaction(WriteOptions()); |
|
|
|
@ -2532,7 +2538,7 @@ TEST_P(WritePreparedTransactionTest, SmallestUncommittedOptimization) { |
|
|
|
|
const size_t commit_cache_bits = 0; // disable commit cache
|
|
|
|
|
for (bool has_recent_prepare : {true, false}) { |
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), "key1", "value1")); |
|
|
|
|
auto* transaction = |
|
|
|
@ -2581,7 +2587,7 @@ TEST_P(WritePreparedTransactionTest, ReleaseSnapshotDuringCompaction) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 0; // minimum commit cache
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), "key1", "value1_1")); |
|
|
|
|
auto* transaction = |
|
|
|
@ -2630,7 +2636,7 @@ TEST_P(WritePreparedTransactionTest, ReleaseSnapshotDuringCompaction2) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 0; // minimum commit cache
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), "key1", "value1")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), "key1", "value2")); |
|
|
|
@ -2680,7 +2686,7 @@ TEST_P(WritePreparedTransactionTest, ReleaseSnapshotDuringCompaction3) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 1; // commit cache size = 2
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
// Add a dummy key to evict v2 commit cache, but keep v1 commit cache.
|
|
|
|
|
// It also advance max_evicted_seq and can trigger old_commit_map cleanup.
|
|
|
|
@ -2731,7 +2737,7 @@ TEST_P(WritePreparedTransactionTest, ReleaseEarliestSnapshotDuringCompaction) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 0; // minimum commit cache
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), "key1", "value1")); |
|
|
|
|
auto* transaction = |
|
|
|
@ -2795,7 +2801,7 @@ TEST_P(WritePreparedTransactionTest, |
|
|
|
|
|
|
|
|
|
Random rnd(1103); |
|
|
|
|
options.disable_auto_compactions = true; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < kNumTransactions; i++) { |
|
|
|
|
std::string key = "key" + ToString(i); |
|
|
|
@ -2836,7 +2842,7 @@ TEST_P(WritePreparedTransactionTest, |
|
|
|
|
snapshots.push_back(db->GetSnapshot()); |
|
|
|
|
snapshot_data.push_back(current_data); |
|
|
|
|
|
|
|
|
|
assert(snapshots.size() == snapshot_data.size()); |
|
|
|
|
ASSERT_EQ(snapshots.size(), snapshot_data.size()); |
|
|
|
|
for (size_t i = 0; i < snapshots.size(); i++) { |
|
|
|
|
VerifyKeys(snapshot_data[i], snapshots[i]); |
|
|
|
|
} |
|
|
|
@ -2871,7 +2877,7 @@ TEST_P(WritePreparedTransactionTest, |
|
|
|
|
TEST_P(WritePreparedTransactionTest, |
|
|
|
|
CompactionShouldKeepSequenceForUncommittedKeys) { |
|
|
|
|
options.disable_auto_compactions = true; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
// Keep track of expected sequence number.
|
|
|
|
|
SequenceNumber expected_seq = 0; |
|
|
|
|
auto* transaction = db->BeginTransaction(WriteOptions()); |
|
|
|
@ -2913,7 +2919,7 @@ TEST_P(WritePreparedTransactionTest, |
|
|
|
|
|
|
|
|
|
TEST_P(WritePreparedTransactionTest, CommitAndSnapshotDuringCompaction) { |
|
|
|
|
options.disable_auto_compactions = true; |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
|
|
|
|
|
const Snapshot* snapshot = nullptr; |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), "key1", "value1")); |
|
|
|
@ -2996,6 +3002,7 @@ TEST_P(WritePreparedTransactionTest, Iterate) { |
|
|
|
|
|
|
|
|
|
TEST_P(WritePreparedTransactionTest, IteratorRefreshNotSupported) { |
|
|
|
|
Iterator* iter = db->NewIterator(ReadOptions()); |
|
|
|
|
ASSERT_OK(iter->status()); |
|
|
|
|
ASSERT_TRUE(iter->Refresh().IsNotSupported()); |
|
|
|
|
delete iter; |
|
|
|
|
} |
|
|
|
@ -3017,13 +3024,13 @@ TEST_P(WritePreparedTransactionTest, NonAtomicCommitOfDelayedPrepared) { |
|
|
|
|
} |
|
|
|
|
for (auto split_before_mutex : split_options) { |
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
DBImpl* db_impl = static_cast_with_check<DBImpl>(db->GetRootDB()); |
|
|
|
|
// Fill up the commit cache
|
|
|
|
|
std::string init_value("value1"); |
|
|
|
|
for (int i = 0; i < 10; i++) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key1"), Slice(init_value)); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key1"), Slice(init_value))); |
|
|
|
|
} |
|
|
|
|
// Prepare a transaction but do not commit it
|
|
|
|
|
Transaction* txn = |
|
|
|
@ -3034,7 +3041,7 @@ TEST_P(WritePreparedTransactionTest, NonAtomicCommitOfDelayedPrepared) { |
|
|
|
|
// Commit a bunch of entries to advance max evicted seq and make the
|
|
|
|
|
// prepared a delayed prepared
|
|
|
|
|
for (int i = 0; i < 10; i++) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
} |
|
|
|
|
// The snapshot should not see the delayed prepared entry
|
|
|
|
|
auto snap = db->GetSnapshot(); |
|
|
|
@ -3075,7 +3082,7 @@ TEST_P(WritePreparedTransactionTest, NonAtomicCommitOfDelayedPrepared) { |
|
|
|
|
auto seq = db_impl->TEST_GetLastVisibleSequence(); |
|
|
|
|
size_t tries = 0; |
|
|
|
|
while (wp_db->max_evicted_seq_ < seq && tries < 50) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
tries++; |
|
|
|
|
}; |
|
|
|
|
ASSERT_LT(tries, 50); |
|
|
|
@ -3115,12 +3122,12 @@ TEST_P(WritePreparedTransactionTest, NonAtomicUpdateOfDelayedPrepared) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 3; // 8 entries
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
// Fill up the commit cache
|
|
|
|
|
std::string init_value("value1"); |
|
|
|
|
for (int i = 0; i < 10; i++) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key1"), Slice(init_value)); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key1"), Slice(init_value))); |
|
|
|
|
} |
|
|
|
|
// Prepare a transaction but do not commit it
|
|
|
|
|
Transaction* txn = db->BeginTransaction(WriteOptions(), TransactionOptions()); |
|
|
|
@ -3128,8 +3135,8 @@ TEST_P(WritePreparedTransactionTest, NonAtomicUpdateOfDelayedPrepared) { |
|
|
|
|
ASSERT_OK(txn->Put(Slice("key1"), Slice("value2"))); |
|
|
|
|
ASSERT_OK(txn->Prepare()); |
|
|
|
|
// Create a gap between prepare seq and snapshot seq
|
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
// The snapshot should not see the delayed prepared entry
|
|
|
|
|
auto snap = db->GetSnapshot(); |
|
|
|
|
ASSERT_LT(txn->GetId(), snap->GetSequenceNumber()); |
|
|
|
@ -3148,7 +3155,7 @@ TEST_P(WritePreparedTransactionTest, NonAtomicUpdateOfDelayedPrepared) { |
|
|
|
|
// prepared a delayed prepared
|
|
|
|
|
size_t tries = 0; |
|
|
|
|
while (wp_db->max_evicted_seq_ < txn->GetId() && tries < 50) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
tries++; |
|
|
|
|
}; |
|
|
|
|
ASSERT_LT(tries, 50); |
|
|
|
@ -3185,13 +3192,13 @@ TEST_P(WritePreparedTransactionTest, NonAtomicUpdateOfMaxEvictedSeq) { |
|
|
|
|
const size_t snapshot_cache_bits = 7; // same as default
|
|
|
|
|
const size_t commit_cache_bits = 3; // 8 entries
|
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
// Fill up the commit cache
|
|
|
|
|
std::string init_value("value1"); |
|
|
|
|
std::string last_value("value_final"); |
|
|
|
|
for (int i = 0; i < 10; i++) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key1"), Slice(init_value)); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key1"), Slice(init_value))); |
|
|
|
|
} |
|
|
|
|
// Do an uncommitted write to prevent min_uncommitted optimization
|
|
|
|
|
Transaction* txn1 = |
|
|
|
@ -3206,8 +3213,8 @@ TEST_P(WritePreparedTransactionTest, NonAtomicUpdateOfMaxEvictedSeq) { |
|
|
|
|
ASSERT_OK(txn->Prepare()); |
|
|
|
|
ASSERT_OK(txn->Commit()); |
|
|
|
|
// Create a gap between commit entry and snapshot seq
|
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
// The snapshot should see the last commit
|
|
|
|
|
auto snap = db->GetSnapshot(); |
|
|
|
|
ASSERT_LE(txn->GetId(), snap->GetSequenceNumber()); |
|
|
|
@ -3225,7 +3232,7 @@ TEST_P(WritePreparedTransactionTest, NonAtomicUpdateOfMaxEvictedSeq) { |
|
|
|
|
// Commit a bunch of entries to advance max evicted seq beyond txn->GetId()
|
|
|
|
|
size_t tries = 0; |
|
|
|
|
while (wp_db->max_evicted_seq_ < txn->GetId() && tries < 50) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key3"), Slice("value3")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3"))); |
|
|
|
|
tries++; |
|
|
|
|
}; |
|
|
|
|
ASSERT_LT(tries, 50); |
|
|
|
@ -3248,7 +3255,7 @@ TEST_P(WritePreparedTransactionTest, NonAtomicUpdateOfMaxEvictedSeq) { |
|
|
|
|
read_thread.join(); |
|
|
|
|
commit_thread.join(); |
|
|
|
|
delete txn; |
|
|
|
|
txn1->Commit(); |
|
|
|
|
ASSERT_OK(txn1->Commit()); |
|
|
|
|
delete txn1; |
|
|
|
|
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing(); |
|
|
|
|
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks(); |
|
|
|
@ -3266,7 +3273,7 @@ TEST_P(WritePreparedTransactionTest, AddPreparedBeforeMax) { |
|
|
|
|
// 1 entry to advance max after the 2nd commit
|
|
|
|
|
const size_t commit_cache_bits = 0; |
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
WritePreparedTxnDB* wp_db = dynamic_cast<WritePreparedTxnDB*>(db); |
|
|
|
|
std::string some_value("value_some"); |
|
|
|
|
std::string uncommitted_value("value_uncommitted"); |
|
|
|
@ -3347,7 +3354,7 @@ TEST_P(WritePreparedTransactionTest, CommitOfDelayedPrepared) { |
|
|
|
|
for (const size_t commit_cache_bits : {0, 2, 3}) { |
|
|
|
|
for (const size_t sub_batch_cnt : {1, 2, 3}) { |
|
|
|
|
UpdateTransactionDBOptions(snapshot_cache_bits, commit_cache_bits); |
|
|
|
|
ReOpen(); |
|
|
|
|
ASSERT_OK(ReOpen()); |
|
|
|
|
std::atomic<const Snapshot*> snap = {nullptr}; |
|
|
|
|
std::atomic<SequenceNumber> exp_prepare = {0}; |
|
|
|
|
ROCKSDB_NAMESPACE::port::Thread callback_thread; |
|
|
|
@ -3385,7 +3392,7 @@ TEST_P(WritePreparedTransactionTest, CommitOfDelayedPrepared) { |
|
|
|
|
// Too many txns might cause commit_seq - prepare_seq in another thread
|
|
|
|
|
// to go beyond DELTA_UPPERBOUND
|
|
|
|
|
for (int i = 0; i < 25 * (1 << commit_cache_bits); i++) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key1"), Slice("value1")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key1"), Slice("value1"))); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
ROCKSDB_NAMESPACE::port::Thread write_thread([&]() { |
|
|
|
@ -3448,7 +3455,7 @@ TEST_P(WritePreparedTransactionTest, AtomicCommit) { |
|
|
|
|
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing(); |
|
|
|
|
ROCKSDB_NAMESPACE::port::Thread write_thread([&]() { |
|
|
|
|
if (skip_prepare) { |
|
|
|
|
db->Put(WriteOptions(), Slice("key"), Slice("value")); |
|
|
|
|
ASSERT_OK(db->Put(WriteOptions(), Slice("key"), Slice("value"))); |
|
|
|
|
} else { |
|
|
|
|
Transaction* txn = |
|
|
|
|
db->BeginTransaction(WriteOptions(), TransactionOptions()); |
|
|
|
|