Skip to content

Commit c71d7ee

Browse files
authored
Merge pull request ceph#63264 from yuvalif/wip-yuval-71308
rgw/logging: Make unique portion of log object name ordered
2 parents 62fba6c + 198fa75 commit c71d7ee

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

doc/radosgw/bucket_logging.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ in different objects in the log bucket.
2626
- Source and log bucket must be in the same zonegroup
2727
- Source and log buckets may belong to different accounts (with proper bucket policy set)
2828
- The log bucket may have object lock enabled with default retention period
29+
- The 16 bit unique ID part of the log object name is an incrementing counter, or a random,
30+
alphanumeric string if the counter is not available
2931

3032

3133
.. toctree::
@@ -157,7 +159,7 @@ For example:
157159

158160
::
159161

160-
fish/testid//all-log/2024/08/06/2024-08-06-10-11-18-1HMU3UMWOJKNQJ0X
162+
fish/testid//all-log/2024/08/06/2024-08-06-10-11-18-0000000000000002
161163

162164
Log Records
163165
~~~~~~~~~~~

src/rgw/rgw_bucket_logging.cc

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "rgw_sal.h"
1010
#include "rgw_op.h"
1111
#include "rgw_auth_s3.h"
12+
#include <boost/lexical_cast.hpp>
1213

1314
#define dout_subsys ceph_subsys_rgw
1415

@@ -171,6 +172,7 @@ std::string configuration::to_json_str() const {
171172
return ss.str();
172173
}
173174

175+
// create a random string of N characters
174176
template<size_t N>
175177
std::string unique_string() {
176178
static const std::string possible_characters{"0123456789ABCDEFGHIJKLMNOPQRSTUVWXY"};
@@ -183,6 +185,27 @@ std::string unique_string() {
183185
return str;
184186
}
185187

188+
// create an incremental string of N characters if possible
189+
// fallback to a random string of N characters if not
190+
template<size_t N>
191+
std::string incremental_string(const DoutPrefixProvider *dpp, std::optional<std::string> old_name) {
192+
// for the fist time we create a string of zeros
193+
if (!old_name) {
194+
return std::string(N, '0');
195+
}
196+
const auto str_counter = old_name->substr(old_name->length() - N+1, N);
197+
try {
198+
auto counter = boost::lexical_cast<unsigned long>(str_counter);
199+
++counter;
200+
static const auto format = fmt::format("{{:0>{}}}", N);
201+
return fmt::vformat(format, fmt::make_format_args(counter));
202+
} catch (const boost::bad_lexical_cast& e) {
203+
ldpp_dout(dpp, 5) << "WARNING: failed to convert string '" << str_counter <<
204+
"' to counter. " <<e.what() << ". will create random temporary logging file name" << dendl;
205+
return unique_string<N>();
206+
}
207+
}
208+
186209
constexpr size_t UniqueStringLength = 16;
187210

188211
ceph::coarse_real_time time_from_name(const std::string& obj_name, const DoutPrefixProvider *dpp) {
@@ -220,13 +243,13 @@ int new_logging_object(const configuration& conf,
220243
std::string& obj_name,
221244
const DoutPrefixProvider *dpp,
222245
optional_yield y,
223-
bool init_obj,
246+
std::optional<std::string> old_name,
224247
RGWObjVersionTracker* objv_tracker) {
225248
const auto tt = ceph::coarse_real_time::clock::to_time_t(ceph::coarse_real_time::clock::now());
226249
std::tm t{};
227250
localtime_r(&tt, &t);
228251

229-
const auto unique = unique_string<UniqueStringLength>();
252+
const auto unique = incremental_string<UniqueStringLength>(dpp, old_name);
230253

231254
switch (conf.obj_key_format) {
232255
case KeyFormat::Simple:
@@ -251,7 +274,7 @@ int new_logging_object(const configuration& conf,
251274
break;
252275
}
253276
const auto& target_bucket_id = target_bucket->get_key();
254-
int ret = target_bucket->set_logging_object_name(obj_name, conf.target_prefix, y, dpp, init_obj, objv_tracker);
277+
int ret = target_bucket->set_logging_object_name(obj_name, conf.target_prefix, y, dpp, (old_name == std::nullopt), objv_tracker);
255278
if (ret == -EEXIST || ret == -ECANCELED) {
256279
if (ret = target_bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, nullptr); ret < 0) {
257280
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of bucket '" <<
@@ -330,7 +353,7 @@ int rollover_logging_object(const configuration& conf,
330353
return -EINVAL;
331354
}
332355
const auto old_obj = obj_name;
333-
const int ret = new_logging_object(conf, target_bucket, obj_name, dpp, y, false, objv_tracker);
356+
const int ret = new_logging_object(conf, target_bucket, obj_name, dpp, y, old_obj, objv_tracker);
334357
if (ret == -ECANCELED) {
335358
ldpp_dout(dpp, 20) << "INFO: rollover already performed for object '" << old_obj << "' to logging bucket '" <<
336359
target_bucket->get_key() << "'. ret = " << ret << dendl;
@@ -455,7 +478,7 @@ int log_record(rgw::sal::Driver* driver,
455478
}
456479
} else if (ret == -ENOENT) {
457480
// try to create the temporary log object for the first time
458-
ret = new_logging_object(conf, target_bucket, obj_name, dpp, y, true, nullptr);
481+
ret = new_logging_object(conf, target_bucket, obj_name, dpp, y, std::nullopt, nullptr);
459482
if (ret == 0) {
460483
ldpp_dout(dpp, 20) << "INFO: first time logging for bucket '" << target_bucket_id << "' and prefix '" <<
461484
conf.target_prefix << "'" << dendl;

0 commit comments

Comments
 (0)