]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/utilities/transactions/lock/point/point_lock_manager_test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / utilities / transactions / lock / point / point_lock_manager_test.cc
CommitLineData
20effc67
TL
1// Copyright (c) 2020-present, Facebook, Inc. All rights reserved.
2// This source code is licensed under both the GPLv2 (found in the
3// COPYING file in the root directory) and Apache 2.0 License
4// (found in the LICENSE.Apache file in the root directory).
5
6#ifndef ROCKSDB_LITE
7
1e59de90 8#include "utilities/transactions/lock/point/point_lock_manager_test.h"
20effc67
TL
9
10namespace ROCKSDB_NAMESPACE {
11
1e59de90
TL
12// This test is not applicable for Range Lock manager as Range Lock Manager
13// operates on Column Families, not their ids.
20effc67
TL
14TEST_F(PointLockManagerTest, LockNonExistingColumnFamily) {
15 MockColumnFamilyHandle cf(1024);
16 locker_->RemoveColumnFamily(&cf);
17 auto txn = NewTxn();
18 auto s = locker_->TryLock(txn, 1024, "k", env_, true);
19 ASSERT_TRUE(s.IsInvalidArgument());
20 ASSERT_STREQ(s.getState(), "Column family id not found: 1024");
21 delete txn;
22}
23
24TEST_F(PointLockManagerTest, LockStatus) {
25 MockColumnFamilyHandle cf1(1024), cf2(2048);
26 locker_->AddColumnFamily(&cf1);
27 locker_->AddColumnFamily(&cf2);
28
29 auto txn1 = NewTxn();
30 ASSERT_OK(locker_->TryLock(txn1, 1024, "k1", env_, true));
31 ASSERT_OK(locker_->TryLock(txn1, 2048, "k1", env_, true));
32
33 auto txn2 = NewTxn();
34 ASSERT_OK(locker_->TryLock(txn2, 1024, "k2", env_, false));
35 ASSERT_OK(locker_->TryLock(txn2, 2048, "k2", env_, false));
36
37 auto s = locker_->GetPointLockStatus();
38 ASSERT_EQ(s.size(), 4u);
39 for (uint32_t cf_id : {1024, 2048}) {
40 ASSERT_EQ(s.count(cf_id), 2u);
41 auto range = s.equal_range(cf_id);
42 for (auto it = range.first; it != range.second; it++) {
43 ASSERT_TRUE(it->second.key == "k1" || it->second.key == "k2");
44 if (it->second.key == "k1") {
45 ASSERT_EQ(it->second.exclusive, true);
46 ASSERT_EQ(it->second.ids.size(), 1u);
47 ASSERT_EQ(it->second.ids[0], txn1->GetID());
48 } else if (it->second.key == "k2") {
49 ASSERT_EQ(it->second.exclusive, false);
50 ASSERT_EQ(it->second.ids.size(), 1u);
51 ASSERT_EQ(it->second.ids[0], txn2->GetID());
52 }
53 }
54 }
55
1e59de90
TL
56 // Cleanup
57 locker_->UnLock(txn1, 1024, "k1", env_);
58 locker_->UnLock(txn1, 2048, "k1", env_);
59 locker_->UnLock(txn2, 1024, "k2", env_);
60 locker_->UnLock(txn2, 2048, "k2", env_);
61
20effc67
TL
62 delete txn1;
63 delete txn2;
64}
65
66TEST_F(PointLockManagerTest, UnlockExclusive) {
67 MockColumnFamilyHandle cf(1);
68 locker_->AddColumnFamily(&cf);
69
70 auto txn1 = NewTxn();
71 ASSERT_OK(locker_->TryLock(txn1, 1, "k", env_, true));
72 locker_->UnLock(txn1, 1, "k", env_);
73
74 auto txn2 = NewTxn();
75 ASSERT_OK(locker_->TryLock(txn2, 1, "k", env_, true));
76
1e59de90
TL
77 // Cleanup
78 locker_->UnLock(txn2, 1, "k", env_);
79
20effc67
TL
80 delete txn1;
81 delete txn2;
82}
83
84TEST_F(PointLockManagerTest, UnlockShared) {
85 MockColumnFamilyHandle cf(1);
86 locker_->AddColumnFamily(&cf);
87
88 auto txn1 = NewTxn();
89 ASSERT_OK(locker_->TryLock(txn1, 1, "k", env_, false));
90 locker_->UnLock(txn1, 1, "k", env_);
91
92 auto txn2 = NewTxn();
93 ASSERT_OK(locker_->TryLock(txn2, 1, "k", env_, true));
94
1e59de90
TL
95 // Cleanup
96 locker_->UnLock(txn2, 1, "k", env_);
20effc67 97
20effc67
TL
98 delete txn1;
99 delete txn2;
100}
101
1e59de90
TL
102// This test doesn't work with Range Lock Manager, because Range Lock Manager
103// doesn't support deadlock_detect_depth.
20effc67
TL
104
105TEST_F(PointLockManagerTest, DeadlockDepthExceeded) {
106 // Tests that when detecting deadlock, if the detection depth is exceeded,
107 // it's also viewed as deadlock.
108 MockColumnFamilyHandle cf(1);
109 locker_->AddColumnFamily(&cf);
110 TransactionOptions txn_opt;
111 txn_opt.deadlock_detect = true;
112 txn_opt.deadlock_detect_depth = 1;
113 txn_opt.lock_timeout = 1000000;
114 auto txn1 = NewTxn(txn_opt);
115 auto txn2 = NewTxn(txn_opt);
116 auto txn3 = NewTxn(txn_opt);
117 auto txn4 = NewTxn(txn_opt);
118 // "a ->(k) b" means transaction a is waiting for transaction b to release
119 // the held lock on key k.
120 // txn4 ->(k3) -> txn3 ->(k2) txn2 ->(k1) txn1
121 // txn3's deadlock detection will exceed the detection depth 1,
122 // which will be viewed as a deadlock.
123 // NOTE:
124 // txn4 ->(k3) -> txn3 must be set up before
125 // txn3 ->(k2) -> txn2, because to trigger deadlock detection for txn3,
126 // it must have another txn waiting on it, which is txn4 in this case.
127 ASSERT_OK(locker_->TryLock(txn1, 1, "k1", env_, true));
128
1e59de90 129 port::Thread t1 = BlockUntilWaitingTxn(wait_sync_point_name_, [&]() {
20effc67
TL
130 ASSERT_OK(locker_->TryLock(txn2, 1, "k2", env_, true));
131 // block because txn1 is holding a lock on k1.
132 locker_->TryLock(txn2, 1, "k1", env_, true);
133 });
134
135 ASSERT_OK(locker_->TryLock(txn3, 1, "k3", env_, true));
136
1e59de90 137 port::Thread t2 = BlockUntilWaitingTxn(wait_sync_point_name_, [&]() {
20effc67
TL
138 // block because txn3 is holding a lock on k1.
139 locker_->TryLock(txn4, 1, "k3", env_, true);
140 });
141
142 auto s = locker_->TryLock(txn3, 1, "k2", env_, true);
143 ASSERT_TRUE(s.IsBusy());
144 ASSERT_EQ(s.subcode(), Status::SubCode::kDeadlock);
145
146 std::vector<DeadlockPath> deadlock_paths = locker_->GetDeadlockInfoBuffer();
147 ASSERT_EQ(deadlock_paths.size(), 1u);
148 ASSERT_TRUE(deadlock_paths[0].limit_exceeded);
149
150 locker_->UnLock(txn1, 1, "k1", env_);
151 locker_->UnLock(txn3, 1, "k3", env_);
152 t1.join();
153 t2.join();
154
155 delete txn4;
156 delete txn3;
157 delete txn2;
158 delete txn1;
159}
160
1e59de90
TL
161INSTANTIATE_TEST_CASE_P(PointLockManager, AnyLockManagerTest,
162 ::testing::Values(nullptr));
163
20effc67
TL
164} // namespace ROCKSDB_NAMESPACE
165
166int main(int argc, char** argv) {
167 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
168 ::testing::InitGoogleTest(&argc, argv);
169 return RUN_ALL_TESTS();
170}
171
172#else
173#include <stdio.h>
174
175int main(int /*argc*/, char** /*argv*/) {
176 fprintf(stderr,
177 "SKIPPED because Transactions are not supported in ROCKSDB_LITE\n");
178 return 0;
179}
180
181#endif // ROCKSDB_LITE