diff --git a/include/rocksdb/utilities/transaction_db.h b/include/rocksdb/utilities/transaction_db.h index 8435f936a..6bec03eac 100644 --- a/include/rocksdb/utilities/transaction_db.h +++ b/include/rocksdb/utilities/transaction_db.h @@ -169,12 +169,15 @@ struct DeadlockInfo { struct DeadlockPath { std::vector path; bool limit_exceeded; + int64_t deadlock_time; - explicit DeadlockPath(std::vector path_entry) - : path(path_entry), limit_exceeded(false) {} + explicit DeadlockPath( + std::vector path_entry, const int64_t& dl_time) + : path(path_entry), limit_exceeded(false), deadlock_time(dl_time) {} // empty path, limit exceeded constructor and default constructor - explicit DeadlockPath(bool limit = false) : path(0), limit_exceeded(limit) {} + explicit DeadlockPath(const int64_t& dl_time = 0, bool limit = false) + : path(0), limit_exceeded(limit), deadlock_time(dl_time) {} bool empty() { return path.empty() && !limit_exceeded; } }; diff --git a/utilities/transactions/transaction_lock_mgr.cc b/utilities/transactions/transaction_lock_mgr.cc index 6bcae4af4..19321de48 100644 --- a/utilities/transactions/transaction_lock_mgr.cc +++ b/utilities/transactions/transaction_lock_mgr.cc @@ -372,7 +372,7 @@ Status TransactionLockMgr::AcquireWithTimeout( if (wait_ids.size() != 0) { if (txn->IsDeadlockDetect()) { if (IncrementWaiters(txn, wait_ids, key, column_family_id, - lock_info.exclusive)) { + lock_info.exclusive, env)) { result = Status::Busy(Status::SubCode::kDeadlock); stripe->stripe_mutex->UnLock(); return result; @@ -444,7 +444,7 @@ void TransactionLockMgr::DecrementWaitersImpl( bool TransactionLockMgr::IncrementWaiters( const PessimisticTransaction* txn, const autovector& wait_ids, const std::string& key, - const uint32_t& cf_id, const bool& exclusive) { + const uint32_t& cf_id, const bool& exclusive, Env* const env) { auto id = txn->GetID(); std::vector queue_parents(txn->GetDeadlockDetectDepth()); std::vector queue_values(txn->GetDeadlockDetectDepth()); @@ -468,6 +468,7 @@ bool TransactionLockMgr::IncrementWaiters( const auto* next_ids = &wait_ids; int parent = -1; + int64_t deadlock_time = 0; for (int tail = 0, head = 0; head < txn->GetDeadlockDetectDepth(); head++) { int i = 0; if (next_ids) { @@ -497,8 +498,10 @@ bool TransactionLockMgr::IncrementWaiters( extracted_info.m_exclusive}); head = queue_parents[head]; } + env->GetCurrentTime(&deadlock_time); std::reverse(path.begin(), path.end()); - dlock_buffer_.AddNewPath(DeadlockPath(path)); + dlock_buffer_.AddNewPath(DeadlockPath(path, deadlock_time)); + deadlock_time = 0; DecrementWaitersImpl(txn, wait_ids); return true; } else if (!wait_txn_map_.Contains(next)) { @@ -511,7 +514,8 @@ bool TransactionLockMgr::IncrementWaiters( } // Wait cycle too big, just assume deadlock. - dlock_buffer_.AddNewPath(DeadlockPath(true)); + env->GetCurrentTime(&deadlock_time); + dlock_buffer_.AddNewPath(DeadlockPath(deadlock_time, true)); DecrementWaitersImpl(txn, wait_ids); return true; } diff --git a/utilities/transactions/transaction_lock_mgr.h b/utilities/transactions/transaction_lock_mgr.h index abf7c5d3d..cb650d9fc 100644 --- a/utilities/transactions/transaction_lock_mgr.h +++ b/utilities/transactions/transaction_lock_mgr.h @@ -143,7 +143,7 @@ class TransactionLockMgr { bool IncrementWaiters(const PessimisticTransaction* txn, const autovector& wait_ids, const std::string& key, const uint32_t& cf_id, - const bool& exclusive); + const bool& exclusive, Env* const env); void DecrementWaiters(const PessimisticTransaction* txn, const autovector& wait_ids); void DecrementWaitersImpl(const PessimisticTransaction* txn, diff --git a/utilities/transactions/transaction_test.cc b/utilities/transactions/transaction_test.cc index 21b80c203..6eb0e06fb 100644 --- a/utilities/transactions/transaction_test.cc +++ b/utilities/transactions/transaction_test.cc @@ -465,6 +465,14 @@ TEST_P(TransactionTest, DeadlockCycleShared) { ASSERT_EQ(dlock_buffer.size(), curr_dlock_buffer_len_); auto dlock_entry = dlock_buffer[0].path; ASSERT_EQ(dlock_entry.size(), kInitialMaxDeadlocks); + int64_t pre_deadlock_time = dlock_buffer[0].deadlock_time; + int64_t cur_deadlock_time = 0; + for (auto const& dl_path_rec : dlock_buffer) { + cur_deadlock_time = dl_path_rec.deadlock_time; + ASSERT_NE(cur_deadlock_time, 0); + ASSERT_TRUE(cur_deadlock_time <= pre_deadlock_time); + pre_deadlock_time = cur_deadlock_time; + } int64_t curr_waiting_key = 0; @@ -670,6 +678,15 @@ TEST_P(TransactionTest, DeadlockCycle) { ASSERT_EQ(dlock_entry.size(), check_len); ASSERT_EQ(dlock_buffer[0].limit_exceeded, check_limit_flag); + int64_t pre_deadlock_time = dlock_buffer[0].deadlock_time; + int64_t cur_deadlock_time = 0; + for (auto const& dl_path_rec : dlock_buffer) { + cur_deadlock_time = dl_path_rec.deadlock_time; + ASSERT_NE(cur_deadlock_time, 0); + ASSERT_TRUE(cur_deadlock_time <= pre_deadlock_time); + pre_deadlock_time = cur_deadlock_time; + } + // Iterates backwards over path verifying decreasing txn_ids. for (auto it = dlock_entry.rbegin(); it != dlock_entry.rend(); it++) { auto dl_node = *it;