From: Adam C. Emerson Date: Sat, 23 Jan 2021 01:48:39 +0000 (-0500) Subject: rgw: Add and trim datalog generations X-Git-Tag: v16.2.2~8^2~9^2~12 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=f1e2564d952c9300dedcf017c3cf869ef6bf8ec8;p=ceph.git rgw: Add and trim datalog generations This lets us actually change type in mid-stream. Signed-off-by: Adam C. Emerson (cherry picked from commit 32b100d797cdf88648530e0162fd103cf279df31) Signed-off-by: Adam C. Emerson --- diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index f0da7b9573a1c..33c8eae5725be 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -244,6 +244,7 @@ void usage() cout << " datalog list list data log\n"; cout << " datalog trim trim data log\n"; cout << " datalog status read data log status\n"; + cout << " datalog type change datalog type to --log_type={fifo,omap}\n"; cout << " orphans find deprecated -- init and run search for leaked rados objects (use job-id, pool)\n"; cout << " orphans finish deprecated -- clean up search for leaked rados objects\n"; cout << " orphans list-jobs deprecated -- list the current job-ids for orphans search\n"; @@ -720,6 +721,8 @@ enum class OPT { DATALOG_STATUS, DATALOG_AUTOTRIM, DATALOG_TRIM, + DATALOG_TYPE, + DATALOG_PRUNE, REALM_CREATE, REALM_DELETE, REALM_GET, @@ -930,6 +933,8 @@ static SimpleCmd::Commands all_cmds = { { "datalog status", OPT::DATALOG_STATUS }, { "datalog autotrim", OPT::DATALOG_AUTOTRIM }, { "datalog trim", OPT::DATALOG_TRIM }, + { "datalog type", OPT::DATALOG_TYPE }, + { "datalog prune", OPT::DATALOG_PRUNE }, { "realm create", OPT::REALM_CREATE }, { "realm delete", OPT::REALM_DELETE }, { "realm get", OPT::REALM_GET }, @@ -1020,6 +1025,15 @@ BIIndexType get_bi_index_type(const string& type_str) { return BIIndexType::Invalid; } +log_type get_log_type(const string& type_str) { + if (strcasecmp(type_str.c_str(), "fifo") == 0) + return log_type::fifo; + if (strcasecmp(type_str.c_str(), "omap") == 0) + return log_type::omap; + + return static_cast(0xff); +} + void dump_bi_entry(bufferlist& bl, BIIndexType index_type, Formatter *formatter) { auto iter = bl.cbegin(); @@ -3145,6 +3159,7 @@ int main(int argc, const char **argv) uint64_t min_rewrite_stripe_size = 0; BIIndexType bi_index_type = BIIndexType::Plain; + std::optional opt_log_type; string job_id; int num_shards = 0; @@ -3467,6 +3482,14 @@ int main(int argc, const char **argv) cerr << "ERROR: invalid bucket index entry type" << std::endl; return EINVAL; } + } else if (ceph_argparse_witharg(args, i, &val, "--log-type", (char*)NULL)) { + string log_type_str = val; + auto l = get_log_type(log_type_str); + if (l == static_cast(0xff)) { + cerr << "ERROR: invalid log type" << std::endl; + return EINVAL; + } + opt_log_type = l; } else if (ceph_argparse_binary_flag(args, i, &is_master_int, NULL, "--master", (char*)NULL)) { is_master = (bool)is_master_int; is_master_set = true; @@ -8850,6 +8873,36 @@ next: } } + if (opt_cmd == OPT::DATALOG_TYPE) { + if (!opt_log_type) { + std::cerr << "log-type not specified." << std::endl; + return -EINVAL; + } + auto datalog = static_cast(store)->svc()->datalog_rados; + ret = datalog->change_format(*opt_log_type, null_yield); + if (ret < 0) { + cerr << "ERROR: change_format(): " << cpp_strerror(-ret) << std::endl; + return -ret; + } + } + + if (opt_cmd == OPT::DATALOG_PRUNE) { + auto datalog = static_cast(store)->svc()->datalog_rados; + std::optional through; + ret = datalog->trim_generations(through); + + if (ret < 0) { + cerr << "ERROR: trim_generations(): " << cpp_strerror(-ret) << std::endl; + return -ret; + } + + if (through) { + std::cout << "Pruned " << *through << " empty generations." << std::endl; + } else { + std::cout << "No empty generations." << std::endl; + } + } + bool quota_op = (opt_cmd == OPT::QUOTA_SET || opt_cmd == OPT::QUOTA_ENABLE || opt_cmd == OPT::QUOTA_DISABLE); if (quota_op) { diff --git a/src/rgw/rgw_datalog.cc b/src/rgw/rgw_datalog.cc index c64b22d518a9f..6182ae91909e4 100644 --- a/src/rgw/rgw_datalog.cc +++ b/src/rgw/rgw_datalog.cc @@ -202,6 +202,29 @@ public: std::string_view max_marker() const override { return "99999999"sv; } + int is_empty() override { + for (auto shard = 0u; shard < oids.size(); ++shard) { + std::list log_entries; + lr::ObjectReadOperation op; + std::string out_marker; + bool truncated; + cls_log_list(op, {}, {}, {}, 1, log_entries, &out_marker, &truncated); + auto r = rgw_rados_operate(ioctx, oids[shard], &op, nullptr, null_yield); + if (r == -ENOENT) { + continue; + } + if (r < 0) { + lderr(cct) << __PRETTY_FUNCTION__ + << ": failed to list " << oids[shard] + << cpp_strerror(-r) << dendl; + return r; + } + if (!log_entries.empty()) { + return 0; + } + } + return 1; + } }; class RGWDataChangesFIFO final : public RGWDataChangesBE { @@ -344,6 +367,24 @@ public: rgw::cls::fifo::marker::max().to_string(); return std::string_view(mm); } + int is_empty() override { + std::vector log_entries; + bool more = false; + for (auto shard = 0u; shard < fifos.size(); ++shard) { + auto r = fifos[shard]->list(1, {}, &log_entries, &more, + null_yield); + if (r < 0) { + lderr(cct) << __PRETTY_FUNCTION__ + << ": unable to list FIFO: " << get_oid(shard) + << ": " << cpp_strerror(-r) << dendl; + return r; + } + if (!log_entries.empty()) { + return 0; + } + } + return 1; + } }; RGWDataChangesLog::RGWDataChangesLog(CephContext* cct) @@ -781,7 +822,7 @@ public: GenTrim(DataLogBackends* bes, int shard_id, uint64_t target_gen, std::string cursor, uint64_t head_gen, uint64_t tail_gen, - boost::intrusive_ptr&& be, + boost::intrusive_ptr be, lr::AioCompletion* super) : Completion(super), bes(bes), shard_id(shard_id), target_gen(target_gen), cursor(std::move(cursor)), head_gen(head_gen), tail_gen(tail_gen), @@ -792,6 +833,7 @@ public: be.reset(); if (r == -ENOENT) r = -ENODATA; if (r == -ENODATA && gen_id < target_gen) r = 0; + r = 0; if (r < 0) { complete(std::move(p), r); return; @@ -808,7 +850,7 @@ public: be = i->second; } auto c = be->gen_id == target_gen ? cursor : be->max_marker(); - r = be->trim(shard_id, c, call(std::move(p))); + be->trim(shard_id, c, call(std::move(p))); } }; @@ -821,19 +863,58 @@ void DataLogBackends::trim_entries(int shard_id, std::string_view marker, const auto tail_gen = begin()->first; if (target_gen < tail_gen) { l.unlock(); - rgw_complete_aio_completion(c, 0); + rgw_complete_aio_completion(c, -ENODATA); return; } - auto be = lower_bound(0)->second; + auto be = begin()->second; l.unlock(); - auto p = be.get(); auto gt = std::make_unique(this, shard_id, target_gen, std::string(cursor), head_gen, tail_gen, - std::move(be), c); + be, c); + + auto cc = be->gen_id == target_gen ? cursor : be->max_marker(); + be->trim(shard_id, cc, GenTrim::call(std::move(gt))); +} + +int DataLogBackends::trim_generations(std::optional& through) { + if (size() == 1) { + return 0; + } - p->trim(shard_id, cursor, GenTrim::call(std::move(gt))); + std::vector candidates; + { + std::scoped_lock l(m); + auto e = cend() - 1; + for (auto i = cbegin(); i < e; ++i) { + candidates.push_back(i->second); + } + } + + std::optional highest; + for (auto& be : candidates) { + auto r = be->is_empty(); + if (r < 0) { + return r; + } else if (r == 1) { + highest = be->gen_id; + } else { + break; + } + } + + through = highest; + if (!highest) { + return 0; + } + auto ec = empty_to(*highest, null_yield); + if (ec) { + return ceph::from_error_code(ec); + } + + return ceph::from_error_code(remove_empty(null_yield)); } + int RGWDataChangesLog::trim_entries(int shard_id, std::string_view marker, librados::AioCompletion* c) { @@ -897,3 +978,11 @@ std::string RGWDataChangesLog::max_marker() const { return gencursor(std::numeric_limits::max(), "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); } + +int RGWDataChangesLog::change_format(log_type type, optional_yield y) { + return ceph::from_error_code(bes->new_backing(type, y)); +} + +int RGWDataChangesLog::trim_generations(std::optional& through) { + return bes->trim_generations(through); +} diff --git a/src/rgw/rgw_datalog.h b/src/rgw/rgw_datalog.h index e9a768d546c00..5886d51dac174 100644 --- a/src/rgw/rgw_datalog.h +++ b/src/rgw/rgw_datalog.h @@ -160,6 +160,8 @@ public: bs::error_code handle_init(entries_t e) noexcept override; bs::error_code handle_new_gens(entries_t e) noexcept override; bs::error_code handle_empty_to(uint64_t new_tail) noexcept override; + + int trim_generations(std::optional& through); }; class RGWDataChangesLog { @@ -262,6 +264,10 @@ public: // a marker that compares greater than any other std::string max_marker() const; std::string get_oid(uint64_t gen_id, int shard_id) const; + + + int change_format(log_type type, optional_yield y); + int trim_generations(std::optional& through); }; class RGWDataChangesBE : public boost::intrusive_ref_counter { @@ -303,6 +309,8 @@ public: virtual int trim(int index, std::string_view marker, librados::AioCompletion* c) = 0; virtual std::string_view max_marker() const = 0; + // 1 on empty, 0 on non-empty, negative on error. + virtual int is_empty() = 0; }; diff --git a/src/test/cli/radosgw-admin/help.t b/src/test/cli/radosgw-admin/help.t index 490499f24a029..c63c63cb55e2c 100644 --- a/src/test/cli/radosgw-admin/help.t +++ b/src/test/cli/radosgw-admin/help.t @@ -138,6 +138,7 @@ datalog list list data log datalog trim trim data log datalog status read data log status + datalog type change datalog type to --log_type={fifo,omap} orphans find deprecated -- init and run search for leaked rados objects (use job-id, pool) orphans finish deprecated -- clean up search for leaked rados objects orphans list-jobs deprecated -- list the current job-ids for orphans search