mirror of https://github.com/facebook/rocksdb.git
adds missing PopSavePoint method to Transaction (#4256)
Summary: Transaction has had methods to deal with SavePoints already, but was missing the PopSavePoint method provided by WriteBatch and WriteBatchWithIndex. This PR adds PopSavePoint to Transaction as well. Having the method on Transaction-level too is useful for applications that repeatedly execute a sequence of operations that normally succeed, but infrequently need to get rolled back. Using SavePoints here is sensible, but as operations normally succeed the application may pile up a lot of useless SavePoints inside a Transaction, leading to slightly increased memory usage for managing the unneeded SavePoints. Pull Request resolved: https://github.com/facebook/rocksdb/pull/4256 Differential Revision: D9326932 Pulled By: yiwu-arbug fbshipit-source-id: 53a0af18a6c7e87feff8a56f1f3eab9df7f371d6
This commit is contained in:
parent
c7cf981a85
commit
90f744941d
|
@ -152,6 +152,12 @@ class Transaction {
|
|||
// If there is no previous call to SetSavePoint(), returns Status::NotFound()
|
||||
virtual Status RollbackToSavePoint() = 0;
|
||||
|
||||
// Pop the most recent save point.
|
||||
// If there is no previous call to SetSavePoint(), Status::NotFound()
|
||||
// will be returned.
|
||||
// Otherwise returns Status::OK().
|
||||
virtual Status PopSavePoint() = 0;
|
||||
|
||||
// This function is similar to DB::Get() except it will also read pending
|
||||
// changes in this transaction. Currently, this function will return
|
||||
// Status::MergeInProgress if the most recent write to the queried key in
|
||||
|
|
|
@ -179,6 +179,19 @@ Status TransactionBaseImpl::RollbackToSavePoint() {
|
|||
}
|
||||
}
|
||||
|
||||
Status TransactionBaseImpl::PopSavePoint() {
|
||||
if (save_points_ == nullptr ||
|
||||
save_points_->empty()) {
|
||||
// No SavePoint yet.
|
||||
assert(write_batch_.PopSavePoint().IsNotFound());
|
||||
return Status::NotFound();
|
||||
}
|
||||
|
||||
assert(!save_points_->empty());
|
||||
save_points_->pop();
|
||||
return write_batch_.PopSavePoint();
|
||||
}
|
||||
|
||||
Status TransactionBaseImpl::Get(const ReadOptions& read_options,
|
||||
ColumnFamilyHandle* column_family,
|
||||
const Slice& key, std::string* value) {
|
||||
|
|
|
@ -46,6 +46,8 @@ class TransactionBaseImpl : public Transaction {
|
|||
|
||||
Status RollbackToSavePoint() override;
|
||||
|
||||
Status PopSavePoint() override;
|
||||
|
||||
using Transaction::Get;
|
||||
Status Get(const ReadOptions& options, ColumnFamilyHandle* column_family,
|
||||
const Slice& key, std::string* value) override;
|
||||
|
|
|
@ -3771,6 +3771,79 @@ TEST_P(TransactionTest, SavepointTest2) {
|
|||
delete txn2;
|
||||
}
|
||||
|
||||
TEST_P(TransactionTest, SavepointTest3) {
|
||||
WriteOptions write_options;
|
||||
ReadOptions read_options;
|
||||
TransactionOptions txn_options;
|
||||
Status s;
|
||||
|
||||
txn_options.lock_timeout = 1; // 1 ms
|
||||
Transaction* txn1 = db->BeginTransaction(write_options, txn_options);
|
||||
ASSERT_TRUE(txn1);
|
||||
|
||||
s = txn1->PopSavePoint(); // No SavePoint present
|
||||
ASSERT_TRUE(s.IsNotFound());
|
||||
|
||||
s = txn1->Put("A", "");
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = txn1->PopSavePoint(); // Still no SavePoint present
|
||||
ASSERT_TRUE(s.IsNotFound());
|
||||
|
||||
txn1->SetSavePoint(); // 1
|
||||
|
||||
s = txn1->Put("A", "a");
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = txn1->PopSavePoint(); // Remove 1
|
||||
ASSERT_TRUE(txn1->RollbackToSavePoint().IsNotFound());
|
||||
|
||||
// Verify that "A" is still locked
|
||||
Transaction* txn2 = db->BeginTransaction(write_options, txn_options);
|
||||
ASSERT_TRUE(txn2);
|
||||
|
||||
s = txn2->Put("A", "a2");
|
||||
ASSERT_TRUE(s.IsTimedOut());
|
||||
delete txn2;
|
||||
|
||||
txn1->SetSavePoint(); // 2
|
||||
|
||||
s = txn1->Put("B", "b");
|
||||
ASSERT_OK(s);
|
||||
|
||||
txn1->SetSavePoint(); // 3
|
||||
|
||||
s = txn1->Put("B", "b2");
|
||||
ASSERT_OK(s);
|
||||
|
||||
ASSERT_OK(txn1->RollbackToSavePoint()); // Roll back to 2
|
||||
|
||||
s = txn1->PopSavePoint();
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = txn1->PopSavePoint();
|
||||
ASSERT_TRUE(s.IsNotFound());
|
||||
|
||||
s = txn1->Commit();
|
||||
ASSERT_OK(s);
|
||||
delete txn1;
|
||||
|
||||
std::string value;
|
||||
|
||||
// tnx1 should have modified "A" to "a"
|
||||
s = db->Get(read_options, "A", &value);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("a", value);
|
||||
|
||||
// tnx1 should have set "B" to just "b"
|
||||
s = db->Get(read_options, "B", &value);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("b", value);
|
||||
|
||||
s = db->Get(read_options, "C", &value);
|
||||
ASSERT_TRUE(s.IsNotFound());
|
||||
}
|
||||
|
||||
TEST_P(TransactionTest, UndoGetForUpdateTest) {
|
||||
WriteOptions write_options;
|
||||
ReadOptions read_options;
|
||||
|
|
Loading…
Reference in New Issue