mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 14:47:40 +08:00
Enable large txn optimization by transaction write batch size (#13634)
Summary: Larger key/values can cause memtable write to take longer time. Add new option `TransactionOptions::large_txn_commit_optimize_byte_threshold` that enables the optimization by transaction write batch size. Pull Request resolved: https://github.com/facebook/rocksdb/pull/13634 Test Plan: - new unit test - added option to stress test and ran stress test for some time: `python3 ./tools/db_crashtest.py --txn blackbox --txn_write_policy=0 --commit_bypass_memtable_one_in=50 --test_batches_snapshots=0` Reviewed By: jowlyzhang Differential Revision: D75248126 Pulled By: cbi42 fbshipit-source-id: 9522db93457729ba60e4176f7d47f7c2c7778567
This commit is contained in:
committed by
Facebook GitHub Bot
parent
1d94aeea44
commit
a00391c729
@@ -849,9 +849,15 @@ Status StressTest::NewTxn(WriteOptions& write_opts, ThreadState* thread,
|
||||
assert(FLAGS_user_timestamp_size == 0);
|
||||
if (thread->rand.OneIn(2)) {
|
||||
txn_options.commit_bypass_memtable = true;
|
||||
} else {
|
||||
}
|
||||
if (thread->rand.OneIn(2)) {
|
||||
txn_options.large_txn_commit_optimize_threshold = 1;
|
||||
}
|
||||
if (thread->rand.OneIn(2) ||
|
||||
(!txn_options.commit_bypass_memtable &&
|
||||
txn_options.large_txn_commit_optimize_threshold != 1)) {
|
||||
txn_options.large_txn_commit_optimize_byte_threshold = 1;
|
||||
}
|
||||
if (commit_bypass_memtable) {
|
||||
*commit_bypass_memtable = txn_options.commit_bypass_memtable;
|
||||
}
|
||||
|
||||
@@ -366,6 +366,22 @@ struct TransactionOptions {
|
||||
// DeleteRange, SingleDelete.
|
||||
bool write_batch_track_timestamp_size = false;
|
||||
|
||||
// The following three options enable optimizations for large transaction
|
||||
// commit to bypass memtable write.
|
||||
// - If any transaction's commit should bybass memtable write,
|
||||
// set commit_bypass_memtable to true.
|
||||
// - If only bypass memtable write for transactions with >= n operations,
|
||||
// set commit_bypass_memtable to false,
|
||||
// large_txn_commit_optimize_threshold to n, and
|
||||
// large_txn_commit_optimize_byte_threshold to max.
|
||||
// Similarly for only optimize when a transaction's write batch size is >= n.
|
||||
// - If bypass memtable write for transactions with >= n operations or >= x
|
||||
// bytes,
|
||||
// set commit_bypass_memtable to false,
|
||||
// large_txn_commit_optimize_threshold to n, and
|
||||
// large_txn_commit_optimize_byte_threshold to x.
|
||||
//
|
||||
//
|
||||
// EXPERIMENTAL, SUBJECT TO CHANGE
|
||||
// Only supports write-committed policy. If set to true, the transaction will
|
||||
// skip memtable write and ingest into the DB directly during Commit(). This
|
||||
@@ -396,6 +412,13 @@ struct TransactionOptions {
|
||||
// comment for `commit_bypass_memtable` for more optimization detail.
|
||||
uint32_t large_txn_commit_optimize_threshold =
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
|
||||
// EXPERIMENTAL, SUBJECT TO CHANGE
|
||||
// When the size of a transaction's write batch is at least this threshold,
|
||||
// we will enable optimizations for commiting a large transaction. See
|
||||
// comment for `commit_bypass_memtable` for more optimization detail.
|
||||
uint64_t large_txn_commit_optimize_byte_threshold =
|
||||
std::numeric_limits<uint64_t>::max();
|
||||
};
|
||||
|
||||
// The per-write optimizations that do not involve transactions. TransactionDB
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
* Add new experimental `TransactionOptions::large_txn_commit_optimize_byte_threshold` to enable optimizations for large transaction commit by transaction batch data size.
|
||||
@@ -115,6 +115,9 @@ void PessimisticTransaction::Initialize(const TransactionOptions& txn_options) {
|
||||
commit_bypass_memtable_threshold_ =
|
||||
db_options.txn_commit_bypass_memtable_threshold;
|
||||
}
|
||||
|
||||
commit_bypass_memtable_byte_threshold_ =
|
||||
txn_options.large_txn_commit_optimize_byte_threshold;
|
||||
}
|
||||
|
||||
PessimisticTransaction::~PessimisticTransaction() {
|
||||
@@ -857,6 +860,8 @@ Status WriteCommittedTxn::CommitInternal() {
|
||||
} else {
|
||||
assert(commit_bypass_memtable_threshold_ ==
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
assert(commit_bypass_memtable_byte_threshold_ ==
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
assert(commit_timestamp_ != kMaxTxnTimestamp);
|
||||
char commit_ts_buf[sizeof(kMaxTxnTimestamp)];
|
||||
EncodeFixed64(commit_ts_buf, commit_timestamp_);
|
||||
@@ -895,7 +900,10 @@ Status WriteCommittedTxn::CommitInternal() {
|
||||
uint32_t wb_count = wb->Count();
|
||||
RecordInHistogram(db_impl_->immutable_db_options_.stats,
|
||||
NUM_OP_PER_TRANSACTION, wb_count);
|
||||
bool bypass_memtable = wb_count >= commit_bypass_memtable_threshold_;
|
||||
bool bypass_memtable =
|
||||
!needs_ts &&
|
||||
(wb_count >= commit_bypass_memtable_threshold_ ||
|
||||
wb->GetDataSize() >= commit_bypass_memtable_byte_threshold_);
|
||||
if (!bypass_memtable) {
|
||||
// insert prepared batch into Memtable only skipping WAL.
|
||||
// Memtable will ignore BeginPrepare/EndPrepare markers
|
||||
|
||||
@@ -166,10 +166,11 @@ class PessimisticTransaction : public TransactionBaseImpl {
|
||||
// Refer to
|
||||
// TransactionOptions::skip_prepare
|
||||
bool skip_prepare_ = false;
|
||||
// Refer to
|
||||
// TransactionOptions::commit_bypass_memtable
|
||||
// Refer to TransactionOptions::commit_bypass_memtable
|
||||
uint32_t commit_bypass_memtable_threshold_ =
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
uint64_t commit_bypass_memtable_byte_threshold_ =
|
||||
std::numeric_limits<uint64_t>::max();
|
||||
|
||||
private:
|
||||
friend class TransactionTest_ValidateSnapshotTest_Test;
|
||||
|
||||
@@ -9889,6 +9889,118 @@ TEST_F(TransactionDBTest, SelfDeadlockBug) {
|
||||
delete txn1;
|
||||
delete txn2;
|
||||
}
|
||||
|
||||
TEST_P(CommitBypassMemtableTest,
|
||||
OptimizeLargeTxnCommitWriteBatchSizeThreshold) {
|
||||
// Tests TransactionOptions::large_txn_commit_optimize_byte_threshold
|
||||
const uint64_t threshold = 100;
|
||||
SetUpTransactionDB();
|
||||
bool commit_bypass_memtable = false;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteCommittedTxn::CommitInternal:bypass_memtable",
|
||||
[&](void* arg) { commit_bypass_memtable = *(static_cast<bool*>(arg)); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Random rnd(301);
|
||||
// Test with transaction option only
|
||||
WriteOptions wopts;
|
||||
TransactionOptions txn_opts;
|
||||
txn_opts.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
|
||||
// Above threshold
|
||||
auto txn = txn_db->BeginTransaction(wopts, txn_opts, nullptr);
|
||||
ASSERT_OK(txn->SetName("xid1"));
|
||||
ASSERT_OK(txn->Put("k1", rnd.RandomString(threshold)));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() >= threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
// Below threshold
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts, txn);
|
||||
ASSERT_OK(txn->SetName("xid2"));
|
||||
ASSERT_OK(txn->Put("k2", "v2"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
delete txn;
|
||||
|
||||
// With commit_bypass_memtbale
|
||||
TransactionOptions txn_opts2;
|
||||
txn_opts2.commit_bypass_memtable = true;
|
||||
txn_opts2.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts2, nullptr);
|
||||
ASSERT_OK(txn->SetName("xid3"));
|
||||
ASSERT_OK(txn->Put("k3", "v3"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
delete txn;
|
||||
|
||||
// With count based threshold `large_txn_commit_optimize_threshold`
|
||||
TransactionOptions txn_opts3;
|
||||
txn_opts3.commit_bypass_memtable = false;
|
||||
txn_opts3.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
txn_opts3.large_txn_commit_optimize_threshold = 3;
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts3, nullptr);
|
||||
ASSERT_OK(txn->SetName("xid4"));
|
||||
ASSERT_OK(txn->Put("k3", "v3"));
|
||||
ASSERT_OK(txn->Delete("k2"));
|
||||
ASSERT_OK(txn->Delete("k1"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts3, txn);
|
||||
ASSERT_OK(txn->SetName("xid4"));
|
||||
ASSERT_OK(txn->Put("k3", "v3"));
|
||||
ASSERT_OK(txn->Delete("k2"));
|
||||
ASSERT_OK(txn->Delete("k1"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
txn = txn_db->BeginTransaction(wopts, txn_opts3, txn);
|
||||
ASSERT_OK(txn->SetName("xid5"));
|
||||
ASSERT_OK(txn->Put("k5", "v5"));
|
||||
ASSERT_TRUE(txn->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
delete txn;
|
||||
|
||||
// Test with multiple column families
|
||||
std::vector<std::string> cfs = {"pk", "sk"};
|
||||
CreateColumnFamilies(cfs, options);
|
||||
TransactionOptions txn_opts_cf;
|
||||
|
||||
txn_opts_cf.large_txn_commit_optimize_byte_threshold = threshold;
|
||||
|
||||
// Below threshold
|
||||
auto txn_cf = txn_db->BeginTransaction(wopts, txn_opts_cf, nullptr);
|
||||
ASSERT_OK(txn_cf->SetName("xid_cf_above"));
|
||||
ASSERT_OK(txn_cf->Put(handles_[0], "k1", rnd.RandomString(threshold / 2)));
|
||||
ASSERT_OK(txn_cf->Put(handles_[1], "k2", rnd.RandomString(threshold / 2)));
|
||||
ASSERT_TRUE(txn_cf->GetWriteBatch()->GetDataSize() >= threshold);
|
||||
ASSERT_OK(txn_cf->Prepare());
|
||||
ASSERT_OK(txn_cf->Commit());
|
||||
ASSERT_TRUE(commit_bypass_memtable);
|
||||
|
||||
txn_cf = txn_db->BeginTransaction(wopts, txn_opts_cf, txn_cf);
|
||||
ASSERT_OK(txn_cf->SetName("xid_cf_below"));
|
||||
ASSERT_OK(txn_cf->Put(handles_[0], "k1", rnd.RandomString(10)));
|
||||
ASSERT_OK(txn_cf->Put(handles_[1], "k2", rnd.RandomString(10)));
|
||||
ASSERT_TRUE(txn_cf->GetWriteBatch()->GetDataSize() < threshold);
|
||||
ASSERT_OK(txn_cf->Prepare());
|
||||
ASSERT_OK(txn_cf->Commit());
|
||||
ASSERT_FALSE(commit_bypass_memtable);
|
||||
|
||||
delete txn_cf;
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
Reference in New Issue
Block a user