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