diff --git a/db_stress_tool/db_stress_test_base.cc b/db_stress_tool/db_stress_test_base.cc index be65b198b56f9c222ce19933d99d51e295add59f..c0ecb926aa5cf8657671aac70c294f78c5e4794b 100644 --- a/db_stress_tool/db_stress_test_base.cc +++ b/db_stress_tool/db_stress_test_base.cc @@ -470,6 +470,17 @@ Status StressTest::CommitTxn(Transaction* txn) { delete txn; return s; } + +Status StressTest::RollbackTxn(Transaction* txn) { + if (!FLAGS_use_txn) { + return Status::InvalidArgument( + "RollbackTxn when FLAGS_use_txn is not" + " set"); + } + Status s = txn->Rollback(); + delete txn; + return s; +} #endif void StressTest::OperateDb(ThreadState* thread) { diff --git a/db_stress_tool/db_stress_test_base.h b/db_stress_tool/db_stress_test_base.h index f16af3b0bf7b8d09ac2d8225aebd344a46d30c67..0f0dbbc82155ee024e8992e6a8a610f3428c9e28 100644 --- a/db_stress_tool/db_stress_test_base.h +++ b/db_stress_tool/db_stress_test_base.h @@ -52,6 +52,8 @@ class StressTest { Status NewTxn(WriteOptions& write_opts, Transaction** txn); Status CommitTxn(Transaction* txn); + + Status RollbackTxn(Transaction* txn); #endif virtual void MaybeClearOneColumnFamily(ThreadState* /* thread */) {} diff --git a/db_stress_tool/no_batched_ops_stress.cc b/db_stress_tool/no_batched_ops_stress.cc index da7796e36bb73bfa79d31b51008e48bd69841767..938c75ced2508c8839e1d0f07b8c84d9cff1c01f 100644 --- a/db_stress_tool/no_batched_ops_stress.cc +++ b/db_stress_tool/no_batched_ops_stress.cc @@ -166,12 +166,68 @@ class NonBatchedOpsStressTest : public StressTest { std::vector statuses(num_keys); ColumnFamilyHandle* cfh = column_families_[rand_column_families[0]]; + // Create a transaction in order to write some data. The purpose is to + // exercise WriteBatchWithIndex::MultiGetFromBatchAndDB. The transaction + // will be rolled back once MultiGet returns. +#ifndef ROCKSDB_LITE + Transaction* txn = nullptr; + if (FLAGS_use_txn) { + WriteOptions wo; + NewTxn(wo, &txn); + } +#endif for (size_t i = 0; i < num_keys; ++i) { key_str.emplace_back(Key(rand_keys[i])); keys.emplace_back(key_str.back()); +#ifndef ROCKSDB_LITE + if (FLAGS_use_txn) { + // With a 1 in 10 probability, insert the just added key in the batch + // into the transaction. This will create an overlap with the MultiGet + // keys and exercise some corner cases in the code + if (thread->rand.OneIn(10)) { + int op = thread->rand.Uniform(2); + Status s; + switch (op) { + case 0: + case 1: { + uint32_t value_base = + thread->rand.Next() % thread->shared->UNKNOWN_SENTINEL; + char value[100]; + size_t sz = GenerateValue(value_base, value, sizeof(value)); + Slice v(value, sz); + if (op == 0) { + s = txn->Put(cfh, keys.back(), v); + } else { + s = txn->Merge(cfh, keys.back(), v); + } + break; + } + case 2: + s = txn->Delete(cfh, keys.back()); + break; + default: + assert(false); + } + if (!s.ok()) { + fprintf(stderr, "Transaction put: %s\n", s.ToString().c_str()); + std::terminate(); + } + } + } +#endif + } + + if (!FLAGS_use_txn) { + db_->MultiGet(read_opts, cfh, num_keys, keys.data(), values.data(), + statuses.data()); + } else { +#ifndef ROCKSDB_LITE + txn->MultiGet(read_opts, cfh, num_keys, keys.data(), values.data(), + statuses.data()); + RollbackTxn(txn); +#endif } - db_->MultiGet(read_opts, cfh, num_keys, keys.data(), values.data(), - statuses.data()); + for (const auto& s : statuses) { if (s.ok()) { // found case