point_lock_tracker.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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. #include "utilities/transactions/lock/point/point_lock_tracker.h"
  6. namespace ROCKSDB_NAMESPACE {
  7. namespace {
  8. class TrackedKeysColumnFamilyIterator
  9. : public LockTracker::ColumnFamilyIterator {
  10. public:
  11. explicit TrackedKeysColumnFamilyIterator(const TrackedKeys& keys)
  12. : tracked_keys_(keys), it_(keys.begin()) {}
  13. bool HasNext() const override { return it_ != tracked_keys_.end(); }
  14. ColumnFamilyId Next() override { return (it_++)->first; }
  15. private:
  16. const TrackedKeys& tracked_keys_;
  17. TrackedKeys::const_iterator it_;
  18. };
  19. class TrackedKeysIterator : public LockTracker::KeyIterator {
  20. public:
  21. TrackedKeysIterator(const TrackedKeys& keys, ColumnFamilyId id)
  22. : key_infos_(keys.at(id)), it_(key_infos_.begin()) {}
  23. bool HasNext() const override { return it_ != key_infos_.end(); }
  24. const std::string& Next() override { return (it_++)->first; }
  25. private:
  26. const TrackedKeyInfos& key_infos_;
  27. TrackedKeyInfos::const_iterator it_;
  28. };
  29. } // namespace
  30. void PointLockTracker::Track(const PointLockRequest& r) {
  31. auto& keys = tracked_keys_[r.column_family_id];
  32. auto result = keys.try_emplace(r.key, r.seq);
  33. auto it = result.first;
  34. if (!result.second && r.seq < it->second.seq) {
  35. // Now tracking this key with an earlier sequence number
  36. it->second.seq = r.seq;
  37. }
  38. // else we do not update the seq. The smaller the tracked seq, the stronger it
  39. // the guarantee since it implies from the seq onward there has not been a
  40. // concurrent update to the key. So we update the seq if it implies stronger
  41. // guarantees, i.e., if it is smaller than the existing tracked seq.
  42. if (r.read_only) {
  43. it->second.num_reads++;
  44. } else {
  45. it->second.num_writes++;
  46. }
  47. it->second.exclusive = it->second.exclusive || r.exclusive;
  48. }
  49. UntrackStatus PointLockTracker::Untrack(const PointLockRequest& r) {
  50. auto cf_keys = tracked_keys_.find(r.column_family_id);
  51. if (cf_keys == tracked_keys_.end()) {
  52. return UntrackStatus::NOT_TRACKED;
  53. }
  54. auto& keys = cf_keys->second;
  55. auto it = keys.find(r.key);
  56. if (it == keys.end()) {
  57. return UntrackStatus::NOT_TRACKED;
  58. }
  59. bool untracked = false;
  60. auto& info = it->second;
  61. if (r.read_only) {
  62. if (info.num_reads > 0) {
  63. info.num_reads--;
  64. untracked = true;
  65. }
  66. } else {
  67. if (info.num_writes > 0) {
  68. info.num_writes--;
  69. untracked = true;
  70. }
  71. }
  72. bool removed = false;
  73. if (info.num_reads == 0 && info.num_writes == 0) {
  74. keys.erase(it);
  75. if (keys.empty()) {
  76. tracked_keys_.erase(cf_keys);
  77. }
  78. removed = true;
  79. }
  80. if (removed) {
  81. return UntrackStatus::REMOVED;
  82. }
  83. if (untracked) {
  84. return UntrackStatus::UNTRACKED;
  85. }
  86. return UntrackStatus::NOT_TRACKED;
  87. }
  88. void PointLockTracker::Merge(const LockTracker& tracker) {
  89. const PointLockTracker& t = static_cast<const PointLockTracker&>(tracker);
  90. for (const auto& cf_keys : t.tracked_keys_) {
  91. ColumnFamilyId cf = cf_keys.first;
  92. const auto& keys = cf_keys.second;
  93. auto current_cf_keys = tracked_keys_.find(cf);
  94. if (current_cf_keys == tracked_keys_.end()) {
  95. tracked_keys_.emplace(cf_keys);
  96. } else {
  97. auto& current_keys = current_cf_keys->second;
  98. for (const auto& key_info : keys) {
  99. const std::string& key = key_info.first;
  100. const TrackedKeyInfo& info = key_info.second;
  101. // If key was not previously tracked, just copy the whole struct over.
  102. // Otherwise, some merging needs to occur.
  103. auto current_info = current_keys.find(key);
  104. if (current_info == current_keys.end()) {
  105. current_keys.emplace(key_info);
  106. } else {
  107. current_info->second.Merge(info);
  108. }
  109. }
  110. }
  111. }
  112. }
  113. void PointLockTracker::Subtract(const LockTracker& tracker) {
  114. const PointLockTracker& t = static_cast<const PointLockTracker&>(tracker);
  115. for (const auto& cf_keys : t.tracked_keys_) {
  116. ColumnFamilyId cf = cf_keys.first;
  117. const auto& keys = cf_keys.second;
  118. auto& current_keys = tracked_keys_.at(cf);
  119. for (const auto& key_info : keys) {
  120. const std::string& key = key_info.first;
  121. const TrackedKeyInfo& info = key_info.second;
  122. uint32_t num_reads = info.num_reads;
  123. uint32_t num_writes = info.num_writes;
  124. auto current_key_info = current_keys.find(key);
  125. assert(current_key_info != current_keys.end());
  126. // Decrement the total reads/writes of this key by the number of
  127. // reads/writes done since the last SavePoint.
  128. if (num_reads > 0) {
  129. assert(current_key_info->second.num_reads >= num_reads);
  130. current_key_info->second.num_reads -= num_reads;
  131. }
  132. if (num_writes > 0) {
  133. assert(current_key_info->second.num_writes >= num_writes);
  134. current_key_info->second.num_writes -= num_writes;
  135. }
  136. if (current_key_info->second.num_reads == 0 &&
  137. current_key_info->second.num_writes == 0) {
  138. current_keys.erase(current_key_info);
  139. }
  140. }
  141. }
  142. }
  143. LockTracker* PointLockTracker::GetTrackedLocksSinceSavePoint(
  144. const LockTracker& save_point_tracker) const {
  145. // Examine the number of reads/writes performed on all keys written
  146. // since the last SavePoint and compare to the total number of reads/writes
  147. // for each key.
  148. LockTracker* t = new PointLockTracker();
  149. const PointLockTracker& save_point_t =
  150. static_cast<const PointLockTracker&>(save_point_tracker);
  151. for (const auto& cf_keys : save_point_t.tracked_keys_) {
  152. ColumnFamilyId cf = cf_keys.first;
  153. const auto& keys = cf_keys.second;
  154. auto& current_keys = tracked_keys_.at(cf);
  155. for (const auto& key_info : keys) {
  156. const std::string& key = key_info.first;
  157. const TrackedKeyInfo& info = key_info.second;
  158. uint32_t num_reads = info.num_reads;
  159. uint32_t num_writes = info.num_writes;
  160. auto current_key_info = current_keys.find(key);
  161. assert(current_key_info != current_keys.end());
  162. assert(current_key_info->second.num_reads >= num_reads);
  163. assert(current_key_info->second.num_writes >= num_writes);
  164. if (current_key_info->second.num_reads == num_reads &&
  165. current_key_info->second.num_writes == num_writes) {
  166. // All the reads/writes to this key were done in the last savepoint.
  167. PointLockRequest r;
  168. r.column_family_id = cf;
  169. r.key = key;
  170. r.seq = info.seq;
  171. r.read_only = (num_writes == 0);
  172. r.exclusive = info.exclusive;
  173. t->Track(r);
  174. }
  175. }
  176. }
  177. return t;
  178. }
  179. PointLockStatus PointLockTracker::GetPointLockStatus(
  180. ColumnFamilyId column_family_id, const std::string& key) const {
  181. assert(IsPointLockSupported());
  182. PointLockStatus status;
  183. auto it = tracked_keys_.find(column_family_id);
  184. if (it == tracked_keys_.end()) {
  185. return status;
  186. }
  187. const auto& keys = it->second;
  188. auto key_it = keys.find(key);
  189. if (key_it == keys.end()) {
  190. return status;
  191. }
  192. const TrackedKeyInfo& key_info = key_it->second;
  193. status.locked = true;
  194. status.exclusive = key_info.exclusive;
  195. status.seq = key_info.seq;
  196. return status;
  197. }
  198. uint64_t PointLockTracker::GetNumPointLocks() const {
  199. uint64_t num_keys = 0;
  200. for (const auto& cf_keys : tracked_keys_) {
  201. num_keys += cf_keys.second.size();
  202. }
  203. return num_keys;
  204. }
  205. LockTracker::ColumnFamilyIterator* PointLockTracker::GetColumnFamilyIterator()
  206. const {
  207. return new TrackedKeysColumnFamilyIterator(tracked_keys_);
  208. }
  209. LockTracker::KeyIterator* PointLockTracker::GetKeyIterator(
  210. ColumnFamilyId column_family_id) const {
  211. assert(tracked_keys_.find(column_family_id) != tracked_keys_.end());
  212. return new TrackedKeysIterator(tracked_keys_, column_family_id);
  213. }
  214. void PointLockTracker::Clear() { tracked_keys_.clear(); }
  215. } // namespace ROCKSDB_NAMESPACE