1 // Copyright (c) 2011-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 #pragma once
7 
8 #include <memory>
9 #include <string>
10 #include <unordered_map>
11 
12 #include "util/mutexlock.h"
13 #include "utilities/transactions/lock/lock_tracker.h"
14 #include "utilities/transactions/pessimistic_transaction.h"
15 
16 // Range Locking:
17 #include "lib/locktree/lock_request.h"
18 #include "lib/locktree/locktree.h"
19 
20 namespace ROCKSDB_NAMESPACE {
21 
22 class RangeTreeLockManager;
23 
24 // Storage for locks that are currently held by a transaction.
25 //
26 // Locks are kept in toku::range_buffer because toku::locktree::release_locks()
27 // accepts that as an argument.
28 //
29 // Note: the list of locks may differ slighly from the contents of the lock
30 // tree, due to concurrency between lock acquisition, lock release, and lock
31 // escalation. See MDEV-18227 and RangeTreeLockManager::UnLock for details.
32 // This property is currently harmless.
33 //
34 // Append() and ReleaseLocks() are not thread-safe, as they are expected to be
35 // called only by the owner transaction. ReplaceLocks() is safe to call from
36 // other threads.
37 class RangeLockList {
38  public:
~RangeLockList()39   ~RangeLockList() { Clear(); }
40 
RangeLockList()41   RangeLockList() : releasing_locks_(false) {}
42 
43   void Append(ColumnFamilyId cf_id, const DBT* left_key, const DBT* right_key);
44   void ReleaseLocks(RangeTreeLockManager* mgr, PessimisticTransaction* txn,
45                     bool all_trx_locks);
46   void ReplaceLocks(const toku::locktree* lt, const toku::range_buffer& buffer);
47 
48  private:
Clear()49   void Clear() {
50     for (auto it : buffers_) {
51       it.second->destroy();
52     }
53     buffers_.clear();
54   }
55 
56   std::unordered_map<ColumnFamilyId, std::shared_ptr<toku::range_buffer>>
57       buffers_;
58   port::Mutex mutex_;
59   std::atomic<bool> releasing_locks_;
60 };
61 
62 // A LockTracker-based object that is used together with RangeTreeLockManager.
63 class RangeTreeLockTracker : public LockTracker {
64  public:
RangeTreeLockTracker()65   RangeTreeLockTracker() : range_list_(nullptr) {}
66 
67   RangeTreeLockTracker(const RangeTreeLockTracker&) = delete;
68   RangeTreeLockTracker& operator=(const RangeTreeLockTracker&) = delete;
69 
70   void Track(const PointLockRequest&) override;
71   void Track(const RangeLockRequest&) override;
72 
IsPointLockSupported()73   bool IsPointLockSupported() const override {
74     // This indicates that we don't implement GetPointLockStatus()
75     return false;
76   }
IsRangeLockSupported()77   bool IsRangeLockSupported() const override { return true; }
78 
79   // a Not-supported dummy implementation.
Untrack(const RangeLockRequest &)80   UntrackStatus Untrack(const RangeLockRequest& /*lock_request*/) override {
81     return UntrackStatus::NOT_TRACKED;
82   }
83 
Untrack(const PointLockRequest &)84   UntrackStatus Untrack(const PointLockRequest& /*lock_request*/) override {
85     return UntrackStatus::NOT_TRACKED;
86   }
87 
88   // "If this method is not supported, leave it as a no-op."
Merge(const LockTracker &)89   void Merge(const LockTracker&) override {}
90 
91   // "If this method is not supported, leave it as a no-op."
Subtract(const LockTracker &)92   void Subtract(const LockTracker&) override {}
93 
94   void Clear() override;
95 
96   // "If this method is not supported, returns nullptr."
GetTrackedLocksSinceSavePoint(const LockTracker &)97   virtual LockTracker* GetTrackedLocksSinceSavePoint(
98       const LockTracker&) const override {
99     return nullptr;
100   }
101 
102   PointLockStatus GetPointLockStatus(ColumnFamilyId column_family_id,
103                                      const std::string& key) const override;
104 
105   // The return value is only used for tests
GetNumPointLocks()106   uint64_t GetNumPointLocks() const override { return 0; }
107 
GetColumnFamilyIterator()108   ColumnFamilyIterator* GetColumnFamilyIterator() const override {
109     return nullptr;
110   }
111 
GetKeyIterator(ColumnFamilyId)112   KeyIterator* GetKeyIterator(
113       ColumnFamilyId /*column_family_id*/) const override {
114     return nullptr;
115   }
116 
ReleaseLocks(RangeTreeLockManager * mgr,PessimisticTransaction * txn,bool all_trx_locks)117   void ReleaseLocks(RangeTreeLockManager* mgr, PessimisticTransaction* txn,
118                     bool all_trx_locks) {
119     if (range_list_) range_list_->ReleaseLocks(mgr, txn, all_trx_locks);
120   }
121 
ReplaceLocks(const toku::locktree * lt,const toku::range_buffer & buffer)122   void ReplaceLocks(const toku::locktree* lt,
123                     const toku::range_buffer& buffer) {
124     // range_list_ cannot be NULL here
125     range_list_->ReplaceLocks(lt, buffer);
126   }
127 
128  private:
129   RangeLockList* getOrCreateList();
130   std::unique_ptr<RangeLockList> range_list_;
131 };
132 
133 class RangeTreeLockTrackerFactory : public LockTrackerFactory {
134  public:
Get()135   static const RangeTreeLockTrackerFactory& Get() {
136     static const RangeTreeLockTrackerFactory instance;
137     return instance;
138   }
139 
Create()140   LockTracker* Create() const override { return new RangeTreeLockTracker(); }
141 
142  private:
RangeTreeLockTrackerFactory()143   RangeTreeLockTrackerFactory() {}
144 };
145 
146 }  // namespace ROCKSDB_NAMESPACE
147