Fix an assertion failure in range locking, locktree code. (#7938)

Summary:
Fix this scenario:
trx1> acquire shared lock on $key
trx2> acquire shared lock on the same $key
trx1> attempt to acquire a unique lock on $key.

Lock acquisition will fail, and deadlock detection will start.
It will call iterate_and_get_overlapping_row_locks() which will
produce a list with two locks (shared locks by trx1 and trx2).

However the code in lock_request::build_wait_graph() was not prepared
to find the lock by the same transaction in the list of conflicting
locks. Fix it to ignore it.

(One may suggest to fix iterate_and_get_overlapping_row_locks() to not
include locks by trx1. This is not a good idea, because that function
is also used to report all locks currently held)

Pull Request resolved: https://github.com/facebook/rocksdb/pull/7938

Reviewed By: zhichao-cao

Differential Revision: D26529374

Pulled By: ajkr

fbshipit-source-id: d89cbed008db1a97a8f2351b9bfb75310750d16a
main
Sergei Petrunia 4 years ago committed by Facebook GitHub Bot
parent ad25b1afb9
commit c9878baa87
  1. 35
      utilities/transactions/lock/range/range_locking_test.cc
  2. 4
      utilities/transactions/lock/range/range_tree/lib/locktree/locktree.cc

@ -136,6 +136,41 @@ TEST_F(RangeLockingTest, MyRocksLikeUpdate) {
delete txn0;
}
TEST_F(RangeLockingTest, UpgradeLockAndGetConflict) {
WriteOptions write_options;
TransactionOptions txn_options;
auto cf = db->DefaultColumnFamily();
Status s;
std::string value;
txn_options.lock_timeout= 10;
Transaction* txn0 = db->BeginTransaction(write_options, txn_options);
Transaction* txn1 = db->BeginTransaction(write_options, txn_options);
// Get the shared lock in txn0
s = txn0->GetForUpdate(ReadOptions(), cf,
Slice("a"), &value,
false /*exclusive*/);
ASSERT_TRUE(s.IsNotFound());
// Get the shared lock on the same key in txn1
s = txn1->GetForUpdate(ReadOptions(), cf,
Slice("a"), &value,
false /*exclusive*/);
ASSERT_TRUE(s.IsNotFound());
// Now, try getting an exclusive lock that overlaps with the above
s = txn0->GetRangeLock(cf, Endpoint("a"), Endpoint("b"));
ASSERT_TRUE(s.IsTimedOut());
txn0->Rollback();
txn1->Rollback();
delete txn0;
delete txn1;
}
TEST_F(RangeLockingTest, SnapshotValidation) {
Status s;
Slice key_slice = Slice("k");

@ -187,8 +187,10 @@ static bool determine_conflicting_txnids(
if (other_txnid != txnid) {
if (conflicts) {
if (other_txnid == TXNID_SHARED) {
// Add all shared lock owners, except this transaction.
for (TXNID shared_id : *lock.owners) {
conflicts->add(shared_id);
if (shared_id != txnid)
conflicts->add(shared_id);
}
} else {
conflicts->add(other_txnid);

Loading…
Cancel
Save