Skip to content

Commit ef0c3ed

Browse files
Cheng Changfacebook-github-bot
Cheng Chang
authored andcommitted
Make users explicitly be aware of prepare before commit (facebook#6775)
Summary: In current commit protocol of pessimistic transaction, if the transaction is not prepared before commit, the commit protocol implicitly assumes that the user wants to commit without prepare. This PR adds TransactionOptions::skip_prepare, the default value is `true` because if set to `false`, all existing users who commit without prepare need to update their code to set skip_prepare to true. Although this does not force the user to explicitly express their intention of skip_prepare, it at least lets the user be aware of the assumption of being able to commit without prepare. Pull Request resolved: facebook#6775 Test Plan: added a new unit test TransactionTest::CommitWithoutPrepare Reviewed By: lth Differential Revision: D21313270 Pulled By: cheng-chang fbshipit-source-id: 3d95b7c9b2d6cdddc09bdd66c561bc4fae8c3251
1 parent 079e50d commit ef0c3ed

File tree

6 files changed

+51
-5
lines changed

6 files changed

+51
-5
lines changed

include/rocksdb/status.h

+13
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class Status {
7979
KMergeOperandsInsufficientCapacity = 10,
8080
kManualCompactionPaused = 11,
8181
kOverwritten = 12,
82+
kTxnNotPrepared = 13,
8283
kMaxSubCode
8384
};
8485

@@ -224,6 +225,13 @@ class Status {
224225
return Status(kIOError, kPathNotFound, msg, msg2);
225226
}
226227

228+
static Status TxnNotPrepared() {
229+
return Status(kInvalidArgument, kTxnNotPrepared);
230+
}
231+
static Status TxnNotPrepared(const Slice& msg, const Slice& msg2 = Slice()) {
232+
return Status(kInvalidArgument, kTxnNotPrepared, msg, msg2);
233+
}
234+
227235
// Returns true iff the status indicates success.
228236
bool ok() const { return code() == kOk; }
229237

@@ -315,6 +323,11 @@ class Status {
315323
return (code() == kIncomplete) && (subcode() == kManualCompactionPaused);
316324
}
317325

326+
// Returns true iff the status indicates a TxnNotPrepared error.
327+
bool IsTxnNotPrepared() const {
328+
return (code() == kInvalidArgument) && (subcode() == kTxnNotPrepared);
329+
}
330+
318331
// Return a string representation of this status suitable for printing.
319332
// Returns the string "OK" for success.
320333
std::string ToString() const;

include/rocksdb/utilities/transaction.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ class Transaction {
139139
//
140140
// If this transaction was created by a TransactionDB(), Status::Expired()
141141
// may be returned if this transaction has lived for longer than
142-
// TransactionOptions.expiration.
142+
// TransactionOptions.expiration. Status::TxnNotPrepared() may be returned if
143+
// TransactionOptions.skip_prepare is false and Prepare is not called on this
144+
// transaction before Commit.
143145
virtual Status Commit() = 0;
144146

145147
// Discard all batched writes in this transaction.

include/rocksdb/utilities/transaction_db.h

+4
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ struct TransactionOptions {
172172
// Default: false
173173
bool skip_concurrency_control = false;
174174

175+
// In pessimistic transaction, if this is true, then you can skip Prepare
176+
// before Commit, otherwise, you must Prepare before Commit.
177+
bool skip_prepare = true;
178+
175179
// See TransactionDBOptions::default_write_batch_flush_threshold for
176180
// description. If a negative value is specified, then the default value from
177181
// TransactionDBOptions is used.

utilities/transactions/pessimistic_transaction.cc

+6-4
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ void PessimisticTransaction::Initialize(const TransactionOptions& txn_options) {
8787
}
8888
use_only_the_last_commit_time_batch_for_recovery_ =
8989
txn_options.use_only_the_last_commit_time_batch_for_recovery;
90+
skip_prepare_ = txn_options.skip_prepare;
9091
}
9192

9293
PessimisticTransaction::~PessimisticTransaction() {
@@ -283,10 +284,11 @@ Status PessimisticTransaction::Commit() {
283284
commit_prepared = true;
284285
} else if (txn_state_ == STARTED) {
285286
// expiration and lock stealing is not a concern
286-
commit_without_prepare = true;
287-
// TODO(myabandeh): what if the user mistakenly forgets prepare? We should
288-
// add an option so that the user explictly express the intention of
289-
// skipping the prepare phase.
287+
if (skip_prepare_) {
288+
commit_without_prepare = true;
289+
} else {
290+
return Status::TxnNotPrepared();
291+
}
290292
}
291293

292294
if (commit_without_prepare) {

utilities/transactions/pessimistic_transaction.h

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ class PessimisticTransaction : public TransactionBaseImpl {
120120
// Refer to
121121
// TransactionOptions::use_only_the_last_commit_time_batch_for_recovery
122122
bool use_only_the_last_commit_time_batch_for_recovery_ = false;
123+
// Refer to
124+
// TransactionOptions::skip_prepare
125+
bool skip_prepare_ = false;
123126

124127
virtual Status PrepareInternal() = 0;
125128

utilities/transactions/transaction_test.cc

+22
Original file line numberDiff line numberDiff line change
@@ -6205,6 +6205,28 @@ TEST_P(TransactionTest, DoubleCrashInRecovery) {
62056205
}
62066206
}
62076207

6208+
TEST_P(TransactionTest, CommitWithoutPrepare) {
6209+
{
6210+
// skip_prepare = false.
6211+
WriteOptions write_options;
6212+
TransactionOptions txn_options;
6213+
txn_options.skip_prepare = false;
6214+
Transaction* txn = db->BeginTransaction(write_options, txn_options);
6215+
ASSERT_TRUE(txn->Commit().IsTxnNotPrepared());
6216+
delete txn;
6217+
}
6218+
6219+
{
6220+
// skip_prepare = true.
6221+
WriteOptions write_options;
6222+
TransactionOptions txn_options;
6223+
txn_options.skip_prepare = true;
6224+
Transaction* txn = db->BeginTransaction(write_options, txn_options);
6225+
ASSERT_OK(txn->Commit());
6226+
delete txn;
6227+
}
6228+
}
6229+
62086230
} // namespace ROCKSDB_NAMESPACE
62096231

62106232
int main(int argc, char** argv) {

0 commit comments

Comments
 (0)