Skip to content

Commit e3b7dd7

Browse files
cbi42facebook-github-bot
authored andcommitted
Add a new transaction option for large transaction optimization (facebook#13582)
Summary: I added `TransactionDBOptions::txn_commit_bypass_memtable_threshold` previously but per DB option is not dynamically changeable. Adding it as a per transaction option to make it easier to use. The option naming is updated to make it easier for customer to understand `large_txn_commit_optimize_threshold`. The transaction DB option `TransactionDBOptions::txn_commit_bypass_memtable_threshold` is marked as deprecated. Pull Request resolved: facebook#13582 Test Plan: - new unit test - updated stress test to use this new transaction option Reviewed By: jowlyzhang Differential Revision: D73960981 Pulled By: cbi42 fbshipit-source-id: 406f6e0f5f4eb6b336976f9a93b0bc08e61a9662
1 parent 9d1a071 commit e3b7dd7

File tree

5 files changed

+151
-14
lines changed

5 files changed

+151
-14
lines changed

db_stress_tool/db_stress_test_base.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -838,11 +838,15 @@ Status StressTest::NewTxn(WriteOptions& write_opts, ThreadState* thread,
838838
FLAGS_use_only_the_last_commit_time_batch_for_recovery;
839839
txn_options.lock_timeout = 600000; // 10 min
840840
txn_options.deadlock_detect = true;
841-
if (FLAGS_commit_bypass_memtable_one_in > 0) {
841+
if (FLAGS_commit_bypass_memtable_one_in > 0 &&
842+
thread->rand.OneIn(FLAGS_commit_bypass_memtable_one_in)) {
842843
assert(FLAGS_txn_write_policy == 0);
843844
assert(FLAGS_user_timestamp_size == 0);
844-
txn_options.commit_bypass_memtable =
845-
thread->rand.OneIn(FLAGS_commit_bypass_memtable_one_in);
845+
if (thread->rand.OneIn(2)) {
846+
txn_options.commit_bypass_memtable = true;
847+
} else {
848+
txn_options.large_txn_commit_optimize_threshold = 1;
849+
}
846850
if (commit_bypass_memtable) {
847851
*commit_bypass_memtable = txn_options.commit_bypass_memtable;
848852
}

include/rocksdb/utilities/transaction_db.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,12 @@ struct TransactionDBOptions {
254254
// for more details.
255255
std::vector<std::shared_ptr<SecondaryIndex>> secondary_indices;
256256

257-
// EXPERIMENTAL, SUBJECT TO CHANGE
257+
// Deprecated, this option may be removed in the future.
258+
// Use TransactionOptions::large_txn_commit_optimize_threshold instead.
259+
//
258260
// This option is only valid for write committed. If the number of updates in
259-
// a transaction exceeds this threshold, then the transaction commit will skip
260-
// insertions into memtable as an optimization to reduce commit latency.
261+
// a transaction is at least this threshold, then the transaction commit will
262+
// skip insertions into memtable as an optimization to reduce commit latency.
261263
// See comment for TransactionOptions::commit_bypass_memtable for more detail.
262264
// Setting TransactionOptions::commit_bypass_memtable to true takes precedence
263265
// over this option.
@@ -387,6 +389,13 @@ struct TransactionOptions {
387389
// can cause flush/compaction to report `num_single_del_mismatch` due to
388390
// consecutive SingleDeletes.
389391
bool commit_bypass_memtable = false;
392+
393+
// EXPERIMENTAL, SUBJECT TO CHANGE
394+
// When the number of updates in a transaction is at least this threshold,
395+
// we will enable optimizations for commiting a large transaction. See
396+
// comment for `commit_bypass_memtable` for more optimization detail.
397+
uint32_t large_txn_commit_optimize_threshold =
398+
std::numeric_limits<uint32_t>::max();
390399
};
391400

392401
// The per-write optimizations that do not involve transactions. TransactionDB
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Add new experimental `TransactionOptions::large_txn_commit_optimize_threshold` to enable optimizations for large transaction commit with per transaction threshold. `TransactionDBOptions::txn_commit_bypass_memtable_threshold` is deprecated in favor of this transaction option.

utilities/transactions/pessimistic_transaction.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,12 @@ void PessimisticTransaction::Initialize(const TransactionOptions& txn_options) {
105105
commit_timestamp_ = kMaxTxnTimestamp;
106106

107107
if (txn_options.commit_bypass_memtable) {
108-
commit_bypass_memtable_threshold_ = 0;
108+
// No need to optimize for empty transction
109+
commit_bypass_memtable_threshold_ = 1;
110+
} else if (txn_options.large_txn_commit_optimize_threshold !=
111+
std::numeric_limits<uint32_t>::max()) {
112+
commit_bypass_memtable_threshold_ =
113+
txn_options.large_txn_commit_optimize_threshold;
109114
} else {
110115
commit_bypass_memtable_threshold_ =
111116
db_options.txn_commit_bypass_memtable_threshold;
@@ -887,7 +892,7 @@ Status WriteCommittedTxn::CommitInternal() {
887892
// any operations appended to this working_batch will be ignored from WAL
888893
working_batch->MarkWalTerminationPoint();
889894

890-
bool bypass_memtable = wb->Count() > commit_bypass_memtable_threshold_;
895+
bool bypass_memtable = wb->Count() >= commit_bypass_memtable_threshold_;
891896
if (!bypass_memtable) {
892897
// insert prepared batch into Memtable only skipping WAL.
893898
// Memtable will ignore BeginPrepare/EndPrepare markers

utilities/transactions/transaction_test.cc

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9414,8 +9414,8 @@ TEST_P(CommitBypassMemtableTest, ThresholdTxnDBOption) {
94149414
ASSERT_OK(txn1->Commit());
94159415
ASSERT_TRUE(commit_bypass_memtable);
94169416

9417-
// Below threshold
9418-
for (auto num_ops : {threshold, threshold + 1}) {
9417+
// Test threshold behavior
9418+
for (auto num_ops : {threshold - 1, threshold}) {
94199419
commit_bypass_memtable = false;
94209420
txn_opts.commit_bypass_memtable = false;
94219421
auto txn = txn_db->BeginTransaction(wopts, txn_opts, txn1);
@@ -9427,16 +9427,16 @@ TEST_P(CommitBypassMemtableTest, ThresholdTxnDBOption) {
94279427
}
94289428
ASSERT_OK(txn->Prepare());
94299429
ASSERT_OK(txn->Commit());
9430-
ASSERT_EQ(commit_bypass_memtable, num_ops > threshold);
9430+
ASSERT_EQ(commit_bypass_memtable, num_ops >= threshold);
94319431
delete txn;
94329432
}
94339433

94349434
// Repeat the same test with updates to two CFs
94359435
std::vector<std::string> cfs = {"pk", "sk"};
94369436
CreateColumnFamilies(cfs, options);
94379437

9438-
// Below threshold
9439-
for (auto num_ops : {threshold, threshold + 1}) {
9438+
// Test threshold behavior with CFs
9439+
for (auto num_ops : {threshold - 1, threshold}) {
94409440
commit_bypass_memtable = false;
94419441
txn_opts.commit_bypass_memtable = false;
94429442
auto txn_cf = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
@@ -9447,11 +9447,129 @@ TEST_P(CommitBypassMemtableTest, ThresholdTxnDBOption) {
94479447
}
94489448
ASSERT_OK(txn_cf->Prepare());
94499449
ASSERT_OK(txn_cf->Commit());
9450-
ASSERT_EQ(commit_bypass_memtable, num_ops > threshold);
9450+
ASSERT_EQ(commit_bypass_memtable, num_ops >= threshold);
94519451
delete txn_cf;
94529452
}
94539453
}
94549454

9455+
TEST_P(CommitBypassMemtableTest, OptimizeLargeTxnCommitThreshold) {
9456+
// Tests TransactionOptions::large_txn_commit_optimize_threshold
9457+
const uint32_t threshold = 10;
9458+
SetUpTransactionDB();
9459+
bool commit_bypass_memtable = false;
9460+
SyncPoint::GetInstance()->SetCallBack(
9461+
"WriteCommittedTxn::CommitInternal:bypass_memtable",
9462+
[&](void* arg) { commit_bypass_memtable = *(static_cast<bool*>(arg)); });
9463+
SyncPoint::GetInstance()->EnableProcessing();
9464+
9465+
// Test with transaction option only
9466+
WriteOptions wopts;
9467+
TransactionOptions txn_opts;
9468+
txn_opts.large_txn_commit_optimize_threshold = threshold;
9469+
9470+
// Test with transaction below threshold
9471+
auto txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
9472+
ASSERT_OK(txn1->SetName("xid1"));
9473+
ASSERT_OK(txn1->Put("k1", "v1"));
9474+
ASSERT_OK(txn1->Prepare());
9475+
ASSERT_OK(txn1->Commit());
9476+
ASSERT_FALSE(commit_bypass_memtable);
9477+
delete txn1;
9478+
9479+
// Test with transaction at threshold
9480+
txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
9481+
ASSERT_OK(txn1->SetName("xid2"));
9482+
for (uint32_t i = 0; i < threshold; ++i) {
9483+
ASSERT_OK(
9484+
txn1->Put("key" + std::to_string(i), "value" + std::to_string(i)));
9485+
}
9486+
ASSERT_OK(txn1->Prepare());
9487+
ASSERT_OK(txn1->Commit());
9488+
ASSERT_TRUE(commit_bypass_memtable);
9489+
delete txn1;
9490+
9491+
// Test with both DB option and transaction option - transaction option should
9492+
// take precedence
9493+
SetUpTransactionDB(/*threshold=*/threshold * 2);
9494+
9495+
// Transaction option is lower than DB option, should use transaction option
9496+
txn_opts.large_txn_commit_optimize_threshold = threshold;
9497+
txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
9498+
ASSERT_OK(txn1->SetName("xid3"));
9499+
for (uint32_t i = 0; i < threshold; ++i) {
9500+
ASSERT_OK(
9501+
txn1->Put("key" + std::to_string(i), "value" + std::to_string(i)));
9502+
}
9503+
ASSERT_OK(txn1->Prepare());
9504+
commit_bypass_memtable = false;
9505+
ASSERT_OK(txn1->Commit());
9506+
ASSERT_TRUE(commit_bypass_memtable);
9507+
delete txn1;
9508+
9509+
// Transaction option is higher than DB option, should use transaction option
9510+
txn_opts.large_txn_commit_optimize_threshold = threshold * 3;
9511+
txn1 = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
9512+
ASSERT_OK(txn1->SetName("xid4"));
9513+
for (uint32_t i = 0; i < threshold * 3 - 1; ++i) {
9514+
ASSERT_OK(
9515+
txn1->Put("key" + std::to_string(i), "value" + std::to_string(i)));
9516+
}
9517+
ASSERT_OK(txn1->Prepare());
9518+
commit_bypass_memtable = false;
9519+
ASSERT_OK(txn1->Commit());
9520+
ASSERT_FALSE(commit_bypass_memtable);
9521+
delete txn1;
9522+
9523+
SetUpTransactionDB();
9524+
// Test with multiple column families
9525+
std::vector<std::string> cfs = {"pk", "sk"};
9526+
CreateColumnFamilies(cfs, options);
9527+
9528+
txn_opts.large_txn_commit_optimize_threshold = threshold;
9529+
9530+
// Below threshold
9531+
auto txn_cf = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
9532+
ASSERT_OK(txn_cf->SetName("xid_cf_below"));
9533+
for (uint32_t i = 0; i < threshold - 1; ++i) {
9534+
ASSERT_OK(txn_cf->Put(handles_[i % 2], "key" + std::to_string(i),
9535+
"value" + std::to_string(i)));
9536+
}
9537+
ASSERT_OK(txn_cf->Prepare());
9538+
commit_bypass_memtable = false;
9539+
ASSERT_OK(txn_cf->Commit());
9540+
ASSERT_FALSE(commit_bypass_memtable);
9541+
delete txn_cf;
9542+
9543+
// At threshold
9544+
txn_cf = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
9545+
ASSERT_OK(txn_cf->SetName("xid_cf_at_threshold"));
9546+
for (uint32_t i = 0; i < threshold; ++i) {
9547+
ASSERT_OK(txn_cf->Put(handles_[i % 2], "key" + std::to_string(i),
9548+
"value" + std::to_string(i)));
9549+
}
9550+
ASSERT_OK(txn_cf->Prepare());
9551+
commit_bypass_memtable = false;
9552+
ASSERT_OK(txn_cf->Commit());
9553+
ASSERT_TRUE(commit_bypass_memtable);
9554+
delete txn_cf;
9555+
9556+
// Test that commit_bypass_memtable takes precedence over
9557+
// large_txn_commit_optimize_threshold
9558+
txn_opts.large_txn_commit_optimize_threshold =
9559+
threshold * 10; // High threshold
9560+
txn_opts.commit_bypass_memtable = true; // Should override threshold
9561+
9562+
txn_cf = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
9563+
ASSERT_OK(txn_cf->SetName("xid_cf_precedence"));
9564+
ASSERT_OK(txn_cf->Put(handles_[0], "key1", "value1")); // Just one operation
9565+
ASSERT_OK(txn_cf->Prepare());
9566+
commit_bypass_memtable = false;
9567+
ASSERT_OK(txn_cf->Commit());
9568+
ASSERT_TRUE(commit_bypass_memtable); // Should be true because of
9569+
// commit_bypass_memtable
9570+
delete txn_cf;
9571+
}
9572+
94559573
TEST_P(CommitBypassMemtableTest, AtomicFlushTest) {
94569574
const uint32_t threshold = 10;
94579575
SetUpTransactionDB(/*threshold=*/threshold, /*atomic_flush=*/true);

0 commit comments

Comments
 (0)