point_lock_manager.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. #pragma once
  6. #include <memory>
  7. #include <string>
  8. #include <unordered_map>
  9. #include <utility>
  10. #include <vector>
  11. #include "monitoring/instrumented_mutex.h"
  12. #include "rocksdb/utilities/transaction.h"
  13. #include "util/autovector.h"
  14. #include "util/hash_containers.h"
  15. #include "util/hash_map.h"
  16. #include "util/thread_local.h"
  17. #include "utilities/transactions/lock/lock_manager.h"
  18. #include "utilities/transactions/lock/point/point_lock_tracker.h"
  19. namespace ROCKSDB_NAMESPACE {
  20. class ColumnFamilyHandle;
  21. struct LockInfo;
  22. struct LockMap;
  23. struct LockMapStripe;
  24. template <class Path>
  25. class DeadlockInfoBufferTempl {
  26. private:
  27. std::vector<Path> paths_buffer_;
  28. uint32_t buffer_idx_;
  29. std::mutex paths_buffer_mutex_;
  30. std::vector<Path> Normalize() {
  31. auto working = paths_buffer_;
  32. if (working.empty()) {
  33. return working;
  34. }
  35. // Next write occurs at a nonexistent path's slot
  36. if (paths_buffer_[buffer_idx_].empty()) {
  37. working.resize(buffer_idx_);
  38. } else {
  39. std::rotate(working.begin(), working.begin() + buffer_idx_,
  40. working.end());
  41. }
  42. return working;
  43. }
  44. public:
  45. explicit DeadlockInfoBufferTempl(uint32_t n_latest_dlocks)
  46. : paths_buffer_(n_latest_dlocks), buffer_idx_(0) {}
  47. void AddNewPath(Path path) {
  48. std::lock_guard<std::mutex> lock(paths_buffer_mutex_);
  49. if (paths_buffer_.empty()) {
  50. return;
  51. }
  52. paths_buffer_[buffer_idx_] = std::move(path);
  53. buffer_idx_ = (buffer_idx_ + 1) % paths_buffer_.size();
  54. }
  55. void Resize(uint32_t target_size) {
  56. std::lock_guard<std::mutex> lock(paths_buffer_mutex_);
  57. paths_buffer_ = Normalize();
  58. // Drop the deadlocks that will no longer be needed ater the normalize
  59. if (target_size < paths_buffer_.size()) {
  60. paths_buffer_.erase(
  61. paths_buffer_.begin(),
  62. paths_buffer_.begin() + (paths_buffer_.size() - target_size));
  63. buffer_idx_ = 0;
  64. }
  65. // Resize the buffer to the target size and restore the buffer's idx
  66. else {
  67. auto prev_size = paths_buffer_.size();
  68. paths_buffer_.resize(target_size);
  69. buffer_idx_ = (uint32_t)prev_size;
  70. }
  71. }
  72. std::vector<Path> PrepareBuffer() {
  73. std::lock_guard<std::mutex> lock(paths_buffer_mutex_);
  74. // Reversing the normalized vector returns the latest deadlocks first
  75. auto working = Normalize();
  76. std::reverse(working.begin(), working.end());
  77. return working;
  78. }
  79. };
  80. using DeadlockInfoBuffer = DeadlockInfoBufferTempl<DeadlockPath>;
  81. struct TrackedTrxInfo {
  82. autovector<TransactionID> m_neighbors;
  83. uint32_t m_cf_id;
  84. bool m_exclusive;
  85. std::string m_waiting_key;
  86. };
  87. class PointLockManager : public LockManager {
  88. public:
  89. PointLockManager(PessimisticTransactionDB* db,
  90. const TransactionDBOptions& opt);
  91. // No copying allowed
  92. PointLockManager(const PointLockManager&) = delete;
  93. PointLockManager& operator=(const PointLockManager&) = delete;
  94. ~PointLockManager() override {}
  95. bool IsPointLockSupported() const override { return true; }
  96. bool IsRangeLockSupported() const override { return false; }
  97. const LockTrackerFactory& GetLockTrackerFactory() const override {
  98. return PointLockTrackerFactory::Get();
  99. }
  100. // Creates a new LockMap for this column family. Caller should guarantee
  101. // that this column family does not already exist.
  102. void AddColumnFamily(const ColumnFamilyHandle* cf) override;
  103. // Deletes the LockMap for this column family. Caller should guarantee that
  104. // this column family is no longer in use.
  105. void RemoveColumnFamily(const ColumnFamilyHandle* cf) override;
  106. // Caller makes sure that a lock on the key is not requested again, unless it
  107. // is an upgrade or downgrade.
  108. Status TryLock(PessimisticTransaction* txn, ColumnFamilyId column_family_id,
  109. const std::string& key, Env* env, bool exclusive) override;
  110. // Caller makes sure that a lock on the key is not requested again, unless it
  111. // is an upgrade or downgrade.
  112. Status TryLock(PessimisticTransaction* txn, ColumnFamilyId column_family_id,
  113. const Endpoint& start, const Endpoint& end, Env* env,
  114. bool exclusive) override;
  115. void UnLock(PessimisticTransaction* txn, const LockTracker& tracker,
  116. Env* env) override;
  117. void UnLock(PessimisticTransaction* txn, ColumnFamilyId column_family_id,
  118. const std::string& key, Env* env) override;
  119. void UnLock(PessimisticTransaction* txn, ColumnFamilyId column_family_id,
  120. const Endpoint& start, const Endpoint& end, Env* env) override;
  121. PointLockStatus GetPointLockStatus() override;
  122. RangeLockStatus GetRangeLockStatus() override;
  123. std::vector<DeadlockPath> GetDeadlockInfoBuffer() override;
  124. void Resize(uint32_t new_size) override;
  125. protected:
  126. PessimisticTransactionDB* txn_db_impl_;
  127. // Default number of lock map stripes per column family
  128. const size_t default_num_stripes_;
  129. // Limit on number of keys locked per column family
  130. const int64_t max_num_locks_;
  131. // The following lock order must be satisfied in order to avoid deadlocking
  132. // ourselves.
  133. // - lock_map_mutex_
  134. // - stripe mutexes in ascending cf id, ascending stripe order
  135. // - wait_txn_map_mutex_
  136. //
  137. // Must be held when accessing/modifying lock_maps_.
  138. InstrumentedMutex lock_map_mutex_;
  139. // Map of ColumnFamilyId to locked key info
  140. using LockMaps = UnorderedMap<uint32_t, std::shared_ptr<LockMap>>;
  141. LockMaps lock_maps_;
  142. // Thread-local cache of entries in lock_maps_. This is an optimization
  143. // to avoid acquiring a mutex in order to look up a LockMap
  144. std::unique_ptr<ThreadLocalPtr> lock_maps_cache_;
  145. // Thread local variable for KeyLockWaiter. As one thread could only need one
  146. // KeyLockWaiter.
  147. // Lazy init on first time usage
  148. ThreadLocalPtr key_lock_waiter_;
  149. // Must be held when modifying wait_txn_map_ and rev_wait_txn_map_.
  150. std::mutex wait_txn_map_mutex_;
  151. // Maps from waitee -> number of waiters.
  152. HashMap<TransactionID, int> rev_wait_txn_map_;
  153. // Maps from waiter -> waitee.
  154. HashMap<TransactionID, TrackedTrxInfo> wait_txn_map_;
  155. DeadlockInfoBuffer dlock_buffer_;
  156. // Used to allocate mutexes/condvars to use when locking keys
  157. std::shared_ptr<TransactionDBMutexFactory> mutex_factory_;
  158. bool IsLockExpired(TransactionID txn_id, const LockInfo& lock_info, Env* env,
  159. uint64_t* wait_time);
  160. std::shared_ptr<LockMap> GetLockMap(uint32_t column_family_id);
  161. virtual Status AcquireWithTimeout(
  162. PessimisticTransaction* txn, LockMap* lock_map, LockMapStripe* stripe,
  163. uint32_t column_family_id, const std::string& key, Env* env,
  164. int64_t timeout, int64_t deadlock_timeout_us, const LockInfo& lock_info);
  165. virtual void UnLockKey(PessimisticTransaction* txn, const std::string& key,
  166. LockMapStripe* stripe, LockMap* lock_map, Env* env);
  167. // Returns true if a deadlock is detected.
  168. // Will DecrementWaiters() if a deadlock is detected.
  169. bool IncrementWaiters(const PessimisticTransaction* txn,
  170. const autovector<TransactionID>& wait_ids,
  171. const std::string& key, const uint32_t& cf_id,
  172. const bool& exclusive, Env* const env);
  173. void DecrementWaiters(const PessimisticTransaction* txn,
  174. const autovector<TransactionID>& wait_ids);
  175. void DecrementWaitersImpl(const PessimisticTransaction* txn,
  176. const autovector<TransactionID>& wait_ids);
  177. private:
  178. Status AcquireLocked(LockMap* lock_map, LockMapStripe* stripe,
  179. const std::string& key, Env* env,
  180. const LockInfo& lock_info, uint64_t* wait_time,
  181. autovector<TransactionID>* txn_ids);
  182. };
  183. class PerKeyPointLockManager : public PointLockManager {
  184. public:
  185. PerKeyPointLockManager(PessimisticTransactionDB* db,
  186. const TransactionDBOptions& opt);
  187. // No copying allowed
  188. PerKeyPointLockManager(const PerKeyPointLockManager&) = delete;
  189. PerKeyPointLockManager& operator=(const PerKeyPointLockManager&) = delete;
  190. // No move allowed
  191. PerKeyPointLockManager(PerKeyPointLockManager&&) = delete;
  192. PerKeyPointLockManager& operator=(PerKeyPointLockManager&&) = delete;
  193. ~PerKeyPointLockManager() override {}
  194. void UnLock(PessimisticTransaction* txn, const LockTracker& tracker,
  195. Env* env) override;
  196. void UnLock(PessimisticTransaction* txn, ColumnFamilyId column_family_id,
  197. const std::string& key, Env* env) override;
  198. void UnLock(PessimisticTransaction* txn, ColumnFamilyId column_family_id,
  199. const Endpoint& start, const Endpoint& end, Env* env) override;
  200. void UnLockKey(PessimisticTransaction* txn, const std::string& key,
  201. LockMapStripe* stripe, LockMap* lock_map, Env* env) override;
  202. protected:
  203. Status AcquireWithTimeout(PessimisticTransaction* txn, LockMap* lock_map,
  204. LockMapStripe* stripe, uint32_t column_family_id,
  205. const std::string& key, Env* env, int64_t timeout,
  206. int64_t deadlock_timeout_us,
  207. const LockInfo& lock_info) override;
  208. private:
  209. Status AcquireLocked(LockMap* lock_map, LockMapStripe* stripe,
  210. const std::string& key, Env* env,
  211. const LockInfo& txn_lock_info, uint64_t* wait_time,
  212. autovector<TransactionID>* txn_ids,
  213. LockInfo** lock_info_ptr, bool* isUpgrade, bool fifo);
  214. int64_t CalculateWaitEndTime(int64_t expire_time_hint, int64_t end_time);
  215. Status FillWaitIds(LockInfo& lock_info, const LockInfo& txn_lock_info,
  216. autovector<TransactionID>* wait_ids, bool& isUpgrade,
  217. TransactionID& my_txn_id, const std::string& key);
  218. };
  219. } // namespace ROCKSDB_NAMESPACE