]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/driver/rados/config/period.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / driver / rados / config / period.cc
1 // vim: ts=8 sw=2 smarttab ft=cpp
2
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2022 Red Hat, Inc.
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "common/dout.h"
16 #include "common/errno.h"
17 #include "rgw_zone.h"
18 #include "driver/rados/config/store.h"
19
20 #include "impl.h"
21
22 namespace rgw::rados {
23
24 // period oids
25 constexpr std::string_view period_info_oid_prefix = "periods.";
26 constexpr std::string_view period_latest_epoch_info_oid = ".latest_epoch";
27 constexpr std::string_view period_staging_suffix = ":staging";
28
29 static std::string period_oid(std::string_view period_id, uint32_t epoch)
30 {
31 // omit the epoch for the staging period
32 if (period_id.ends_with(period_staging_suffix)) {
33 return string_cat_reserve(period_info_oid_prefix, period_id);
34 }
35 return fmt::format("{}{}.{}", period_info_oid_prefix, period_id, epoch);
36 }
37
38 static std::string latest_epoch_oid(const ceph::common::ConfigProxy& conf,
39 std::string_view period_id)
40 {
41 return string_cat_reserve(
42 period_info_oid_prefix, period_id,
43 name_or_default(conf->rgw_period_latest_epoch_info_oid,
44 period_latest_epoch_info_oid));
45 }
46
47 static int read_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y,
48 ConfigImpl* impl, std::string_view period_id,
49 uint32_t& epoch, RGWObjVersionTracker* objv)
50 {
51 const auto& pool = impl->period_pool;
52 const auto latest_oid = latest_epoch_oid(dpp->get_cct()->_conf, period_id);
53 RGWPeriodLatestEpochInfo latest;
54 int r = impl->read(dpp, y, pool, latest_oid, latest, objv);
55 if (r >= 0) {
56 epoch = latest.epoch;
57 }
58 return r;
59 }
60
61 static int write_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y,
62 ConfigImpl* impl, bool exclusive,
63 std::string_view period_id, uint32_t epoch,
64 RGWObjVersionTracker* objv)
65 {
66 const auto& pool = impl->period_pool;
67 const auto latest_oid = latest_epoch_oid(dpp->get_cct()->_conf, period_id);
68 const auto create = exclusive ? Create::MustNotExist : Create::MayExist;
69 RGWPeriodLatestEpochInfo latest{epoch};
70 return impl->write(dpp, y, pool, latest_oid, create, latest, objv);
71 }
72
73 static int delete_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y,
74 ConfigImpl* impl, std::string_view period_id,
75 RGWObjVersionTracker* objv)
76 {
77 const auto& pool = impl->period_pool;
78 const auto latest_oid = latest_epoch_oid(dpp->get_cct()->_conf, period_id);
79 return impl->remove(dpp, y, pool, latest_oid, objv);
80 }
81
82 static int update_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y,
83 ConfigImpl* impl, std::string_view period_id,
84 uint32_t epoch)
85 {
86 static constexpr int MAX_RETRIES = 20;
87
88 for (int i = 0; i < MAX_RETRIES; i++) {
89 uint32_t existing_epoch = 0;
90 RGWObjVersionTracker objv;
91 bool exclusive = false;
92
93 // read existing epoch
94 int r = read_latest_epoch(dpp, y, impl, period_id, existing_epoch, &objv);
95 if (r == -ENOENT) {
96 // use an exclusive create to set the epoch atomically
97 exclusive = true;
98 objv.generate_new_write_ver(dpp->get_cct());
99 ldpp_dout(dpp, 20) << "creating initial latest_epoch=" << epoch
100 << " for period=" << period_id << dendl;
101 } else if (r < 0) {
102 ldpp_dout(dpp, 0) << "ERROR: failed to read latest_epoch" << dendl;
103 return r;
104 } else if (epoch <= existing_epoch) {
105 r = -EEXIST; // fail with EEXIST if epoch is not newer
106 ldpp_dout(dpp, 10) << "found existing latest_epoch " << existing_epoch
107 << " >= given epoch " << epoch << ", returning r=" << r << dendl;
108 return r;
109 } else {
110 ldpp_dout(dpp, 20) << "updating latest_epoch from " << existing_epoch
111 << " -> " << epoch << " on period=" << period_id << dendl;
112 }
113
114 r = write_latest_epoch(dpp, y, impl, exclusive, period_id, epoch, &objv);
115 if (r == -EEXIST) {
116 continue; // exclusive create raced with another update, retry
117 } else if (r == -ECANCELED) {
118 continue; // write raced with a conflicting version, retry
119 }
120 if (r < 0) {
121 ldpp_dout(dpp, 0) << "ERROR: failed to write latest_epoch" << dendl;
122 return r;
123 }
124 return 0; // return success
125 }
126
127 return -ECANCELED; // fail after max retries
128 }
129
130 int RadosConfigStore::create_period(const DoutPrefixProvider* dpp,
131 optional_yield y, bool exclusive,
132 const RGWPeriod& info)
133 {
134 if (info.get_id().empty()) {
135 ldpp_dout(dpp, 0) << "period cannot have an empty id" << dendl;
136 return -EINVAL;
137 }
138 if (info.get_epoch() == 0) {
139 ldpp_dout(dpp, 0) << "period cannot have an empty epoch" << dendl;
140 return -EINVAL;
141 }
142 const auto& pool = impl->period_pool;
143 const auto info_oid = period_oid(info.get_id(), info.get_epoch());
144 const auto create = exclusive ? Create::MustNotExist : Create::MayExist;
145 RGWObjVersionTracker objv;
146 objv.generate_new_write_ver(dpp->get_cct());
147 int r = impl->write(dpp, y, pool, info_oid, create, info, &objv);
148 if (r < 0) {
149 return r;
150 }
151
152 (void) update_latest_epoch(dpp, y, impl.get(), info.get_id(), info.get_epoch());
153 return 0;
154 }
155
156 int RadosConfigStore::read_period(const DoutPrefixProvider* dpp,
157 optional_yield y,
158 std::string_view period_id,
159 std::optional<uint32_t> epoch,
160 RGWPeriod& info)
161 {
162 int r = 0;
163 if (!epoch) {
164 epoch = 0;
165 r = read_latest_epoch(dpp, y, impl.get(), period_id, *epoch, nullptr);
166 if (r < 0) {
167 return r;
168 }
169 }
170
171 const auto& pool = impl->period_pool;
172 const auto info_oid = period_oid(period_id, *epoch);
173 return impl->read(dpp, y, pool, info_oid, info, nullptr);
174 }
175
176 int RadosConfigStore::delete_period(const DoutPrefixProvider* dpp,
177 optional_yield y,
178 std::string_view period_id)
179 {
180 const auto& pool = impl->period_pool;
181
182 // read the latest_epoch
183 uint32_t latest_epoch = 0;
184 RGWObjVersionTracker latest_objv;
185 int r = read_latest_epoch(dpp, y, impl.get(), period_id,
186 latest_epoch, &latest_objv);
187 if (r < 0 && r != -ENOENT) { // just delete epoch=0 on ENOENT
188 ldpp_dout(dpp, 0) << "failed to read latest epoch for period "
189 << period_id << ": " << cpp_strerror(r) << dendl;
190 return r;
191 }
192
193 for (uint32_t epoch = 0; epoch <= latest_epoch; epoch++) {
194 const auto info_oid = period_oid(period_id, epoch);
195 r = impl->remove(dpp, y, pool, info_oid, nullptr);
196 if (r < 0 && r != -ENOENT) { // ignore ENOENT
197 ldpp_dout(dpp, 0) << "failed to delete period " << info_oid
198 << ": " << cpp_strerror(r) << dendl;
199 return r;
200 }
201 }
202
203 return delete_latest_epoch(dpp, y, impl.get(), period_id, &latest_objv);
204 }
205
206 int RadosConfigStore::list_period_ids(const DoutPrefixProvider* dpp,
207 optional_yield y,
208 const std::string& marker,
209 std::span<std::string> entries,
210 sal::ListResult<std::string>& result)
211 {
212 const auto& pool = impl->period_pool;
213 constexpr auto prefix = [] (std::string oid) -> std::string {
214 if (!oid.starts_with(period_info_oid_prefix)) {
215 return {};
216 }
217 if (!oid.ends_with(period_latest_epoch_info_oid)) {
218 return {};
219 }
220 // trim the prefix and suffix
221 const std::size_t count = oid.size() -
222 period_info_oid_prefix.size() -
223 period_latest_epoch_info_oid.size();
224 return oid.substr(period_info_oid_prefix.size(), count);
225 };
226
227 return impl->list(dpp, y, pool, marker, prefix, entries, result);
228 }
229
230 } // namespace rgw::rados