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