]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_rest_log.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rgw / rgw_rest_log.cc
CommitLineData
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
11fdf7f2 3
7c673cae
FG
4/*
5 * Ceph - scalable distributed file system
6 *
7 * Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
8 *
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
13 *
14 */
11fdf7f2 15
7c673cae
FG
16#include "common/ceph_json.h"
17#include "common/strtol.h"
18#include "rgw_rest.h"
19#include "rgw_op.h"
20#include "rgw_rest_s3.h"
21#include "rgw_rest_log.h"
22#include "rgw_client_io.h"
23#include "rgw_sync.h"
24#include "rgw_data_sync.h"
31f18b77 25#include "rgw_common.h"
11fdf7f2 26#include "rgw_zone.h"
9f95a23c 27#include "rgw_mdlog.h"
11fdf7f2
TL
28
29#include "services/svc_zone.h"
9f95a23c
TL
30#include "services/svc_mdlog.h"
31#include "services/svc_bilog_rados.h"
11fdf7f2 32
7c673cae 33#include "common/errno.h"
11fdf7f2 34#include "include/ceph_assert.h"
7c673cae
FG
35
36#define dout_context g_ceph_context
37#define LOG_CLASS_LIST_MAX_ENTRIES (1000)
38#define dout_subsys ceph_subsys_rgw
39
20effc67
TL
40using namespace std;
41
f67539c2 42void RGWOp_MDLog_List::execute(optional_yield y) {
7c673cae
FG
43 string period = s->info.args.get("period");
44 string shard = s->info.args.get("id");
45 string max_entries_str = s->info.args.get("max-entries");
f67539c2 46 string marker = s->info.args.get("marker"),
7c673cae 47 err;
7c673cae
FG
48 void *handle;
49 unsigned shard_id, max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
50
f67539c2
TL
51 if (s->info.args.exists("start-time") ||
52 s->info.args.exists("end-time")) {
b3b6e05e 53 ldpp_dout(this, 5) << "start-time and end-time are no longer accepted" << dendl;
f67539c2 54 op_ret = -EINVAL;
7c673cae
FG
55 return;
56 }
57
f67539c2
TL
58 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
59 if (!err.empty()) {
b3b6e05e 60 ldpp_dout(this, 5) << "Error parsing shard_id " << shard << dendl;
f67539c2 61 op_ret = -EINVAL;
7c673cae
FG
62 return;
63 }
64
65 if (!max_entries_str.empty()) {
66 max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err);
67 if (!err.empty()) {
b3b6e05e 68 ldpp_dout(this, 5) << "Error parsing max-entries " << max_entries_str << dendl;
f67539c2 69 op_ret = -EINVAL;
7c673cae
FG
70 return;
71 }
224ce89b
WB
72 if (max_entries > LOG_CLASS_LIST_MAX_ENTRIES) {
73 max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
74 }
f67539c2 75 }
7c673cae
FG
76
77 if (period.empty()) {
b3b6e05e 78 ldpp_dout(this, 5) << "Missing period id trying to use current" << dendl;
20effc67 79 period = store->get_zone()->get_current_period_id();
7c673cae 80 if (period.empty()) {
b3b6e05e 81 ldpp_dout(this, 5) << "Missing period id" << dendl;
f67539c2 82 op_ret = -EINVAL;
7c673cae
FG
83 return;
84 }
85 }
86
20effc67 87 RGWMetadataLog meta_log{s->cct, static_cast<rgw::sal::RadosStore*>(store)->svc()->zone, static_cast<rgw::sal::RadosStore*>(store)->svc()->cls, period};
7c673cae 88
f67539c2 89 meta_log.init_list_entries(shard_id, {}, {}, marker, &handle);
7c673cae 90
b3b6e05e 91 op_ret = meta_log.list_entries(this, handle, max_entries, entries,
224ce89b 92 &last_marker, &truncated);
7c673cae
FG
93
94 meta_log.complete_list_entries(handle);
95}
96
97void RGWOp_MDLog_List::send_response() {
f67539c2 98 set_req_state_err(s, op_ret);
7c673cae
FG
99 dump_errno(s);
100 end_header(s);
101
f67539c2 102 if (op_ret < 0)
7c673cae
FG
103 return;
104
105 s->formatter->open_object_section("log_entries");
106 s->formatter->dump_string("marker", last_marker);
107 s->formatter->dump_bool("truncated", truncated);
108 {
109 s->formatter->open_array_section("entries");
110 for (list<cls_log_entry>::iterator iter = entries.begin();
111 iter != entries.end(); ++iter) {
112 cls_log_entry& entry = *iter;
20effc67 113 static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->dump_log_entry(entry, s->formatter);
7c673cae
FG
114 flusher.flush();
115 }
116 s->formatter->close_section();
117 }
118 s->formatter->close_section();
119 flusher.flush();
120}
121
f67539c2 122void RGWOp_MDLog_Info::execute(optional_yield y) {
7c673cae 123 num_objects = s->cct->_conf->rgw_md_log_max_shards;
20effc67 124 period = static_cast<rgw::sal::RadosStore*>(store)->svc()->mdlog->read_oldest_log_period(y, s);
f67539c2 125 op_ret = period.get_error();
7c673cae
FG
126}
127
128void RGWOp_MDLog_Info::send_response() {
f67539c2 129 set_req_state_err(s, op_ret);
7c673cae
FG
130 dump_errno(s);
131 end_header(s);
132
133 s->formatter->open_object_section("mdlog");
134 s->formatter->dump_unsigned("num_objects", num_objects);
135 if (period) {
136 s->formatter->dump_string("period", period.get_period().get_id());
137 s->formatter->dump_unsigned("realm_epoch", period.get_epoch());
138 }
139 s->formatter->close_section();
140 flusher.flush();
141}
142
f67539c2 143void RGWOp_MDLog_ShardInfo::execute(optional_yield y) {
7c673cae
FG
144 string period = s->info.args.get("period");
145 string shard = s->info.args.get("id");
146 string err;
147
148 unsigned shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
149 if (!err.empty()) {
b3b6e05e 150 ldpp_dout(this, 5) << "Error parsing shard_id " << shard << dendl;
f67539c2 151 op_ret = -EINVAL;
7c673cae
FG
152 return;
153 }
154
155 if (period.empty()) {
b3b6e05e 156 ldpp_dout(this, 5) << "Missing period id trying to use current" << dendl;
20effc67 157 period = store->get_zone()->get_current_period_id();
7c673cae
FG
158
159 if (period.empty()) {
b3b6e05e 160 ldpp_dout(this, 5) << "Missing period id" << dendl;
f67539c2 161 op_ret = -EINVAL;
7c673cae
FG
162 return;
163 }
164 }
20effc67 165 RGWMetadataLog meta_log{s->cct, static_cast<rgw::sal::RadosStore*>(store)->svc()->zone, static_cast<rgw::sal::RadosStore*>(store)->svc()->cls, period};
7c673cae 166
b3b6e05e 167 op_ret = meta_log.get_info(this, shard_id, &info);
7c673cae
FG
168}
169
170void RGWOp_MDLog_ShardInfo::send_response() {
f67539c2 171 set_req_state_err(s, op_ret);
7c673cae
FG
172 dump_errno(s);
173 end_header(s);
174
175 encode_json("info", info, s->formatter);
176 flusher.flush();
177}
178
f67539c2
TL
179void RGWOp_MDLog_Delete::execute(optional_yield y) {
180 string marker = s->info.args.get("marker"),
7c673cae
FG
181 period = s->info.args.get("period"),
182 shard = s->info.args.get("id"),
183 err;
7c673cae
FG
184 unsigned shard_id;
185
7c673cae 186
f67539c2
TL
187 if (s->info.args.exists("start-time") ||
188 s->info.args.exists("end-time")) {
b3b6e05e 189 ldpp_dout(this, 5) << "start-time and end-time are no longer accepted" << dendl;
f67539c2 190 op_ret = -EINVAL;
7c673cae 191 }
f67539c2
TL
192
193 if (s->info.args.exists("start-marker")) {
b3b6e05e 194 ldpp_dout(this, 5) << "start-marker is no longer accepted" << dendl;
f67539c2
TL
195 op_ret = -EINVAL;
196 }
197
198 if (s->info.args.exists("end-marker")) {
199 if (!s->info.args.exists("marker")) {
200 marker = s->info.args.get("end-marker");
201 } else {
b3b6e05e 202 ldpp_dout(this, 5) << "end-marker and marker cannot both be provided" << dendl;
f67539c2
TL
203 op_ret = -EINVAL;
204 }
7c673cae
FG
205 }
206
f67539c2
TL
207 op_ret = 0;
208
209 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
210 if (!err.empty()) {
b3b6e05e 211 ldpp_dout(this, 5) << "Error parsing shard_id " << shard << dendl;
f67539c2 212 op_ret = -EINVAL;
7c673cae
FG
213 return;
214 }
215
f67539c2
TL
216 if (marker.empty()) { /* bounding end */
217 op_ret = -EINVAL;
7c673cae
FG
218 return;
219 }
220
221 if (period.empty()) {
b3b6e05e 222 ldpp_dout(this, 5) << "Missing period id trying to use current" << dendl;
20effc67 223 period = store->get_zone()->get_current_period_id();
7c673cae
FG
224
225 if (period.empty()) {
b3b6e05e 226 ldpp_dout(this, 5) << "Missing period id" << dendl;
f67539c2 227 op_ret = -EINVAL;
7c673cae
FG
228 return;
229 }
230 }
20effc67 231 RGWMetadataLog meta_log{s->cct, static_cast<rgw::sal::RadosStore*>(store)->svc()->zone, static_cast<rgw::sal::RadosStore*>(store)->svc()->cls, period};
7c673cae 232
b3b6e05e 233 op_ret = meta_log.trim(this, shard_id, {}, {}, {}, marker);
7c673cae
FG
234}
235
f67539c2 236void RGWOp_MDLog_Lock::execute(optional_yield y) {
7c673cae
FG
237 string period, shard_id_str, duration_str, locker_id, zone_id;
238 unsigned shard_id;
239
f67539c2 240 op_ret = 0;
7c673cae
FG
241
242 period = s->info.args.get("period");
243 shard_id_str = s->info.args.get("id");
244 duration_str = s->info.args.get("length");
245 locker_id = s->info.args.get("locker-id");
246 zone_id = s->info.args.get("zone-id");
247
248 if (period.empty()) {
b3b6e05e 249 ldpp_dout(this, 5) << "Missing period id trying to use current" << dendl;
20effc67 250 period = store->get_zone()->get_current_period_id();
7c673cae
FG
251 }
252
253 if (period.empty() ||
254 shard_id_str.empty() ||
255 (duration_str.empty()) ||
256 locker_id.empty() ||
257 zone_id.empty()) {
b3b6e05e 258 ldpp_dout(this, 5) << "Error invalid parameter list" << dendl;
f67539c2 259 op_ret = -EINVAL;
7c673cae
FG
260 return;
261 }
262
263 string err;
264 shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err);
265 if (!err.empty()) {
b3b6e05e 266 ldpp_dout(this, 5) << "Error parsing shard_id param " << shard_id_str << dendl;
f67539c2 267 op_ret = -EINVAL;
7c673cae
FG
268 return;
269 }
270
20effc67 271 RGWMetadataLog meta_log{s->cct, static_cast<rgw::sal::RadosStore*>(store)->svc()->zone, static_cast<rgw::sal::RadosStore*>(store)->svc()->cls, period};
7c673cae
FG
272 unsigned dur;
273 dur = (unsigned)strict_strtol(duration_str.c_str(), 10, &err);
274 if (!err.empty() || dur <= 0) {
b3b6e05e 275 ldpp_dout(this, 5) << "invalid length param " << duration_str << dendl;
f67539c2 276 op_ret = -EINVAL;
7c673cae
FG
277 return;
278 }
b3b6e05e 279 op_ret = meta_log.lock_exclusive(s, shard_id, make_timespan(dur), zone_id,
7c673cae 280 locker_id);
f67539c2
TL
281 if (op_ret == -EBUSY)
282 op_ret = -ERR_LOCKED;
7c673cae
FG
283}
284
f67539c2 285void RGWOp_MDLog_Unlock::execute(optional_yield y) {
7c673cae
FG
286 string period, shard_id_str, locker_id, zone_id;
287 unsigned shard_id;
288
f67539c2 289 op_ret = 0;
7c673cae
FG
290
291 period = s->info.args.get("period");
292 shard_id_str = s->info.args.get("id");
293 locker_id = s->info.args.get("locker-id");
294 zone_id = s->info.args.get("zone-id");
295
296 if (period.empty()) {
b3b6e05e 297 ldpp_dout(this, 5) << "Missing period id trying to use current" << dendl;
20effc67 298 period = store->get_zone()->get_current_period_id();
7c673cae
FG
299 }
300
301 if (period.empty() ||
302 shard_id_str.empty() ||
303 locker_id.empty() ||
304 zone_id.empty()) {
b3b6e05e 305 ldpp_dout(this, 5) << "Error invalid parameter list" << dendl;
f67539c2 306 op_ret = -EINVAL;
7c673cae
FG
307 return;
308 }
309
310 string err;
311 shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err);
312 if (!err.empty()) {
b3b6e05e 313 ldpp_dout(this, 5) << "Error parsing shard_id param " << shard_id_str << dendl;
f67539c2 314 op_ret = -EINVAL;
7c673cae
FG
315 return;
316 }
317
20effc67 318 RGWMetadataLog meta_log{s->cct, static_cast<rgw::sal::RadosStore*>(store)->svc()->zone, static_cast<rgw::sal::RadosStore*>(store)->svc()->cls, period};
b3b6e05e 319 op_ret = meta_log.unlock(s, shard_id, zone_id, locker_id);
7c673cae
FG
320}
321
f67539c2 322void RGWOp_MDLog_Notify::execute(optional_yield y) {
7c673cae 323#define LARGE_ENOUGH_BUF (128 * 1024)
11fdf7f2
TL
324
325 int r = 0;
326 bufferlist data;
20effc67 327 std::tie(r, data) = read_all_input(s, LARGE_ENOUGH_BUF);
7c673cae 328 if (r < 0) {
f67539c2 329 op_ret = r;
7c673cae
FG
330 return;
331 }
332
11fdf7f2 333 char* buf = data.c_str();
b3b6e05e 334 ldpp_dout(this, 20) << __func__ << "(): read data: " << buf << dendl;
7c673cae
FG
335
336 JSONParser p;
11fdf7f2 337 r = p.parse(buf, data.length());
7c673cae 338 if (r < 0) {
b3b6e05e 339 ldpp_dout(this, 0) << "ERROR: failed to parse JSON" << dendl;
f67539c2 340 op_ret = r;
7c673cae
FG
341 return;
342 }
343
344 set<int> updated_shards;
345 try {
346 decode_json_obj(updated_shards, &p);
347 } catch (JSONDecoder::err& err) {
b3b6e05e 348 ldpp_dout(this, 0) << "ERROR: failed to decode JSON" << dendl;
f67539c2 349 op_ret = -EINVAL;
7c673cae
FG
350 return;
351 }
352
11fdf7f2 353 if (store->ctx()->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
7c673cae 354 for (set<int>::iterator iter = updated_shards.begin(); iter != updated_shards.end(); ++iter) {
b3b6e05e 355 ldpp_dout(this, 20) << __func__ << "(): updated shard=" << *iter << dendl;
7c673cae
FG
356 }
357 }
358
20effc67 359 store->wakeup_meta_sync_shards(updated_shards);
7c673cae 360
f67539c2 361 op_ret = 0;
7c673cae
FG
362}
363
f67539c2 364void RGWOp_BILog_List::execute(optional_yield y) {
7c673cae
FG
365 string tenant_name = s->info.args.get("tenant"),
366 bucket_name = s->info.args.get("bucket"),
367 marker = s->info.args.get("marker"),
368 max_entries_str = s->info.args.get("max-entries"),
369 bucket_instance = s->info.args.get("bucket-instance");
20effc67
TL
370 std::unique_ptr<rgw::sal::Bucket> bucket;
371 rgw_bucket b(rgw_bucket_key(tenant_name, bucket_name));
7c673cae
FG
372 unsigned max_entries;
373
7c673cae 374 if (bucket_name.empty() && bucket_instance.empty()) {
b3b6e05e 375 ldpp_dout(this, 5) << "ERROR: neither bucket nor bucket instance specified" << dendl;
f67539c2 376 op_ret = -EINVAL;
7c673cae
FG
377 return;
378 }
379
380 int shard_id;
9f95a23c 381 string bn;
f67539c2
TL
382 op_ret = rgw_bucket_parse_bucket_instance(bucket_instance, &bn, &bucket_instance, &shard_id);
383 if (op_ret < 0) {
7c673cae
FG
384 return;
385 }
386
387 if (!bucket_instance.empty()) {
20effc67
TL
388 b.name = bn;
389 b.bucket_id = bucket_instance;
390 }
391 op_ret = store->get_bucket(s, nullptr, b, &bucket, y);
392 if (op_ret < 0) {
393 ldpp_dout(this, 5) << "could not get bucket info for bucket=" << bucket_name << dendl;
394 return;
7c673cae
FG
395 }
396
397 bool truncated;
398 unsigned count = 0;
399 string err;
400
401 max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err);
402 if (!err.empty())
403 max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
404
405 send_response();
406 do {
407 list<rgw_bi_log_entry> entries;
20effc67 408 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->bilog_rados->log_list(s, bucket->get_info(), shard_id,
9f95a23c
TL
409 marker, max_entries - count,
410 entries, &truncated);
7c673cae 411 if (ret < 0) {
b3b6e05e 412 ldpp_dout(this, 5) << "ERROR: list_bi_log_entries()" << dendl;
7c673cae
FG
413 return;
414 }
415
416 count += entries.size();
417
418 send_response(entries, marker);
419 } while (truncated && count < max_entries);
420
421 send_response_end();
422}
423
424void RGWOp_BILog_List::send_response() {
425 if (sent_header)
426 return;
427
f67539c2 428 set_req_state_err(s, op_ret);
7c673cae
FG
429 dump_errno(s);
430 end_header(s);
431
432 sent_header = true;
433
f67539c2 434 if (op_ret < 0)
7c673cae
FG
435 return;
436
437 s->formatter->open_array_section("entries");
438}
439
440void RGWOp_BILog_List::send_response(list<rgw_bi_log_entry>& entries, string& marker)
441{
442 for (list<rgw_bi_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
443 rgw_bi_log_entry& entry = *iter;
444 encode_json("entry", entry, s->formatter);
445
446 marker = entry.id;
447 flusher.flush();
448 }
449}
450
451void RGWOp_BILog_List::send_response_end() {
452 s->formatter->close_section();
453 flusher.flush();
454}
455
f67539c2 456void RGWOp_BILog_Info::execute(optional_yield y) {
7c673cae
FG
457 string tenant_name = s->info.args.get("tenant"),
458 bucket_name = s->info.args.get("bucket"),
459 bucket_instance = s->info.args.get("bucket-instance");
20effc67
TL
460 std::unique_ptr<rgw::sal::Bucket> bucket;
461 rgw_bucket b(rgw_bucket_key(tenant_name, bucket_name));
7c673cae 462
7c673cae 463 if (bucket_name.empty() && bucket_instance.empty()) {
b3b6e05e 464 ldpp_dout(this, 5) << "ERROR: neither bucket nor bucket instance specified" << dendl;
f67539c2 465 op_ret = -EINVAL;
7c673cae
FG
466 return;
467 }
468
469 int shard_id;
9f95a23c 470 string bn;
f67539c2
TL
471 op_ret = rgw_bucket_parse_bucket_instance(bucket_instance, &bn, &bucket_instance, &shard_id);
472 if (op_ret < 0) {
7c673cae
FG
473 return;
474 }
475
476 if (!bucket_instance.empty()) {
20effc67
TL
477 b.name = bn;
478 b.bucket_id = bucket_instance;
7c673cae 479 }
20effc67
TL
480 op_ret = store->get_bucket(s, nullptr, b, &bucket, y);
481 if (op_ret < 0) {
482 ldpp_dout(this, 5) << "could not get bucket info for bucket=" << bucket_name << dendl;
483 return;
484 }
485
7c673cae 486 map<RGWObjCategory, RGWStorageStats> stats;
20effc67 487 int ret = bucket->read_stats(s, shard_id, &bucket_ver, &master_ver, stats, &max_marker, &syncstopped);
7c673cae 488 if (ret < 0 && ret != -ENOENT) {
f67539c2 489 op_ret = ret;
7c673cae
FG
490 return;
491 }
492}
493
494void RGWOp_BILog_Info::send_response() {
f67539c2 495 set_req_state_err(s, op_ret);
7c673cae
FG
496 dump_errno(s);
497 end_header(s);
498
f67539c2 499 if (op_ret < 0)
7c673cae
FG
500 return;
501
502 s->formatter->open_object_section("info");
503 encode_json("bucket_ver", bucket_ver, s->formatter);
504 encode_json("master_ver", master_ver, s->formatter);
505 encode_json("max_marker", max_marker, s->formatter);
c07f9fc5 506 encode_json("syncstopped", syncstopped, s->formatter);
7c673cae
FG
507 s->formatter->close_section();
508
509 flusher.flush();
510}
511
f67539c2 512void RGWOp_BILog_Delete::execute(optional_yield y) {
7c673cae
FG
513 string tenant_name = s->info.args.get("tenant"),
514 bucket_name = s->info.args.get("bucket"),
515 start_marker = s->info.args.get("start-marker"),
516 end_marker = s->info.args.get("end-marker"),
517 bucket_instance = s->info.args.get("bucket-instance");
518
20effc67
TL
519 std::unique_ptr<rgw::sal::Bucket> bucket;
520 rgw_bucket b(rgw_bucket_key(tenant_name, bucket_name));
7c673cae 521
f67539c2 522 op_ret = 0;
7c673cae
FG
523 if ((bucket_name.empty() && bucket_instance.empty()) ||
524 end_marker.empty()) {
b3b6e05e 525 ldpp_dout(this, 5) << "ERROR: one of bucket and bucket instance, and also end-marker is mandatory" << dendl;
f67539c2 526 op_ret = -EINVAL;
7c673cae
FG
527 return;
528 }
529
530 int shard_id;
9f95a23c 531 string bn;
f67539c2
TL
532 op_ret = rgw_bucket_parse_bucket_instance(bucket_instance, &bn, &bucket_instance, &shard_id);
533 if (op_ret < 0) {
7c673cae
FG
534 return;
535 }
536
537 if (!bucket_instance.empty()) {
20effc67
TL
538 b.name = bn;
539 b.bucket_id = bucket_instance;
540 }
541 op_ret = store->get_bucket(s, nullptr, b, &bucket, y);
542 if (op_ret < 0) {
543 ldpp_dout(this, 5) << "could not get bucket info for bucket=" << bucket_name << dendl;
544 return;
7c673cae 545 }
20effc67
TL
546
547 op_ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->bilog_rados->log_trim(s, bucket->get_info(), shard_id, start_marker, end_marker);
f67539c2 548 if (op_ret < 0) {
b3b6e05e 549 ldpp_dout(this, 5) << "ERROR: trim_bi_log_entries() " << dendl;
7c673cae
FG
550 }
551 return;
552}
553
f67539c2 554void RGWOp_DATALog_List::execute(optional_yield y) {
7c673cae
FG
555 string shard = s->info.args.get("id");
556
f67539c2 557 string max_entries_str = s->info.args.get("max-entries"),
7c673cae
FG
558 marker = s->info.args.get("marker"),
559 err;
7c673cae
FG
560 unsigned shard_id, max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
561
f67539c2
TL
562 if (s->info.args.exists("start-time") ||
563 s->info.args.exists("end-time")) {
b3b6e05e 564 ldpp_dout(this, 5) << "start-time and end-time are no longer accepted" << dendl;
f67539c2
TL
565 op_ret = -EINVAL;
566 }
567
7c673cae
FG
568 s->info.args.get_bool("extra-info", &extra_info, false);
569
570 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
571 if (!err.empty()) {
b3b6e05e 572 ldpp_dout(this, 5) << "Error parsing shard_id " << shard << dendl;
f67539c2 573 op_ret = -EINVAL;
7c673cae
FG
574 return;
575 }
576
577 if (!max_entries_str.empty()) {
578 max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err);
579 if (!err.empty()) {
b3b6e05e 580 ldpp_dout(this, 5) << "Error parsing max-entries " << max_entries_str << dendl;
f67539c2 581 op_ret = -EINVAL;
7c673cae
FG
582 return;
583 }
224ce89b
WB
584 if (max_entries > LOG_CLASS_LIST_MAX_ENTRIES) {
585 max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
586 }
587 }
588
589 // Note that last_marker is updated to be the marker of the last
590 // entry listed
20effc67 591 op_ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados->list_entries(this, shard_id,
f67539c2
TL
592 max_entries, entries,
593 marker, &last_marker,
594 &truncated);
7c673cae
FG
595}
596
597void RGWOp_DATALog_List::send_response() {
f67539c2 598 set_req_state_err(s, op_ret);
7c673cae
FG
599 dump_errno(s);
600 end_header(s);
601
f67539c2 602 if (op_ret < 0)
7c673cae
FG
603 return;
604
605 s->formatter->open_object_section("log_entries");
606 s->formatter->dump_string("marker", last_marker);
607 s->formatter->dump_bool("truncated", truncated);
608 {
609 s->formatter->open_array_section("entries");
f67539c2 610 for (const auto& entry : entries) {
7c673cae
FG
611 if (!extra_info) {
612 encode_json("entry", entry.entry, s->formatter);
613 } else {
614 encode_json("entry", entry, s->formatter);
615 }
616 flusher.flush();
617 }
618 s->formatter->close_section();
619 }
620 s->formatter->close_section();
621 flusher.flush();
622}
623
624
f67539c2 625void RGWOp_DATALog_Info::execute(optional_yield y) {
7c673cae 626 num_objects = s->cct->_conf->rgw_data_log_num_shards;
f67539c2 627 op_ret = 0;
7c673cae
FG
628}
629
630void RGWOp_DATALog_Info::send_response() {
f67539c2 631 set_req_state_err(s, op_ret);
7c673cae
FG
632 dump_errno(s);
633 end_header(s);
634
635 s->formatter->open_object_section("num_objects");
636 s->formatter->dump_unsigned("num_objects", num_objects);
637 s->formatter->close_section();
638 flusher.flush();
639}
640
f67539c2 641void RGWOp_DATALog_ShardInfo::execute(optional_yield y) {
7c673cae
FG
642 string shard = s->info.args.get("id");
643 string err;
644
645 unsigned shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
646 if (!err.empty()) {
b3b6e05e 647 ldpp_dout(this, 5) << "Error parsing shard_id " << shard << dendl;
f67539c2 648 op_ret = -EINVAL;
7c673cae
FG
649 return;
650 }
651
20effc67 652 op_ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados->get_info(this, shard_id, &info);
7c673cae
FG
653}
654
655void RGWOp_DATALog_ShardInfo::send_response() {
f67539c2 656 set_req_state_err(s, op_ret);
7c673cae
FG
657 dump_errno(s);
658 end_header(s);
659
660 encode_json("info", info, s->formatter);
661 flusher.flush();
662}
663
f67539c2 664void RGWOp_DATALog_Notify::execute(optional_yield y) {
7c673cae 665 string source_zone = s->info.args.get("source-zone");
7c673cae 666#define LARGE_ENOUGH_BUF (128 * 1024)
11fdf7f2
TL
667
668 int r = 0;
669 bufferlist data;
20effc67 670 std::tie(r, data) = read_all_input(s, LARGE_ENOUGH_BUF);
7c673cae 671 if (r < 0) {
f67539c2 672 op_ret = r;
7c673cae
FG
673 return;
674 }
675
11fdf7f2 676 char* buf = data.c_str();
b3b6e05e 677 ldpp_dout(this, 20) << __func__ << "(): read data: " << buf << dendl;
7c673cae
FG
678
679 JSONParser p;
11fdf7f2 680 r = p.parse(buf, data.length());
7c673cae 681 if (r < 0) {
b3b6e05e 682 ldpp_dout(this, 0) << "ERROR: failed to parse JSON" << dendl;
f67539c2 683 op_ret = r;
7c673cae
FG
684 return;
685 }
686
687 map<int, set<string> > updated_shards;
688 try {
689 decode_json_obj(updated_shards, &p);
690 } catch (JSONDecoder::err& err) {
b3b6e05e 691 ldpp_dout(this, 0) << "ERROR: failed to decode JSON" << dendl;
f67539c2 692 op_ret = -EINVAL;
7c673cae
FG
693 return;
694 }
695
11fdf7f2 696 if (store->ctx()->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
7c673cae 697 for (map<int, set<string> >::iterator iter = updated_shards.begin(); iter != updated_shards.end(); ++iter) {
b3b6e05e 698 ldpp_dout(this, 20) << __func__ << "(): updated shard=" << iter->first << dendl;
7c673cae
FG
699 set<string>& keys = iter->second;
700 for (set<string>::iterator kiter = keys.begin(); kiter != keys.end(); ++kiter) {
b3b6e05e 701 ldpp_dout(this, 20) << __func__ << "(): modified key=" << *kiter << dendl;
7c673cae
FG
702 }
703 }
704 }
705
20effc67 706 store->wakeup_data_sync_shards(this, source_zone, updated_shards);
7c673cae 707
f67539c2 708 op_ret = 0;
7c673cae
FG
709}
710
f67539c2
TL
711void RGWOp_DATALog_Delete::execute(optional_yield y) {
712 string marker = s->info.args.get("marker"),
7c673cae
FG
713 shard = s->info.args.get("id"),
714 err;
7c673cae
FG
715 unsigned shard_id;
716
f67539c2 717 op_ret = 0;
7c673cae 718
f67539c2
TL
719 if (s->info.args.exists("start-time") ||
720 s->info.args.exists("end-time")) {
b3b6e05e 721 ldpp_dout(this, 5) << "start-time and end-time are no longer accepted" << dendl;
f67539c2 722 op_ret = -EINVAL;
7c673cae 723 }
f67539c2
TL
724
725 if (s->info.args.exists("start-marker")) {
b3b6e05e 726 ldpp_dout(this, 5) << "start-marker is no longer accepted" << dendl;
f67539c2 727 op_ret = -EINVAL;
7c673cae
FG
728 }
729
f67539c2
TL
730 if (s->info.args.exists("end-marker")) {
731 if (!s->info.args.exists("marker")) {
732 marker = s->info.args.get("end-marker");
733 } else {
b3b6e05e 734 ldpp_dout(this, 5) << "end-marker and marker cannot both be provided" << dendl;
f67539c2
TL
735 op_ret = -EINVAL;
736 }
7c673cae
FG
737 }
738
f67539c2
TL
739 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
740 if (!err.empty()) {
b3b6e05e 741 ldpp_dout(this, 5) << "Error parsing shard_id " << shard << dendl;
f67539c2
TL
742 op_ret = -EINVAL;
743 return;
744 }
745 if (marker.empty()) { /* bounding end */
746 op_ret = -EINVAL;
7c673cae
FG
747 return;
748 }
749
20effc67 750 op_ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados->trim_entries(this, shard_id, marker);
7c673cae
FG
751}
752
753// not in header to avoid pulling in rgw_sync.h
754class RGWOp_MDLog_Status : public RGWRESTOp {
755 rgw_meta_sync_status status;
756public:
9f95a23c 757 int check_caps(const RGWUserCaps& caps) override {
7c673cae
FG
758 return caps.check_cap("mdlog", RGW_CAP_READ);
759 }
f67539c2 760 int verify_permission(optional_yield) override {
9f95a23c 761 return check_caps(s->user->get_caps());
7c673cae 762 }
f67539c2 763 void execute(optional_yield y) override;
7c673cae 764 void send_response() override;
11fdf7f2 765 const char* name() const override { return "get_metadata_log_status"; }
7c673cae
FG
766};
767
f67539c2 768void RGWOp_MDLog_Status::execute(optional_yield y)
7c673cae 769{
20effc67 770 auto sync = static_cast<rgw::sal::RadosStore*>(store)->getRados()->get_meta_sync_manager();
7c673cae 771 if (sync == nullptr) {
b3b6e05e 772 ldpp_dout(this, 1) << "no sync manager" << dendl;
f67539c2 773 op_ret = -ENOENT;
7c673cae
FG
774 return;
775 }
b3b6e05e 776 op_ret = sync->read_sync_status(this, &status);
7c673cae
FG
777}
778
779void RGWOp_MDLog_Status::send_response()
780{
f67539c2 781 set_req_state_err(s, op_ret);
7c673cae
FG
782 dump_errno(s);
783 end_header(s);
784
f67539c2 785 if (op_ret >= 0) {
7c673cae
FG
786 encode_json("status", status, s->formatter);
787 }
788 flusher.flush();
789}
790
b32b8144
FG
791// not in header to avoid pulling in rgw_data_sync.h
792class RGWOp_BILog_Status : public RGWRESTOp {
793 std::vector<rgw_bucket_shard_sync_info> status;
794public:
9f95a23c 795 int check_caps(const RGWUserCaps& caps) override {
b32b8144
FG
796 return caps.check_cap("bilog", RGW_CAP_READ);
797 }
f67539c2 798 int verify_permission(optional_yield y) override {
9f95a23c 799 return check_caps(s->user->get_caps());
b32b8144 800 }
f67539c2 801 void execute(optional_yield y) override;
b32b8144 802 void send_response() override;
11fdf7f2 803 const char* name() const override { return "get_bucket_index_log_status"; }
b32b8144
FG
804};
805
f67539c2 806void RGWOp_BILog_Status::execute(optional_yield y)
b32b8144 807{
9f95a23c
TL
808 const auto options = s->info.args.get("options");
809 bool merge = (options == "merge");
b32b8144 810 const auto source_zone = s->info.args.get("source-zone");
9f95a23c
TL
811 const auto source_key = s->info.args.get("source-bucket");
812 auto key = s->info.args.get("bucket");
813 if (key.empty()) {
814 key = source_key;
815 }
b32b8144 816 if (key.empty()) {
b3b6e05e 817 ldpp_dout(this, 4) << "no 'bucket' provided" << dendl;
f67539c2 818 op_ret = -EINVAL;
b32b8144
FG
819 return;
820 }
821
20effc67 822 rgw_bucket b;
b32b8144 823 int shard_id{-1}; // unused
20effc67 824 op_ret = rgw_bucket_parse_bucket_key(s->cct, key, &b, &shard_id);
f67539c2 825 if (op_ret < 0) {
b3b6e05e 826 ldpp_dout(this, 4) << "invalid 'bucket' provided" << dendl;
f67539c2 827 op_ret = -EINVAL;
b32b8144
FG
828 return;
829 }
830
28e407b8 831 // read the bucket instance info for num_shards
20effc67
TL
832 std::unique_ptr<rgw::sal::Bucket> bucket;
833 op_ret = store->get_bucket(s, nullptr, b, &bucket, y);
f67539c2 834 if (op_ret < 0) {
b3b6e05e 835 ldpp_dout(this, 4) << "failed to read bucket info: " << cpp_strerror(op_ret) << dendl;
28e407b8
AA
836 return;
837 }
9f95a23c
TL
838
839 rgw_bucket source_bucket;
840
841 if (source_key.empty() ||
842 source_key == key) {
20effc67 843 source_bucket = bucket->get_key();
9f95a23c 844 } else {
f67539c2
TL
845 op_ret = rgw_bucket_parse_bucket_key(s->cct, source_key, &source_bucket, nullptr);
846 if (op_ret < 0) {
b3b6e05e 847 ldpp_dout(this, 4) << "invalid 'source-bucket' provided (key=" << source_key << ")" << dendl;
9f95a23c
TL
848 return;
849 }
850 }
851
20effc67 852 const auto& local_zone_id = store->get_zone()->get_id();
9f95a23c
TL
853
854 if (!merge) {
855 rgw_sync_bucket_pipe pipe;
856 pipe.source.zone = source_zone;
857 pipe.source.bucket = source_bucket;
858 pipe.dest.zone = local_zone_id;
20effc67 859 pipe.dest.bucket = bucket->get_key();
9f95a23c 860
b3b6e05e 861 ldpp_dout(this, 20) << "RGWOp_BILog_Status::execute(optional_yield y): getting sync status for pipe=" << pipe << dendl;
9f95a23c 862
20effc67 863 op_ret = rgw_bucket_sync_status(this, static_cast<rgw::sal::RadosStore*>(store), pipe, bucket->get_info(), nullptr, &status);
9f95a23c 864
f67539c2 865 if (op_ret < 0) {
b3b6e05e 866 ldpp_dout(this, -1) << "ERROR: rgw_bucket_sync_status() on pipe=" << pipe << " returned ret=" << op_ret << dendl;
9f95a23c
TL
867 }
868 return;
869 }
870
871 rgw_zone_id source_zone_id(source_zone);
872
873 RGWBucketSyncPolicyHandlerRef source_handler;
20effc67 874 op_ret = store->get_sync_policy_handler(s, source_zone_id, source_bucket, &source_handler, y);
f67539c2 875 if (op_ret < 0) {
b3b6e05e 876 ldpp_dout(this, -1) << "could not get bucket sync policy handler (r=" << op_ret << ")" << dendl;
9f95a23c
TL
877 return;
878 }
879
880 auto local_dests = source_handler->get_all_dests_in_zone(local_zone_id);
881
882 std::vector<rgw_bucket_shard_sync_info> current_status;
883 for (auto& entry : local_dests) {
884 auto pipe = entry.second;
885
b3b6e05e 886 ldpp_dout(this, 20) << "RGWOp_BILog_Status::execute(optional_yield y): getting sync status for pipe=" << pipe << dendl;
9f95a23c 887
20effc67 888 RGWBucketInfo *pinfo = &bucket->get_info();
9f95a23c
TL
889 std::optional<RGWBucketInfo> opt_dest_info;
890
891 if (!pipe.dest.bucket) {
892 /* Uh oh, something went wrong */
b3b6e05e 893 ldpp_dout(this, 20) << "ERROR: RGWOp_BILog_Status::execute(optional_yield y): BUG: pipe.dest.bucket was not initialized" << pipe << dendl;
f67539c2 894 op_ret = -EIO;
9f95a23c
TL
895 return;
896 }
897
20effc67 898 if (*pipe.dest.bucket != pinfo->bucket) {
9f95a23c 899 opt_dest_info.emplace();
20effc67
TL
900 std::unique_ptr<rgw::sal::Bucket> dest_bucket;
901 op_ret = store->get_bucket(s, nullptr, *pipe.dest.bucket, &dest_bucket, y);
f67539c2 902 if (op_ret < 0) {
b3b6e05e 903 ldpp_dout(this, 4) << "failed to read target bucket info (bucket=: " << cpp_strerror(op_ret) << dendl;
9f95a23c
TL
904 return;
905 }
906
20effc67
TL
907 *opt_dest_info = dest_bucket->get_info();
908 pinfo = &(*opt_dest_info);
9f95a23c
TL
909 pipe.dest.bucket = pinfo->bucket;
910 }
911
20effc67 912 int r = rgw_bucket_sync_status(this, static_cast<rgw::sal::RadosStore*>(store), pipe, *pinfo, &bucket->get_info(), &current_status);
9f95a23c 913 if (r < 0) {
b3b6e05e 914 ldpp_dout(this, -1) << "ERROR: rgw_bucket_sync_status() on pipe=" << pipe << " returned ret=" << r << dendl;
f67539c2 915 op_ret = r;
9f95a23c
TL
916 return;
917 }
918
919 if (status.empty()) {
920 status = std::move(current_status);
921 } else {
922 if (current_status.size() !=
923 status.size()) {
f67539c2 924 op_ret = -EINVAL;
b3b6e05e 925 ldpp_dout(this, -1) << "ERROR: different number of shards for sync status of buckets syncing from the same source: status.size()= " << status.size() << " current_status.size()=" << current_status.size() << dendl;
9f95a23c
TL
926 return;
927 }
928 auto m = status.begin();
929 for (auto& cur_shard_status : current_status) {
930 auto& result_shard_status = *m++;
931 // always take the first marker, or any later marker that's smaller
932 if (cur_shard_status.inc_marker.position < result_shard_status.inc_marker.position) {
933 result_shard_status = std::move(cur_shard_status);
934 }
935 }
936 }
937 }
b32b8144
FG
938}
939
940void RGWOp_BILog_Status::send_response()
941{
f67539c2 942 set_req_state_err(s, op_ret);
b32b8144
FG
943 dump_errno(s);
944 end_header(s);
945
f67539c2 946 if (op_ret >= 0) {
b32b8144
FG
947 encode_json("status", status, s->formatter);
948 }
949 flusher.flush();
950}
951
7c673cae
FG
952// not in header to avoid pulling in rgw_data_sync.h
953class RGWOp_DATALog_Status : public RGWRESTOp {
954 rgw_data_sync_status status;
955public:
9f95a23c 956 int check_caps(const RGWUserCaps& caps) override {
7c673cae
FG
957 return caps.check_cap("datalog", RGW_CAP_READ);
958 }
f67539c2 959 int verify_permission(optional_yield y) override {
9f95a23c 960 return check_caps(s->user->get_caps());
7c673cae 961 }
f67539c2 962 void execute(optional_yield y) override ;
7c673cae 963 void send_response() override;
11fdf7f2 964 const char* name() const override { return "get_data_changes_log_status"; }
7c673cae
FG
965};
966
f67539c2 967void RGWOp_DATALog_Status::execute(optional_yield y)
7c673cae
FG
968{
969 const auto source_zone = s->info.args.get("source-zone");
20effc67 970 auto sync = store->get_data_sync_manager(source_zone);
7c673cae 971 if (sync == nullptr) {
b3b6e05e 972 ldpp_dout(this, 1) << "no sync manager for source-zone " << source_zone << dendl;
f67539c2 973 op_ret = -ENOENT;
7c673cae
FG
974 return;
975 }
b3b6e05e 976 op_ret = sync->read_sync_status(this, &status);
7c673cae
FG
977}
978
979void RGWOp_DATALog_Status::send_response()
980{
f67539c2 981 set_req_state_err(s, op_ret);
7c673cae
FG
982 dump_errno(s);
983 end_header(s);
984
f67539c2 985 if (op_ret >= 0) {
7c673cae
FG
986 encode_json("status", status, s->formatter);
987 }
988 flusher.flush();
989}
990
991
992RGWOp *RGWHandler_Log::op_get() {
993 bool exists;
994 string type = s->info.args.get("type", &exists);
995
996 if (!exists) {
997 return NULL;
998 }
999
1000 if (type.compare("metadata") == 0) {
1001 if (s->info.args.exists("id")) {
1002 if (s->info.args.exists("info")) {
1003 return new RGWOp_MDLog_ShardInfo;
1004 } else {
1005 return new RGWOp_MDLog_List;
1006 }
1007 } else if (s->info.args.exists("status")) {
1008 return new RGWOp_MDLog_Status;
1009 } else {
1010 return new RGWOp_MDLog_Info;
1011 }
1012 } else if (type.compare("bucket-index") == 0) {
1013 if (s->info.args.exists("info")) {
1014 return new RGWOp_BILog_Info;
b32b8144
FG
1015 } else if (s->info.args.exists("status")) {
1016 return new RGWOp_BILog_Status;
7c673cae
FG
1017 } else {
1018 return new RGWOp_BILog_List;
1019 }
1020 } else if (type.compare("data") == 0) {
1021 if (s->info.args.exists("id")) {
1022 if (s->info.args.exists("info")) {
1023 return new RGWOp_DATALog_ShardInfo;
1024 } else {
1025 return new RGWOp_DATALog_List;
1026 }
1027 } else if (s->info.args.exists("status")) {
1028 return new RGWOp_DATALog_Status;
1029 } else {
1030 return new RGWOp_DATALog_Info;
1031 }
1032 }
1033 return NULL;
1034}
1035
1036RGWOp *RGWHandler_Log::op_delete() {
1037 bool exists;
1038 string type = s->info.args.get("type", &exists);
1039
1040 if (!exists) {
1041 return NULL;
1042 }
1043
1044 if (type.compare("metadata") == 0)
1045 return new RGWOp_MDLog_Delete;
1046 else if (type.compare("bucket-index") == 0)
1047 return new RGWOp_BILog_Delete;
1048 else if (type.compare("data") == 0)
1049 return new RGWOp_DATALog_Delete;
1050 return NULL;
1051}
1052
1053RGWOp *RGWHandler_Log::op_post() {
1054 bool exists;
1055 string type = s->info.args.get("type", &exists);
1056
1057 if (!exists) {
1058 return NULL;
1059 }
1060
1061 if (type.compare("metadata") == 0) {
1062 if (s->info.args.exists("lock"))
1063 return new RGWOp_MDLog_Lock;
1064 else if (s->info.args.exists("unlock"))
1065 return new RGWOp_MDLog_Unlock;
1066 else if (s->info.args.exists("notify"))
1067 return new RGWOp_MDLog_Notify;
1068 } else if (type.compare("data") == 0) {
9f95a23c 1069 if (s->info.args.exists("notify"))
7c673cae
FG
1070 return new RGWOp_DATALog_Notify;
1071 }
1072 return NULL;
1073}
1074