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