]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
7c673cae FG |
3 | |
4 | #include "rgw_cache.h" | |
11fdf7f2 | 5 | #include "rgw_perf_counters.h" |
7c673cae FG |
6 | |
7 | #include <errno.h> | |
8 | ||
9 | #define dout_subsys ceph_subsys_rgw | |
10 | ||
20effc67 | 11 | using namespace std; |
7c673cae | 12 | |
b3b6e05e | 13 | int ObjectCache::get(const DoutPrefixProvider *dpp, const string& name, ObjectCacheInfo& info, uint32_t mask, rgw_cache_entry_info *cache_info) |
7c673cae | 14 | { |
7c673cae | 15 | |
9f95a23c | 16 | std::shared_lock rl{lock}; |
20effc67 | 17 | std::unique_lock wl{lock, std::defer_lock}; // may be promoted to write lock |
7c673cae FG |
18 | if (!enabled) { |
19 | return -ENOENT; | |
20 | } | |
b32b8144 | 21 | auto iter = cache_map.find(name); |
1adf2230 | 22 | if (iter == cache_map.end()) { |
b3b6e05e | 23 | ldpp_dout(dpp, 10) << "cache get: name=" << name << " : miss" << dendl; |
9f95a23c | 24 | if (perfcounter) { |
b32b8144 | 25 | perfcounter->inc(l_rgw_cache_miss); |
9f95a23c | 26 | } |
7c673cae FG |
27 | return -ENOENT; |
28 | } | |
9f95a23c | 29 | |
1adf2230 AA |
30 | if (expiry.count() && |
31 | (ceph::coarse_mono_clock::now() - iter->second.info.time_added) > expiry) { | |
b3b6e05e | 32 | ldpp_dout(dpp, 10) << "cache get: name=" << name << " : expiry miss" << dendl; |
9f95a23c | 33 | rl.unlock(); |
20effc67 | 34 | wl.lock(); // write lock for expiration |
1adf2230 AA |
35 | // check that wasn't already removed by other thread |
36 | iter = cache_map.find(name); | |
37 | if (iter != cache_map.end()) { | |
38 | for (auto &kv : iter->second.chained_entries) | |
39 | kv.first->invalidate(kv.second); | |
40 | remove_lru(name, iter->second.lru_iter); | |
41 | cache_map.erase(iter); | |
42 | } | |
9f95a23c | 43 | if (perfcounter) { |
1adf2230 | 44 | perfcounter->inc(l_rgw_cache_miss); |
9f95a23c | 45 | } |
1adf2230 AA |
46 | return -ENOENT; |
47 | } | |
7c673cae FG |
48 | |
49 | ObjectCacheEntry *entry = &iter->second; | |
50 | ||
51 | if (lru_counter - entry->lru_promotion_ts > lru_window) { | |
b3b6e05e | 52 | ldpp_dout(dpp, 20) << "cache get: touching lru, lru_counter=" << lru_counter |
7c673cae | 53 | << " promotion_ts=" << entry->lru_promotion_ts << dendl; |
9f95a23c | 54 | rl.unlock(); |
20effc67 | 55 | wl.lock(); // write lock for touch_lru() |
7c673cae FG |
56 | /* need to redo this because entry might have dropped off the cache */ |
57 | iter = cache_map.find(name); | |
58 | if (iter == cache_map.end()) { | |
b3b6e05e | 59 | ldpp_dout(dpp, 10) << "lost race! cache get: name=" << name << " : miss" << dendl; |
7c673cae FG |
60 | if(perfcounter) perfcounter->inc(l_rgw_cache_miss); |
61 | return -ENOENT; | |
62 | } | |
63 | ||
64 | entry = &iter->second; | |
65 | /* check again, we might have lost a race here */ | |
66 | if (lru_counter - entry->lru_promotion_ts > lru_window) { | |
b3b6e05e | 67 | touch_lru(dpp, name, *entry, iter->second.lru_iter); |
7c673cae FG |
68 | } |
69 | } | |
70 | ||
71 | ObjectCacheInfo& src = iter->second.info; | |
f6b5b4d7 | 72 | if(src.status == -ENOENT) { |
b3b6e05e | 73 | ldpp_dout(dpp, 10) << "cache get: name=" << name << " : hit (negative entry)" << dendl; |
f6b5b4d7 TL |
74 | if (perfcounter) perfcounter->inc(l_rgw_cache_hit); |
75 | return -ENODATA; | |
76 | } | |
7c673cae | 77 | if ((src.flags & mask) != mask) { |
b3b6e05e | 78 | ldpp_dout(dpp, 10) << "cache get: name=" << name << " : type miss (requested=0x" |
7c673cae FG |
79 | << std::hex << mask << ", cached=0x" << src.flags |
80 | << std::dec << ")" << dendl; | |
81 | if(perfcounter) perfcounter->inc(l_rgw_cache_miss); | |
82 | return -ENOENT; | |
83 | } | |
b3b6e05e | 84 | ldpp_dout(dpp, 10) << "cache get: name=" << name << " : hit (requested=0x" |
7c673cae FG |
85 | << std::hex << mask << ", cached=0x" << src.flags |
86 | << std::dec << ")" << dendl; | |
87 | ||
88 | info = src; | |
89 | if (cache_info) { | |
90 | cache_info->cache_locator = name; | |
91 | cache_info->gen = entry->gen; | |
92 | } | |
93 | if(perfcounter) perfcounter->inc(l_rgw_cache_hit); | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
b3b6e05e TL |
98 | bool ObjectCache::chain_cache_entry(const DoutPrefixProvider *dpp, |
99 | std::initializer_list<rgw_cache_entry_info*> cache_info_entries, | |
11fdf7f2 | 100 | RGWChainedCache::Entry *chained_entry) |
7c673cae | 101 | { |
9f95a23c | 102 | std::unique_lock l{lock}; |
7c673cae FG |
103 | |
104 | if (!enabled) { | |
105 | return false; | |
106 | } | |
107 | ||
11fdf7f2 TL |
108 | std::vector<ObjectCacheEntry*> entries; |
109 | entries.reserve(cache_info_entries.size()); | |
7c673cae | 110 | /* first verify that all entries are still valid */ |
11fdf7f2 | 111 | for (auto cache_info : cache_info_entries) { |
b3b6e05e | 112 | ldpp_dout(dpp, 10) << "chain_cache_entry: cache_locator=" |
11fdf7f2 TL |
113 | << cache_info->cache_locator << dendl; |
114 | auto iter = cache_map.find(cache_info->cache_locator); | |
7c673cae | 115 | if (iter == cache_map.end()) { |
b3b6e05e | 116 | ldpp_dout(dpp, 20) << "chain_cache_entry: couldn't find cache locator" << dendl; |
7c673cae FG |
117 | return false; |
118 | } | |
119 | ||
11fdf7f2 | 120 | auto entry = &iter->second; |
7c673cae FG |
121 | |
122 | if (entry->gen != cache_info->gen) { | |
b3b6e05e | 123 | ldpp_dout(dpp, 20) << "chain_cache_entry: entry.gen (" << entry->gen |
11fdf7f2 TL |
124 | << ") != cache_info.gen (" << cache_info->gen << ")" |
125 | << dendl; | |
7c673cae FG |
126 | return false; |
127 | } | |
11fdf7f2 | 128 | entries.push_back(entry); |
7c673cae FG |
129 | } |
130 | ||
131 | ||
132 | chained_entry->cache->chain_cb(chained_entry->key, chained_entry->data); | |
133 | ||
11fdf7f2 TL |
134 | for (auto entry : entries) { |
135 | entry->chained_entries.push_back(make_pair(chained_entry->cache, | |
136 | chained_entry->key)); | |
7c673cae FG |
137 | } |
138 | ||
139 | return true; | |
140 | } | |
141 | ||
b3b6e05e | 142 | void ObjectCache::put(const DoutPrefixProvider *dpp, const string& name, ObjectCacheInfo& info, rgw_cache_entry_info *cache_info) |
7c673cae | 143 | { |
9f95a23c | 144 | std::unique_lock l{lock}; |
7c673cae FG |
145 | |
146 | if (!enabled) { | |
147 | return; | |
148 | } | |
149 | ||
b3b6e05e | 150 | ldpp_dout(dpp, 10) << "cache put: name=" << name << " info.flags=0x" |
7c673cae | 151 | << std::hex << info.flags << std::dec << dendl; |
28e407b8 | 152 | |
11fdf7f2 TL |
153 | auto [iter, inserted] = cache_map.emplace(name, ObjectCacheEntry{}); |
154 | ObjectCacheEntry& entry = iter->second; | |
28e407b8 AA |
155 | entry.info.time_added = ceph::coarse_mono_clock::now(); |
156 | if (inserted) { | |
7c673cae | 157 | entry.lru_iter = lru.end(); |
7c673cae | 158 | } |
7c673cae FG |
159 | ObjectCacheInfo& target = entry.info; |
160 | ||
b32b8144 | 161 | invalidate_lru(entry); |
7c673cae FG |
162 | |
163 | entry.chained_entries.clear(); | |
164 | entry.gen++; | |
165 | ||
b3b6e05e | 166 | touch_lru(dpp, name, entry, entry.lru_iter); |
7c673cae FG |
167 | |
168 | target.status = info.status; | |
169 | ||
170 | if (info.status < 0) { | |
171 | target.flags = 0; | |
172 | target.xattrs.clear(); | |
173 | target.data.clear(); | |
174 | return; | |
175 | } | |
176 | ||
177 | if (cache_info) { | |
178 | cache_info->cache_locator = name; | |
179 | cache_info->gen = entry.gen; | |
180 | } | |
181 | ||
f91f0fd5 TL |
182 | // put() must include the latest version if we're going to keep caching it |
183 | target.flags &= ~CACHE_FLAG_OBJV; | |
184 | ||
7c673cae FG |
185 | target.flags |= info.flags; |
186 | ||
187 | if (info.flags & CACHE_FLAG_META) | |
188 | target.meta = info.meta; | |
189 | else if (!(info.flags & CACHE_FLAG_MODIFY_XATTRS)) | |
190 | target.flags &= ~CACHE_FLAG_META; // non-meta change should reset meta | |
191 | ||
192 | if (info.flags & CACHE_FLAG_XATTRS) { | |
193 | target.xattrs = info.xattrs; | |
194 | map<string, bufferlist>::iterator iter; | |
195 | for (iter = target.xattrs.begin(); iter != target.xattrs.end(); ++iter) { | |
b3b6e05e | 196 | ldpp_dout(dpp, 10) << "updating xattr: name=" << iter->first << " bl.length()=" << iter->second.length() << dendl; |
7c673cae FG |
197 | } |
198 | } else if (info.flags & CACHE_FLAG_MODIFY_XATTRS) { | |
199 | map<string, bufferlist>::iterator iter; | |
200 | for (iter = info.rm_xattrs.begin(); iter != info.rm_xattrs.end(); ++iter) { | |
b3b6e05e | 201 | ldpp_dout(dpp, 10) << "removing xattr: name=" << iter->first << dendl; |
7c673cae FG |
202 | target.xattrs.erase(iter->first); |
203 | } | |
204 | for (iter = info.xattrs.begin(); iter != info.xattrs.end(); ++iter) { | |
b3b6e05e | 205 | ldpp_dout(dpp, 10) << "appending xattr: name=" << iter->first << " bl.length()=" << iter->second.length() << dendl; |
7c673cae FG |
206 | target.xattrs[iter->first] = iter->second; |
207 | } | |
208 | } | |
209 | ||
210 | if (info.flags & CACHE_FLAG_DATA) | |
211 | target.data = info.data; | |
212 | ||
213 | if (info.flags & CACHE_FLAG_OBJV) | |
214 | target.version = info.version; | |
215 | } | |
216 | ||
20effc67 TL |
217 | // WARNING: This function /must not/ be modified to cache a |
218 | // negative lookup. It must only invalidate. | |
219 | bool ObjectCache::invalidate_remove(const DoutPrefixProvider *dpp, const string& name) | |
7c673cae | 220 | { |
9f95a23c | 221 | std::unique_lock l{lock}; |
7c673cae FG |
222 | |
223 | if (!enabled) { | |
3a9019d9 | 224 | return false; |
7c673cae FG |
225 | } |
226 | ||
11fdf7f2 | 227 | auto iter = cache_map.find(name); |
7c673cae | 228 | if (iter == cache_map.end()) |
3a9019d9 | 229 | return false; |
7c673cae | 230 | |
b3b6e05e | 231 | ldpp_dout(dpp, 10) << "removing " << name << " from cache" << dendl; |
7c673cae FG |
232 | ObjectCacheEntry& entry = iter->second; |
233 | ||
11fdf7f2 TL |
234 | for (auto& kv : entry.chained_entries) { |
235 | kv.first->invalidate(kv.second); | |
7c673cae FG |
236 | } |
237 | ||
238 | remove_lru(name, iter->second.lru_iter); | |
239 | cache_map.erase(iter); | |
3a9019d9 | 240 | return true; |
7c673cae FG |
241 | } |
242 | ||
b3b6e05e | 243 | void ObjectCache::touch_lru(const DoutPrefixProvider *dpp, const string& name, ObjectCacheEntry& entry, |
3a9019d9 | 244 | std::list<string>::iterator& lru_iter) |
7c673cae FG |
245 | { |
246 | while (lru_size > (size_t)cct->_conf->rgw_cache_lru_size) { | |
11fdf7f2 | 247 | auto iter = lru.begin(); |
7c673cae FG |
248 | if ((*iter).compare(name) == 0) { |
249 | /* | |
250 | * if the entry we're touching happens to be at the lru end, don't remove it, | |
251 | * lru shrinking can wait for next time | |
252 | */ | |
253 | break; | |
254 | } | |
11fdf7f2 | 255 | auto map_iter = cache_map.find(*iter); |
7c673cae | 256 | ldout(cct, 10) << "removing entry: name=" << *iter << " from cache LRU" << dendl; |
b32b8144 FG |
257 | if (map_iter != cache_map.end()) { |
258 | ObjectCacheEntry& entry = map_iter->second; | |
259 | invalidate_lru(entry); | |
7c673cae | 260 | cache_map.erase(map_iter); |
b32b8144 | 261 | } |
7c673cae FG |
262 | lru.pop_front(); |
263 | lru_size--; | |
264 | } | |
265 | ||
266 | if (lru_iter == lru.end()) { | |
267 | lru.push_back(name); | |
268 | lru_size++; | |
269 | lru_iter--; | |
b3b6e05e | 270 | ldpp_dout(dpp, 10) << "adding " << name << " to cache LRU end" << dendl; |
7c673cae | 271 | } else { |
b3b6e05e | 272 | ldpp_dout(dpp, 10) << "moving " << name << " to cache LRU end" << dendl; |
7c673cae FG |
273 | lru.erase(lru_iter); |
274 | lru.push_back(name); | |
275 | lru_iter = lru.end(); | |
276 | --lru_iter; | |
277 | } | |
278 | ||
279 | lru_counter++; | |
280 | entry.lru_promotion_ts = lru_counter; | |
281 | } | |
282 | ||
3a9019d9 FG |
283 | void ObjectCache::remove_lru(const string& name, |
284 | std::list<string>::iterator& lru_iter) | |
7c673cae FG |
285 | { |
286 | if (lru_iter == lru.end()) | |
287 | return; | |
288 | ||
289 | lru.erase(lru_iter); | |
290 | lru_size--; | |
291 | lru_iter = lru.end(); | |
292 | } | |
293 | ||
b32b8144 FG |
294 | void ObjectCache::invalidate_lru(ObjectCacheEntry& entry) |
295 | { | |
11fdf7f2 | 296 | for (auto iter = entry.chained_entries.begin(); |
b32b8144 FG |
297 | iter != entry.chained_entries.end(); ++iter) { |
298 | RGWChainedCache *chained_cache = iter->first; | |
299 | chained_cache->invalidate(iter->second); | |
300 | } | |
301 | } | |
302 | ||
7c673cae FG |
303 | void ObjectCache::set_enabled(bool status) |
304 | { | |
9f95a23c | 305 | std::unique_lock l{lock}; |
7c673cae FG |
306 | |
307 | enabled = status; | |
308 | ||
309 | if (!enabled) { | |
310 | do_invalidate_all(); | |
311 | } | |
312 | } | |
313 | ||
314 | void ObjectCache::invalidate_all() | |
315 | { | |
9f95a23c | 316 | std::unique_lock l{lock}; |
7c673cae FG |
317 | |
318 | do_invalidate_all(); | |
319 | } | |
320 | ||
321 | void ObjectCache::do_invalidate_all() | |
322 | { | |
323 | cache_map.clear(); | |
324 | lru.clear(); | |
325 | ||
326 | lru_size = 0; | |
327 | lru_counter = 0; | |
328 | lru_window = 0; | |
329 | ||
11fdf7f2 TL |
330 | for (auto& cache : chained_cache) { |
331 | cache->invalidate_all(); | |
7c673cae FG |
332 | } |
333 | } | |
334 | ||
335 | void ObjectCache::chain_cache(RGWChainedCache *cache) { | |
9f95a23c | 336 | std::unique_lock l{lock}; |
7c673cae FG |
337 | chained_cache.push_back(cache); |
338 | } | |
339 | ||
11fdf7f2 | 340 | void ObjectCache::unchain_cache(RGWChainedCache *cache) { |
9f95a23c | 341 | std::unique_lock l{lock}; |
11fdf7f2 TL |
342 | |
343 | auto iter = chained_cache.begin(); | |
344 | for (; iter != chained_cache.end(); ++iter) { | |
345 | if (cache == *iter) { | |
346 | chained_cache.erase(iter); | |
347 | cache->unregistered(); | |
348 | return; | |
349 | } | |
350 | } | |
351 | } | |
352 | ||
353 | ObjectCache::~ObjectCache() | |
354 | { | |
355 | for (auto cache : chained_cache) { | |
356 | cache->unregistered(); | |
357 | } | |
358 | } | |
359 | ||
20effc67 TL |
360 | void ObjectMetaInfo::generate_test_instances(list<ObjectMetaInfo*>& o) |
361 | { | |
362 | ObjectMetaInfo *m = new ObjectMetaInfo; | |
363 | m->size = 1024 * 1024; | |
364 | o.push_back(m); | |
365 | o.push_back(new ObjectMetaInfo); | |
366 | } | |
367 | ||
368 | void ObjectMetaInfo::dump(Formatter *f) const | |
369 | { | |
370 | encode_json("size", size, f); | |
371 | encode_json("mtime", utime_t(mtime), f); | |
372 | } | |
373 | ||
374 | void ObjectCacheInfo::generate_test_instances(list<ObjectCacheInfo*>& o) | |
375 | { | |
376 | using ceph::encode; | |
377 | ObjectCacheInfo *i = new ObjectCacheInfo; | |
378 | i->status = 0; | |
379 | i->flags = CACHE_FLAG_MODIFY_XATTRS; | |
380 | string s = "this is a string"; | |
381 | string s2 = "this is a another string"; | |
382 | bufferlist data, data2; | |
383 | encode(s, data); | |
384 | encode(s2, data2); | |
385 | i->data = data; | |
386 | i->xattrs["x1"] = data; | |
387 | i->xattrs["x2"] = data2; | |
388 | i->rm_xattrs["r2"] = data2; | |
389 | i->rm_xattrs["r3"] = data; | |
390 | i->meta.size = 512 * 1024; | |
391 | o.push_back(i); | |
392 | o.push_back(new ObjectCacheInfo); | |
393 | } | |
394 | ||
395 | void ObjectCacheInfo::dump(Formatter *f) const | |
396 | { | |
397 | encode_json("status", status, f); | |
398 | encode_json("flags", flags, f); | |
399 | encode_json("data", data, f); | |
400 | encode_json_map("xattrs", "name", "value", "length", xattrs, f); | |
401 | encode_json_map("rm_xattrs", "name", "value", "length", rm_xattrs, f); | |
402 | encode_json("meta", meta, f); | |
403 | ||
404 | } | |
405 | ||
406 | void RGWCacheNotifyInfo::generate_test_instances(list<RGWCacheNotifyInfo*>& o) | |
407 | { | |
408 | o.push_back(new RGWCacheNotifyInfo); | |
409 | } | |
410 | ||
411 | void RGWCacheNotifyInfo::dump(Formatter *f) const | |
412 | { | |
413 | encode_json("op", op, f); | |
414 | encode_json("obj", obj, f); | |
415 | encode_json("obj_info", obj_info, f); | |
416 | encode_json("ofs", ofs, f); | |
417 | encode_json("ns", ns, f); | |
418 | } | |
419 |