@ -5,7 +5,7 @@
# ifndef ROCKSDB_LITE
# include "utilities/transactions/transaction_impl .h"
# include "utilities/transactions/pessimistic_ transaction.h"
# include <map>
# include <set>
@ -29,13 +29,13 @@ namespace rocksdb {
struct WriteOptions ;
std : : atomic < TransactionID > PessimisticTx n : : txn_id_counter_ ( 1 ) ;
std : : atomic < TransactionID > PessimisticTransactio n : : txn_id_counter_ ( 1 ) ;
TransactionID PessimisticTx n : : GenTxnID ( ) {
TransactionID PessimisticTransactio n : : GenTxnID ( ) {
return txn_id_counter_ . fetch_add ( 1 ) ;
}
PessimisticTxn : : PessimisticTx n ( TransactionDB * txn_db ,
PessimisticTransaction : : PessimisticTransactio n ( TransactionDB * txn_db ,
const WriteOptions & write_options ,
const TransactionOptions & txn_options )
: TransactionBaseImpl ( txn_db - > GetRootDB ( ) , write_options ) ,
@ -53,7 +53,7 @@ PessimisticTxn::PessimisticTxn(TransactionDB* txn_db,
Initialize ( txn_options ) ;
}
void PessimisticTx n : : Initialize ( const TransactionOptions & txn_options ) {
void PessimisticTransactio n : : Initialize ( const TransactionOptions & txn_options ) {
txn_id_ = GenTxnID ( ) ;
txn_state_ = STARTED ;
@ -84,7 +84,7 @@ void PessimisticTxn::Initialize(const TransactionOptions& txn_options) {
}
}
PessimisticTx n : : ~ PessimisticTx n ( ) {
PessimisticTransactio n : : ~ PessimisticTransactio n ( ) {
txn_db_impl_ - > UnLock ( this , & GetTrackedKeys ( ) ) ;
if ( expiration_time_ > 0 ) {
txn_db_impl_ - > RemoveExpirableTransaction ( txn_id_ ) ;
@ -94,12 +94,12 @@ PessimisticTxn::~PessimisticTxn() {
}
}
void PessimisticTx n : : Clear ( ) {
void PessimisticTransactio n : : Clear ( ) {
txn_db_impl_ - > UnLock ( this , & GetTrackedKeys ( ) ) ;
TransactionBaseImpl : : Clear ( ) ;
}
void PessimisticTx n : : Reinitialize ( TransactionDB * txn_db ,
void PessimisticTransactio n : : Reinitialize ( TransactionDB * txn_db ,
const WriteOptions & write_options ,
const TransactionOptions & txn_options ) {
if ( ! name_ . empty ( ) & & txn_state_ ! = COMMITED ) {
@ -109,7 +109,7 @@ void PessimisticTxn::Reinitialize(TransactionDB* txn_db,
Initialize ( txn_options ) ;
}
bool PessimisticTx n : : IsExpired ( ) const {
bool PessimisticTransactio n : : IsExpired ( ) const {
if ( expiration_time_ > 0 ) {
if ( db_ - > GetEnv ( ) - > NowMicros ( ) > = expiration_time_ ) {
// Transaction is expired.
@ -120,12 +120,12 @@ bool PessimisticTxn::IsExpired() const {
return false ;
}
WriteCommittedTxnImpl : : WriteCommittedTxnImpl (
WriteCommittedTxn : : WriteCommittedTxn (
TransactionDB * txn_db , const WriteOptions & write_options ,
const TransactionOptions & txn_options )
: PessimisticTx n ( txn_db , write_options , txn_options ) { } ;
: PessimisticTransactio n ( txn_db , write_options , txn_options ) { } ;
Status WriteCommittedTxnImpl : : CommitBatch ( WriteBatch * batch ) {
Status WriteCommittedTxn : : CommitBatch ( WriteBatch * batch ) {
TransactionKeyMap keys_to_unlock ;
Status s = LockBatch ( batch , & keys_to_unlock ) ;
@ -163,7 +163,7 @@ Status WriteCommittedTxnImpl::CommitBatch(WriteBatch* batch) {
return s ;
}
Status WriteCommittedTxnImpl : : Prepare ( ) {
Status PessimisticTransaction : : Prepare ( ) {
Status s ;
if ( name_ . empty ( ) ) {
@ -192,12 +192,7 @@ Status WriteCommittedTxnImpl::Prepare() {
txn_state_ . store ( AWAITING_PREPARE ) ;
// transaction can't expire after preparation
expiration_time_ = 0 ;
WriteOptions write_options = write_options_ ;
write_options . disableWAL = false ;
WriteBatchInternal : : MarkEndPrepare ( GetWriteBatch ( ) - > GetWriteBatch ( ) , name_ ) ;
s = db_impl_ - > WriteImpl ( write_options , GetWriteBatch ( ) - > GetWriteBatch ( ) ,
/*callback*/ nullptr , & log_number_ , /*log ref*/ 0 ,
/* disable_memtable*/ true ) ;
s = PrepareInternal ( ) ;
if ( s . ok ( ) ) {
assert ( log_number_ ! = 0 ) ;
dbimpl_ - > MarkLogAsContainingPrepSection ( log_number_ ) ;
@ -218,9 +213,20 @@ Status WriteCommittedTxnImpl::Prepare() {
return s ;
}
Status WriteCommittedTxnImpl : : Commit ( ) {
Status WriteCommittedTxn : : PrepareInternal ( ) {
WriteOptions write_options = write_options_ ;
write_options . disableWAL = false ;
WriteBatchInternal : : MarkEndPrepare ( GetWriteBatch ( ) - > GetWriteBatch ( ) , name_ ) ;
Status s =
db_impl_ - > WriteImpl ( write_options , GetWriteBatch ( ) - > GetWriteBatch ( ) ,
/*callback*/ nullptr , & log_number_ , /*log ref*/ 0 ,
/* disable_memtable*/ true ) ;
return s ;
}
Status PessimisticTransaction : : Commit ( ) {
Status s ;
bool commit_single = false ;
bool commit_without_prepar e = false ;
bool commit_prepared = false ;
if ( IsExpired ( ) ) {
@ -234,25 +240,28 @@ Status WriteCommittedTxnImpl::Commit() {
// our locks stolen. In this case the only valid state is STARTED because
// a state of PREPARED would have a cleared expiration_time_.
TransactionState expected = STARTED ;
commit_singl e = std : : atomic_compare_exchange_strong ( & txn_state_ , & expected ,
AWAITING_COMMIT ) ;
commit_without_prepar e = std : : atomic_compare_exchange_strong (
& txn_state_ , & expected , AWAITING_COMMIT ) ;
TEST_SYNC_POINT ( " TransactionTest::ExpirableTransactionDataRace:1 " ) ;
} else if ( txn_state_ = = PREPARED ) {
// expiration and lock stealing is not a concern
commit_prepared = true ;
} else if ( txn_state_ = = STARTED ) {
// expiration and lock stealing is not a concern
commit_single = true ;
commit_without_prepare = true ;
// TODO(myabandeh): what if the user mistakenly forgets prepare? We should
// add an option so that the user explictly express the intention of
// skipping the prepare phase.
}
if ( commit_single ) {
if ( commit_without_prepar e ) {
assert ( ! commit_prepared ) ;
if ( WriteBatchInternal : : Count ( GetCommitTimeWriteBatch ( ) ) > 0 ) {
s = Status : : InvalidArgument (
" Commit-time batch contains values that will not be committed. " ) ;
} else {
txn_state_ . store ( AWAITING_COMMIT ) ;
s = db_ - > Write ( write_options_ , GetWriteBatch ( ) - > GetWriteBatch ( ) ) ;
s = CommitWithoutPrepareInternal ( ) ;
Clear ( ) ;
if ( s . ok ( ) ) {
txn_state_ . store ( COMMITED ) ;
@ -261,21 +270,8 @@ Status WriteCommittedTxnImpl::Commit() {
} else if ( commit_prepared ) {
txn_state_ . store ( AWAITING_COMMIT ) ;
// We take the commit-time batch and append the Commit marker.
// The Memtable will ignore the Commit marker in non-recovery mode
WriteBatch * working_batch = GetCommitTimeWriteBatch ( ) ;
WriteBatchInternal : : MarkCommit ( working_batch , name_ ) ;
// any operations appended to this working_batch will be ignored from WAL
working_batch - > MarkWalTerminationPoint ( ) ;
s = CommitInternal ( ) ;
// insert prepared batch into Memtable only skipping WAL.
// Memtable will ignore BeginPrepare/EndPrepare markers
// in non recovery mode and simply insert the values
WriteBatchInternal : : Append ( working_batch , GetWriteBatch ( ) - > GetWriteBatch ( ) ) ;
s = db_impl_ - > WriteImpl ( write_options_ , working_batch , nullptr , nullptr ,
log_number_ ) ;
if ( ! s . ok ( ) ) {
ROCKS_LOG_WARN ( db_impl_ - > immutable_db_options ( ) . info_log ,
" Commit write failed " ) ;
@ -304,7 +300,31 @@ Status WriteCommittedTxnImpl::Commit() {
return s ;
}
Status WriteCommittedTxnImpl : : Rollback ( ) {
Status WriteCommittedTxn : : CommitWithoutPrepareInternal ( ) {
Status s = db_ - > Write ( write_options_ , GetWriteBatch ( ) - > GetWriteBatch ( ) ) ;
return s ;
}
Status WriteCommittedTxn : : CommitInternal ( ) {
// We take the commit-time batch and append the Commit marker.
// The Memtable will ignore the Commit marker in non-recovery mode
WriteBatch * working_batch = GetCommitTimeWriteBatch ( ) ;
WriteBatchInternal : : MarkCommit ( working_batch , name_ ) ;
// any operations appended to this working_batch will be ignored from WAL
working_batch - > MarkWalTerminationPoint ( ) ;
// insert prepared batch into Memtable only skipping WAL.
// Memtable will ignore BeginPrepare/EndPrepare markers
// in non recovery mode and simply insert the values
WriteBatchInternal : : Append ( working_batch , GetWriteBatch ( ) - > GetWriteBatch ( ) ) ;
auto s = db_impl_ - > WriteImpl ( write_options_ , working_batch , nullptr , nullptr ,
log_number_ ) ;
return s ;
}
Status WriteCommittedTxn : : Rollback ( ) {
Status s ;
if ( txn_state_ = = PREPARED ) {
WriteBatch rollback_marker ;
@ -331,7 +351,7 @@ Status WriteCommittedTxnImpl::Rollback() {
return s ;
}
Status PessimisticTx n : : RollbackToSavePoint ( ) {
Status PessimisticTransactio n : : RollbackToSavePoint ( ) {
if ( txn_state_ ! = STARTED ) {
return Status : : InvalidArgument ( " Transaction is beyond state for rollback. " ) ;
}
@ -349,7 +369,7 @@ Status PessimisticTxn::RollbackToSavePoint() {
// Lock all keys in this batch.
// On success, caller should unlock keys_to_unlock
Status PessimisticTx n : : LockBatch ( WriteBatch * batch ,
Status PessimisticTransactio n : : LockBatch ( WriteBatch * batch ,
TransactionKeyMap * keys_to_unlock ) {
class Handler : public WriteBatch : : Handler {
public :
@ -372,12 +392,12 @@ Status PessimisticTxn::LockBatch(WriteBatch* batch,
}
virtual Status PutCF ( uint32_t column_family_id , const Slice & key ,
const Slice & value ) override {
const Slice & /* unused */ ) override {
RecordKey ( column_family_id , key ) ;
return Status : : OK ( ) ;
}
virtual Status MergeCF ( uint32_t column_family_id , const Slice & key ,
const Slice & value ) override {
const Slice & /* unused */ ) override {
RecordKey ( column_family_id , key ) ;
return Status : : OK ( ) ;
}
@ -427,7 +447,7 @@ Status PessimisticTxn::LockBatch(WriteBatch* batch,
// If check_shapshot is true and this transaction has a snapshot set,
// this key will only be locked if there have been no writes to this key since
// the snapshot time.
Status PessimisticTx n : : TryLock ( ColumnFamilyHandle * column_family ,
Status PessimisticTransactio n : : TryLock ( ColumnFamilyHandle * column_family ,
const Slice & key , bool read_only , bool exclusive ,
bool untracked ) {
uint32_t cfh_id = GetColumnFamilyID ( column_family ) ;
@ -515,7 +535,7 @@ Status PessimisticTxn::TryLock(ColumnFamilyHandle* column_family,
// Return OK() if this key has not been modified more recently than the
// transaction snapshot_.
Status PessimisticTx n : : ValidateSnapshot ( ColumnFamilyHandle * column_family ,
Status PessimisticTransactio n : : ValidateSnapshot ( ColumnFamilyHandle * column_family ,
const Slice & key ,
SequenceNumber prev_seqno ,
SequenceNumber * new_seqno ) {
@ -539,19 +559,19 @@ Status PessimisticTxn::ValidateSnapshot(ColumnFamilyHandle* column_family,
false /* cache_only */ ) ;
}
bool PessimisticTx n : : TryStealingLocks ( ) {
bool PessimisticTransactio n : : TryStealingLocks ( ) {
assert ( IsExpired ( ) ) ;
TransactionState expected = STARTED ;
return std : : atomic_compare_exchange_strong ( & txn_state_ , & expected ,
LOCKS_STOLEN ) ;
}
void PessimisticTx n : : UnlockGetForUpdate ( ColumnFamilyHandle * column_family ,
void PessimisticTransactio n : : UnlockGetForUpdate ( ColumnFamilyHandle * column_family ,
const Slice & key ) {
txn_db_impl_ - > UnLock ( this , GetColumnFamilyID ( column_family ) , key . ToString ( ) ) ;
}
Status PessimisticTx n : : SetName ( const TransactionName & name ) {
Status PessimisticTransactio n : : SetName ( const TransactionName & name ) {
Status s ;
if ( txn_state_ = = STARTED ) {
if ( name_ . length ( ) ) {