]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/services/svc_sys_obj_cache.cc
bump version to 15.2.6-pve1
[ceph.git] / ceph / src / rgw / services / svc_sys_obj_cache.cc
CommitLineData
9f95a23c
TL
1
2// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
3// vim: ts=8 sw=2 smarttab ft=cpp
4
5#include "common/admin_socket.h"
6
11fdf7f2
TL
7#include "svc_sys_obj_cache.h"
8#include "svc_zone.h"
9#include "svc_notify.h"
10
11#include "rgw/rgw_zone.h"
12#include "rgw/rgw_tools.h"
13
14#define dout_subsys ceph_subsys_rgw
15
16class RGWSI_SysObj_Cache_CB : public RGWSI_Notify::CB
17{
18 RGWSI_SysObj_Cache *svc;
19public:
20 RGWSI_SysObj_Cache_CB(RGWSI_SysObj_Cache *_svc) : svc(_svc) {}
21 int watch_cb(uint64_t notify_id,
22 uint64_t cookie,
23 uint64_t notifier_id,
24 bufferlist& bl) {
25 return svc->watch_cb(notify_id, cookie, notifier_id, bl);
26 }
27
28 void set_enabled(bool status) {
29 svc->set_enabled(status);
30 }
31};
32
33int RGWSI_SysObj_Cache::do_start()
34{
9f95a23c
TL
35 int r = asocket.start();
36 if (r < 0) {
37 return r;
38 }
39
40 r = RGWSI_SysObj_Core::do_start();
11fdf7f2
TL
41 if (r < 0) {
42 return r;
43 }
44
45 r = notify_svc->start();
46 if (r < 0) {
47 return r;
48 }
49
50 assert(notify_svc->is_started());
51
52 cb.reset(new RGWSI_SysObj_Cache_CB(this));
53
54 notify_svc->register_watch_cb(cb.get());
55
56 return 0;
57}
58
9f95a23c
TL
59void RGWSI_SysObj_Cache::shutdown()
60{
61 asocket.shutdown();
62 RGWSI_SysObj_Core::shutdown();
63}
64
11fdf7f2
TL
65static string normal_name(rgw_pool& pool, const std::string& oid) {
66 std::string buf;
67 buf.reserve(pool.name.size() + pool.ns.size() + oid.size() + 2);
68 buf.append(pool.name).append("+").append(pool.ns).append("+").append(oid);
69 return buf;
70}
71
72void RGWSI_SysObj_Cache::normalize_pool_and_obj(const rgw_pool& src_pool, const string& src_obj, rgw_pool& dst_pool, string& dst_obj)
73{
74 if (src_obj.size()) {
75 dst_pool = src_pool;
76 dst_obj = src_obj;
77 } else {
78 dst_pool = zone_svc->get_zone_params().domain_root;
79 dst_obj = src_pool.name;
80 }
81}
82
83
84int RGWSI_SysObj_Cache::remove(RGWSysObjectCtxBase& obj_ctx,
85 RGWObjVersionTracker *objv_tracker,
9f95a23c
TL
86 const rgw_raw_obj& obj,
87 optional_yield y)
11fdf7f2
TL
88
89{
90 rgw_pool pool;
91 string oid;
92 normalize_pool_and_obj(obj.pool, obj.oid, pool, oid);
93
94 string name = normal_name(pool, oid);
95 cache.remove(name);
96
97 ObjectCacheInfo info;
9f95a23c 98 int r = distribute_cache(name, obj, info, REMOVE_OBJ, y);
11fdf7f2
TL
99 if (r < 0) {
100 ldout(cct, 0) << "ERROR: " << __func__ << "(): failed to distribute cache: r=" << r << dendl;
101 }
102
9f95a23c 103 return RGWSI_SysObj_Core::remove(obj_ctx, objv_tracker, obj, y);
11fdf7f2
TL
104}
105
106int RGWSI_SysObj_Cache::read(RGWSysObjectCtxBase& obj_ctx,
9f95a23c 107 RGWSI_SysObj_Obj_GetObjState& read_state,
11fdf7f2
TL
108 RGWObjVersionTracker *objv_tracker,
109 const rgw_raw_obj& obj,
110 bufferlist *obl, off_t ofs, off_t end,
111 map<string, bufferlist> *attrs,
112 bool raw_attrs,
113 rgw_cache_entry_info *cache_info,
9f95a23c
TL
114 boost::optional<obj_version> refresh_version,
115 optional_yield y)
11fdf7f2
TL
116{
117 rgw_pool pool;
118 string oid;
119 if (ofs != 0) {
120 return RGWSI_SysObj_Core::read(obj_ctx, read_state, objv_tracker,
9f95a23c
TL
121 obj, obl, ofs, end, attrs, raw_attrs,
122 cache_info, refresh_version, y);
11fdf7f2
TL
123 }
124
125 normalize_pool_and_obj(obj.pool, obj.oid, pool, oid);
126 string name = normal_name(pool, oid);
127
128 ObjectCacheInfo info;
129
130 uint32_t flags = (end != 0 ? CACHE_FLAG_DATA : 0);
131 if (objv_tracker)
132 flags |= CACHE_FLAG_OBJV;
133 if (attrs)
134 flags |= CACHE_FLAG_XATTRS;
f6b5b4d7
TL
135
136 int r = cache.get(name, info, flags, cache_info);
137 if (r == 0 &&
11fdf7f2
TL
138 (!refresh_version || !info.version.compare(&(*refresh_version)))) {
139 if (info.status < 0)
140 return info.status;
141
142 bufferlist& bl = info.data;
143
144 bufferlist::iterator i = bl.begin();
145
146 obl->clear();
147
148 i.copy_all(*obl);
149 if (objv_tracker)
150 objv_tracker->read_version = info.version;
151 if (attrs) {
152 if (raw_attrs) {
153 *attrs = info.xattrs;
154 } else {
155 rgw_filter_attrset(info.xattrs, RGW_ATTR_PREFIX, attrs);
156 }
157 }
158 return obl->length();
159 }
f6b5b4d7
TL
160 if(r == -ENODATA)
161 return -ENOENT;
11fdf7f2
TL
162
163 map<string, bufferlist> unfiltered_attrset;
f6b5b4d7 164 r = RGWSI_SysObj_Core::read(obj_ctx, read_state, objv_tracker,
11fdf7f2
TL
165 obj, obl, ofs, end,
166 (attrs ? &unfiltered_attrset : nullptr),
167 true, /* cache unfiltered attrs */
168 cache_info,
9f95a23c 169 refresh_version, y);
11fdf7f2
TL
170 if (r < 0) {
171 if (r == -ENOENT) { // only update ENOENT, we'd rather retry other errors
172 info.status = r;
173 cache.put(name, info, cache_info);
174 }
175 return r;
176 }
177
178 if (obl->length() == end + 1) {
179 /* in this case, most likely object contains more data, we can't cache it */
180 flags &= ~CACHE_FLAG_DATA;
181 } else {
182 bufferptr p(r);
183 bufferlist& bl = info.data;
184 bl.clear();
185 bufferlist::iterator o = obl->begin();
186 o.copy_all(bl);
187 }
188
189 info.status = 0;
190 info.flags = flags;
191 if (objv_tracker) {
192 info.version = objv_tracker->read_version;
193 }
194 if (attrs) {
195 info.xattrs = std::move(unfiltered_attrset);
196 if (raw_attrs) {
197 *attrs = info.xattrs;
198 } else {
199 rgw_filter_attrset(info.xattrs, RGW_ATTR_PREFIX, attrs);
200 }
201 }
202 cache.put(name, info, cache_info);
203 return r;
204}
205
206int RGWSI_SysObj_Cache::get_attr(const rgw_raw_obj& obj,
9f95a23c
TL
207 const char *attr_name,
208 bufferlist *dest,
209 optional_yield y)
11fdf7f2
TL
210{
211 rgw_pool pool;
212 string oid;
213
214 normalize_pool_and_obj(obj.pool, obj.oid, pool, oid);
215 string name = normal_name(pool, oid);
216
217 ObjectCacheInfo info;
218
219 uint32_t flags = CACHE_FLAG_XATTRS;
220
f6b5b4d7
TL
221 int r = cache.get(name, info, flags, nullptr);
222 if (r == 0) {
11fdf7f2
TL
223 if (info.status < 0)
224 return info.status;
225
226 auto iter = info.xattrs.find(attr_name);
227 if (iter == info.xattrs.end()) {
228 return -ENODATA;
229 }
230
231 *dest = iter->second;
232 return dest->length();
f6b5b4d7
TL
233 } else if (r == -ENODATA) {
234 return -ENOENT;
11fdf7f2
TL
235 }
236 /* don't try to cache this one */
9f95a23c 237 return RGWSI_SysObj_Core::get_attr(obj, attr_name, dest, y);
11fdf7f2
TL
238}
239
240int RGWSI_SysObj_Cache::set_attrs(const rgw_raw_obj& obj,
241 map<string, bufferlist>& attrs,
242 map<string, bufferlist> *rmattrs,
9f95a23c
TL
243 RGWObjVersionTracker *objv_tracker,
244 optional_yield y)
11fdf7f2
TL
245{
246 rgw_pool pool;
247 string oid;
248 normalize_pool_and_obj(obj.pool, obj.oid, pool, oid);
249 ObjectCacheInfo info;
250 info.xattrs = attrs;
251 if (rmattrs) {
252 info.rm_xattrs = *rmattrs;
253 }
254 info.status = 0;
255 info.flags = CACHE_FLAG_MODIFY_XATTRS;
256 if (objv_tracker) {
257 info.version = objv_tracker->write_version;
258 info.flags |= CACHE_FLAG_OBJV;
259 }
9f95a23c 260 int ret = RGWSI_SysObj_Core::set_attrs(obj, attrs, rmattrs, objv_tracker, y);
11fdf7f2
TL
261 string name = normal_name(pool, oid);
262 if (ret >= 0) {
263 cache.put(name, info, NULL);
9f95a23c 264 int r = distribute_cache(name, obj, info, UPDATE_OBJ, y);
11fdf7f2
TL
265 if (r < 0)
266 ldout(cct, 0) << "ERROR: failed to distribute cache for " << obj << dendl;
267 } else {
268 cache.remove(name);
269 }
270
271 return ret;
272}
273
274int RGWSI_SysObj_Cache::write(const rgw_raw_obj& obj,
275 real_time *pmtime,
276 map<std::string, bufferlist>& attrs,
277 bool exclusive,
278 const bufferlist& data,
279 RGWObjVersionTracker *objv_tracker,
9f95a23c
TL
280 real_time set_mtime,
281 optional_yield y)
11fdf7f2
TL
282{
283 rgw_pool pool;
284 string oid;
285 normalize_pool_and_obj(obj.pool, obj.oid, pool, oid);
286 ObjectCacheInfo info;
287 info.xattrs = attrs;
288 info.status = 0;
289 info.data = data;
290 info.flags = CACHE_FLAG_XATTRS | CACHE_FLAG_DATA | CACHE_FLAG_META;
291 if (objv_tracker) {
292 info.version = objv_tracker->write_version;
293 info.flags |= CACHE_FLAG_OBJV;
294 }
295 ceph::real_time result_mtime;
296 int ret = RGWSI_SysObj_Core::write(obj, &result_mtime, attrs,
9f95a23c
TL
297 exclusive, data,
298 objv_tracker, set_mtime, y);
11fdf7f2
TL
299 if (pmtime) {
300 *pmtime = result_mtime;
301 }
302 info.meta.mtime = result_mtime;
303 info.meta.size = data.length();
304 string name = normal_name(pool, oid);
305 if (ret >= 0) {
306 cache.put(name, info, NULL);
307 // Only distribute the cache information if we did not just create
308 // the object with the exclusive flag. Note: PUT_OBJ_EXCL implies
309 // PUT_OBJ_CREATE. Generally speaking, when successfully creating
310 // a system object with the exclusive flag it is not necessary to
311 // call distribute_cache, as a) it's unclear whether other RGWs
312 // will need that system object in the near-term and b) it
313 // generates additional network traffic.
314 if (!exclusive) {
9f95a23c 315 int r = distribute_cache(name, obj, info, UPDATE_OBJ, y);
11fdf7f2
TL
316 if (r < 0)
317 ldout(cct, 0) << "ERROR: failed to distribute cache for " << obj << dendl;
318 }
319 } else {
320 cache.remove(name);
321 }
322
323 return ret;
324}
325
326int RGWSI_SysObj_Cache::write_data(const rgw_raw_obj& obj,
327 const bufferlist& data,
328 bool exclusive,
9f95a23c
TL
329 RGWObjVersionTracker *objv_tracker,
330 optional_yield y)
11fdf7f2
TL
331{
332 rgw_pool pool;
333 string oid;
334 normalize_pool_and_obj(obj.pool, obj.oid, pool, oid);
335
336 ObjectCacheInfo info;
337 info.data = data;
338 info.meta.size = data.length();
339 info.status = 0;
340 info.flags = CACHE_FLAG_DATA;
341
342 if (objv_tracker) {
343 info.version = objv_tracker->write_version;
344 info.flags |= CACHE_FLAG_OBJV;
345 }
9f95a23c 346 int ret = RGWSI_SysObj_Core::write_data(obj, data, exclusive, objv_tracker, y);
11fdf7f2
TL
347 string name = normal_name(pool, oid);
348 if (ret >= 0) {
349 cache.put(name, info, NULL);
9f95a23c 350 int r = distribute_cache(name, obj, info, UPDATE_OBJ, y);
11fdf7f2
TL
351 if (r < 0)
352 ldout(cct, 0) << "ERROR: failed to distribute cache for " << obj << dendl;
353 } else {
354 cache.remove(name);
355 }
356
357 return ret;
358}
359
360int RGWSI_SysObj_Cache::raw_stat(const rgw_raw_obj& obj, uint64_t *psize, real_time *pmtime, uint64_t *pepoch,
361 map<string, bufferlist> *attrs, bufferlist *first_chunk,
9f95a23c
TL
362 RGWObjVersionTracker *objv_tracker,
363 optional_yield y)
11fdf7f2
TL
364{
365 rgw_pool pool;
366 string oid;
367 normalize_pool_and_obj(obj.pool, obj.oid, pool, oid);
368
369 string name = normal_name(pool, oid);
370
371 uint64_t size;
372 real_time mtime;
373 uint64_t epoch;
374
375 ObjectCacheInfo info;
376 uint32_t flags = CACHE_FLAG_META | CACHE_FLAG_XATTRS;
377 if (objv_tracker)
378 flags |= CACHE_FLAG_OBJV;
379 int r = cache.get(name, info, flags, NULL);
380 if (r == 0) {
381 if (info.status < 0)
382 return info.status;
383
384 size = info.meta.size;
385 mtime = info.meta.mtime;
386 epoch = info.epoch;
387 if (objv_tracker)
388 objv_tracker->read_version = info.version;
389 goto done;
390 }
f6b5b4d7
TL
391 if (r == -ENODATA) {
392 return -ENOENT;
393 }
9f95a23c
TL
394 r = RGWSI_SysObj_Core::raw_stat(obj, &size, &mtime, &epoch, &info.xattrs,
395 first_chunk, objv_tracker, y);
11fdf7f2
TL
396 if (r < 0) {
397 if (r == -ENOENT) {
398 info.status = r;
399 cache.put(name, info, NULL);
400 }
401 return r;
402 }
403 info.status = 0;
404 info.epoch = epoch;
405 info.meta.mtime = mtime;
406 info.meta.size = size;
407 info.flags = CACHE_FLAG_META | CACHE_FLAG_XATTRS;
408 if (objv_tracker) {
409 info.flags |= CACHE_FLAG_OBJV;
410 info.version = objv_tracker->read_version;
411 }
412 cache.put(name, info, NULL);
413done:
414 if (psize)
415 *psize = size;
416 if (pmtime)
417 *pmtime = mtime;
418 if (pepoch)
419 *pepoch = epoch;
420 if (attrs)
421 *attrs = info.xattrs;
422 return 0;
423}
424
9f95a23c
TL
425int RGWSI_SysObj_Cache::distribute_cache(const string& normal_name,
426 const rgw_raw_obj& obj,
427 ObjectCacheInfo& obj_info, int op,
428 optional_yield y)
11fdf7f2
TL
429{
430 RGWCacheNotifyInfo info;
11fdf7f2 431 info.op = op;
11fdf7f2
TL
432 info.obj_info = obj_info;
433 info.obj = obj;
434 bufferlist bl;
435 encode(info, bl);
9f95a23c 436 return notify_svc->distribute(normal_name, bl, y);
11fdf7f2
TL
437}
438
439int RGWSI_SysObj_Cache::watch_cb(uint64_t notify_id,
440 uint64_t cookie,
441 uint64_t notifier_id,
442 bufferlist& bl)
443{
444 RGWCacheNotifyInfo info;
445
446 try {
447 auto iter = bl.cbegin();
448 decode(info, iter);
449 } catch (buffer::end_of_buffer& err) {
450 ldout(cct, 0) << "ERROR: got bad notification" << dendl;
451 return -EIO;
452 } catch (buffer::error& err) {
453 ldout(cct, 0) << "ERROR: buffer::error" << dendl;
454 return -EIO;
455 }
456
457 rgw_pool pool;
458 string oid;
459 normalize_pool_and_obj(info.obj.pool, info.obj.oid, pool, oid);
460 string name = normal_name(pool, oid);
461
462 switch (info.op) {
463 case UPDATE_OBJ:
464 cache.put(name, info.obj_info, NULL);
465 break;
466 case REMOVE_OBJ:
467 cache.remove(name);
468 break;
469 default:
470 ldout(cct, 0) << "WARNING: got unknown notification op: " << info.op << dendl;
471 return -EINVAL;
472 }
473
474 return 0;
475}
476
477void RGWSI_SysObj_Cache::set_enabled(bool status)
478{
479 cache.set_enabled(status);
480}
481
482bool RGWSI_SysObj_Cache::chain_cache_entry(std::initializer_list<rgw_cache_entry_info *> cache_info_entries,
483 RGWChainedCache::Entry *chained_entry)
484{
485 return cache.chain_cache_entry(cache_info_entries, chained_entry);
486}
487
488void RGWSI_SysObj_Cache::register_chained_cache(RGWChainedCache *cc)
489{
490 cache.chain_cache(cc);
491}
492
493void RGWSI_SysObj_Cache::unregister_chained_cache(RGWChainedCache *cc)
494{
495 cache.unchain_cache(cc);
496}
497
498static void cache_list_dump_helper(Formatter* f,
499 const std::string& name,
500 const ceph::real_time mtime,
501 const std::uint64_t size)
502{
503 f->dump_string("name", name);
504 f->dump_string("mtime", ceph::to_iso_8601(mtime));
505 f->dump_unsigned("size", size);
506}
507
9f95a23c
TL
508class RGWSI_SysObj_Cache_ASocketHook : public AdminSocketHook {
509 RGWSI_SysObj_Cache *svc;
510
511 static constexpr const char* admin_commands[4][3] = {
512 { "cache list",
513 "cache list name=filter,type=CephString,req=false",
514 "cache list [filter_str]: list object cache, possibly matching substrings" },
515 { "cache inspect name=target,type=CephString,req=true",
516 "cache inspect target: print cache element" },
517 { "cache erase name=target,type=CephString,req=true",
518 "cache erase target: erase element from cache" },
519 { "cache zap",
520 "cache zap: erase all elements from cache" }
521 };
522
523public:
524 RGWSI_SysObj_Cache_ASocketHook(RGWSI_SysObj_Cache *_svc) : svc(_svc) {}
525
526 int start();
527 void shutdown();
528
529 int call(std::string_view command, const cmdmap_t& cmdmap,
530 Formatter *f,
531 std::ostream& ss,
532 bufferlist& out) override;
533};
534
535int RGWSI_SysObj_Cache_ASocketHook::start()
536{
537 auto admin_socket = svc->ctx()->get_admin_socket();
538 for (auto cmd : admin_commands) {
539 int r = admin_socket->register_command(cmd[0], this, cmd[1]);
540 if (r < 0) {
541 ldout(svc->ctx(), 0) << "ERROR: fail to register admin socket command (r=" << r
542 << ")" << dendl;
543 return r;
544 }
545 }
546 return 0;
547}
548
549void RGWSI_SysObj_Cache_ASocketHook::shutdown()
550{
551 auto admin_socket = svc->ctx()->get_admin_socket();
552 admin_socket->unregister_commands(this);
553}
554
555int RGWSI_SysObj_Cache_ASocketHook::call(
556 std::string_view command, const cmdmap_t& cmdmap,
557 Formatter *f,
558 std::ostream& ss,
559 bufferlist& out)
560{
561 if (command == "cache list"sv) {
562 std::optional<std::string> filter;
563 if (auto i = cmdmap.find("filter"); i != cmdmap.cend()) {
564 filter = boost::get<std::string>(i->second);
565 }
566 f->open_array_section("cache_entries");
567 svc->asocket.call_list(filter, f);
568 f->close_section();
569 return 0;
570 } else if (command == "cache inspect"sv) {
571 const auto& target = boost::get<std::string>(cmdmap.at("target"));
572 if (svc->asocket.call_inspect(target, f)) {
573 return 0;
574 } else {
575 ss << "Unable to find entry "s + target + ".\n";
576 return -ENOENT;
577 }
578 } else if (command == "cache erase"sv) {
579 const auto& target = boost::get<std::string>(cmdmap.at("target"));
580 if (svc->asocket.call_erase(target)) {
581 return 0;
582 } else {
583 ss << "Unable to find entry "s + target + ".\n";
584 return -ENOENT;
585 }
586 } else if (command == "cache zap"sv) {
587 svc->asocket.call_zap();
588 return 0;
589 }
590 return -ENOSYS;
591}
592
593RGWSI_SysObj_Cache::ASocketHandler::ASocketHandler(RGWSI_SysObj_Cache *_svc) : svc(_svc)
594{
595 hook.reset(new RGWSI_SysObj_Cache_ASocketHook(_svc));
596}
597
598RGWSI_SysObj_Cache::ASocketHandler::~ASocketHandler()
599{
600}
601
602int RGWSI_SysObj_Cache::ASocketHandler::start()
603{
604 return hook->start();
605}
606
607void RGWSI_SysObj_Cache::ASocketHandler::shutdown()
608{
609 return hook->shutdown();
610}
611
612void RGWSI_SysObj_Cache::ASocketHandler::call_list(const std::optional<std::string>& filter, Formatter* f)
11fdf7f2 613{
9f95a23c
TL
614 svc->cache.for_each(
615 [&filter, f] (const string& name, const ObjectCacheEntry& entry) {
11fdf7f2
TL
616 if (!filter || name.find(*filter) != name.npos) {
617 cache_list_dump_helper(f, name, entry.info.meta.mtime,
618 entry.info.meta.size);
619 }
620 });
621}
622
9f95a23c 623int RGWSI_SysObj_Cache::ASocketHandler::call_inspect(const std::string& target, Formatter* f)
11fdf7f2 624{
9f95a23c 625 if (const auto entry = svc->cache.get(target)) {
11fdf7f2
TL
626 f->open_object_section("cache_entry");
627 f->dump_string("name", target.c_str());
628 entry->dump(f);
629 f->close_section();
630 return true;
631 } else {
632 return false;
633 }
634}
635
9f95a23c 636int RGWSI_SysObj_Cache::ASocketHandler::call_erase(const std::string& target)
11fdf7f2 637{
9f95a23c 638 return svc->cache.remove(target);
11fdf7f2
TL
639}
640
9f95a23c 641int RGWSI_SysObj_Cache::ASocketHandler::call_zap()
11fdf7f2 642{
9f95a23c 643 svc->cache.invalidate_all();
11fdf7f2
TL
644 return 0;
645}