Skip to content

Commit 53ba9b1

Browse files
committed
rgw/logging: make unique part of log file both random and incremental
new format will be: 10 char incremental count (so 32bit uint fit in it). and 6 char alphanumeric random part. this should fix possible race conditions in case of multisite Fixes: https://tracker.ceph.com/issues/71608 Signed-off-by: Yuval Lifshitz <[email protected]> (cherry picked from commit fa2bc49) Resolves: rhbz#2373177
1 parent 8b5c30e commit 53ba9b1

File tree

2 files changed

+32
-18
lines changed

2 files changed

+32
-18
lines changed

doc/radosgw/bucket_logging.rst

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ 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
29+
- The 16 byte unique ID part of the log object name is a lexicographically ordered random string,
30+
that consists of a 10 bytes counter, and a 6 bytes random alphanumeric string.
31+
or a random, alphanumeric string if the counter is not available
3132

3233

3334
.. toctree::
@@ -84,12 +85,17 @@ The following operation are supported in journal mode:
8485
| ``DeleteObjectTagging`` | ``REST.DELETE.OBJECT_TAGGING`` | No |
8586
+-------------------------------+-------------------------------------+-----------------+
8687

88+
Multisite
89+
`````````
90+
In a multi-zone deployment, each zone will use its own log object before the log object is added to the log bucket.
91+
After the log object is added to the log bucket (e.g after being flushed) it will be replicated to other zones.
92+
This means that for a given time period there could be more than one log object holding relevant log records.
8793

8894
Bucket Logging Policy
8995
---------------------
9096
On the source bucket, only its owner is allowed to enable or disable bucket logging.
9197
For a bucket to be used as a log bucket, it must have bucket policy that allows that (even if the source bucket and the log bucket are owned by the same user or account).
92-
The bucket policy must allow the `s3:PutObject` action for the log bucket, to be perfomed by the `logging.s3.amazonaws.com` service principal.
98+
The bucket policy must allow the `s3:PutObject` action for the log bucket, to be performed by the `logging.s3.amazonaws.com` service principal.
9399
It should also specify the source bucket and account that are expected to write logs to it. For example:
94100

95101
::
@@ -145,7 +151,7 @@ For example:
145151

146152
::
147153

148-
fish/2024-08-06-09-40-09-TI9ROKN05DD4HPQF
154+
fish/2024-08-06-09-40-09-0000000002AGQ6W1
149155

150156
Partitioned
151157
```````````
@@ -159,7 +165,7 @@ For example:
159165

160166
::
161167

162-
fish/testid/default/fish-bucket/2024/08/06/2024-08-06-10-11-18-0000000000000002
168+
fish/testid/default/fish-bucket/2024/08/06/2024-08-06-10-11-18-0000000011D1FGPA
163169

164170
Log Records
165171
~~~~~~~~~~~

src/rgw/rgw_bucket_logging.cc

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ std::string configuration::to_json_str() const {
174174

175175
// create a random string of N characters
176176
template<size_t N>
177-
std::string unique_string() {
177+
std::string random_string() {
178178
static const std::string possible_characters{"0123456789ABCDEFGHIJKLMNOPQRSTUVWXY"};
179179
static const auto max_possible_value = possible_characters.length() - 1;
180180
std::random_device rd;
@@ -185,28 +185,36 @@ std::string unique_string() {
185185
return str;
186186
}
187187

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>
188+
// create a string that start with an incremenatl counter
189+
// of INC charecters and ends with a random string of RND characters
190+
// fallback to a random string of INC+RND characters
191+
template<size_t INC, size_t RND>
191192
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+
static const auto format = fmt::format("{{:0>{}}}{{}}", INC);
194+
uint32_t counter = 0;
193195
if (!old_name) {
194-
return std::string(N, '0');
196+
const auto random_part = random_string<RND>();
197+
return fmt::vformat(format, fmt::make_format_args(counter, random_part));
195198
}
196-
const auto str_counter = old_name->substr(old_name->length() - N+1, N);
199+
const auto str_counter = old_name->substr(old_name->length() - (INC+RND), INC);
197200
try {
198-
auto counter = boost::lexical_cast<unsigned long>(str_counter);
201+
counter = boost::lexical_cast<uint32_t>(str_counter);
202+
// we are not concerned about overflow here, as the counter is only used to
203+
// distinguish between different logging objects created in the same second
199204
++counter;
200-
static const auto format = fmt::format("{{:0>{}}}", N);
201-
return fmt::vformat(format, fmt::make_format_args(counter));
205+
const auto random_part = random_string<RND>();
206+
return fmt::vformat(format, fmt::make_format_args(counter, random_part));
202207
} catch (const boost::bad_lexical_cast& e) {
203208
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>();
209+
"' to counter. " << e.what() << ". will create random temporary logging file name" << dendl;
210+
return random_string<INC+RND>();
206211
}
207212
}
208213

209214
constexpr size_t UniqueStringLength = 16;
215+
// we need 10 characters for the counter (uint32_t)
216+
constexpr size_t CounterStringLength = 10;
217+
constexpr size_t RandomStringLength = UniqueStringLength - CounterStringLength;
210218

211219
ceph::coarse_real_time time_from_name(const std::string& obj_name, const DoutPrefixProvider *dpp) {
212220
static const auto time_format_length = std::string{"YYYY-MM-DD-hh-mm-ss"}.length();
@@ -250,7 +258,7 @@ int new_logging_object(const configuration& conf,
250258
std::tm t{};
251259
localtime_r(&tt, &t);
252260

253-
const auto unique = incremental_string<UniqueStringLength>(dpp, old_name);
261+
const auto unique = incremental_string<CounterStringLength, RandomStringLength>(dpp, old_name);
254262

255263
switch (conf.obj_key_format) {
256264
case KeyFormat::Simple:

0 commit comments

Comments
 (0)