Skip to content

Commit fcfc50b

Browse files
committed
rgw/logging: clean pending objects
* when source bucket is deleted * when logging is disabled * when logging conf changes * when target bucket is deleted also add "bucket logging info" admin command returning logging conf for source bucket, and list of source buckets for log bucket Signed-off-by: Yuval Lifshitz <[email protected]>
1 parent b1e7c06 commit fcfc50b

File tree

13 files changed

+562
-129
lines changed

13 files changed

+562
-129
lines changed

doc/radosgw/bucket_logging.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Adding a log object to the log bucket is done "lazily", meaning, that if no more
3535
remain outside of the log bucket even after the configured time has passed.
3636
To counter that, you can flush all logging objects on a given source bucket to log them,
3737
regardless if enough time passed or if no more records are written to the object.
38+
Flushing will happen automatically when logging is disabled on a bucket, its logging configuration is changed, or the bucket is deleted.
3839

3940
Standard
4041
````````

src/rgw/driver/rados/rgw_sal_rados.cc

Lines changed: 76 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,10 @@ int RadosBucket::remove(const DoutPrefixProvider* dpp,
429429
ldpp_dout(dpp, -1) << "ERROR: unable to remove notifications from bucket. ret=" << ps_ret << dendl;
430430
}
431431

432+
if (ret = rgw::bucketlogging::bucket_deletion_cleanup(dpp, store, this, y); ret < 0) {
433+
ldpp_dout(dpp, 1) << "WARNING: could not cleanup bucket logging configuration and pending objects, ret = " << ret << dendl;
434+
}
435+
432436
ret = store->ctl()->bucket->unlink_bucket(rados, info.owner,
433437
info.bucket, y, dpp, false);
434438
if (ret < 0) {
@@ -1024,15 +1028,15 @@ int RadosBucket::remove_topics(RGWObjVersionTracker* objv_tracker,
10241028
objv_tracker, y);
10251029
}
10261030

1027-
int RadosBucket::get_logging_object_name(std::string& obj_name,
1028-
const std::string& prefix,
1029-
optional_yield y,
1031+
int RadosBucket::get_logging_object_name(std::string& obj_name,
1032+
const std::string& prefix,
1033+
optional_yield y,
10301034
const DoutPrefixProvider *dpp,
10311035
RGWObjVersionTracker* objv_tracker) {
10321036
rgw_pool data_pool;
10331037
const auto obj_name_oid = bucketlogging::object_name_oid(this, prefix);
10341038
if (!store->getRados()->get_obj_data_pool(get_placement_rule(), rgw_obj{get_key(), obj_name_oid}, &data_pool)) {
1035-
ldpp_dout(dpp, 1) << "failed to get data pool for bucket '" << get_name() <<
1039+
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_name() <<
10361040
"' when getting logging object name" << dendl;
10371041
return -EIO;
10381042
}
@@ -1048,23 +1052,23 @@ int RadosBucket::get_logging_object_name(std::string& obj_name,
10481052
nullptr,
10491053
nullptr);
10501054
if (ret < 0) {
1051-
ldpp_dout(dpp, 1) << "failed to get logging object name from '" << obj_name_oid << "'. ret = " << ret << dendl;
1055+
ldpp_dout(dpp, 1) << "ERROR: failed to get logging object name from '" << obj_name_oid << "'. ret = " << ret << dendl;
10521056
return ret;
10531057
}
10541058
obj_name = bl.to_str();
10551059
return 0;
10561060
}
10571061

1058-
int RadosBucket::set_logging_object_name(const std::string& obj_name,
1059-
const std::string& prefix,
1060-
optional_yield y,
1061-
const DoutPrefixProvider *dpp,
1062+
int RadosBucket::set_logging_object_name(const std::string& obj_name,
1063+
const std::string& prefix,
1064+
optional_yield y,
1065+
const DoutPrefixProvider *dpp,
10621066
bool new_obj,
10631067
RGWObjVersionTracker* objv_tracker) {
10641068
rgw_pool data_pool;
10651069
const auto obj_name_oid = bucketlogging::object_name_oid(this, prefix);
10661070
if (!store->getRados()->get_obj_data_pool(get_placement_rule(), rgw_obj{get_key(), obj_name_oid}, &data_pool)) {
1067-
ldpp_dout(dpp, 1) << "failed to get data pool for bucket '" << get_name() <<
1071+
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_name() <<
10681072
"' when setting logging object name" << dendl;
10691073
return -EIO;
10701074
}
@@ -1080,28 +1084,65 @@ int RadosBucket::set_logging_object_name(const std::string& obj_name,
10801084
y,
10811085
nullptr);
10821086
if (ret == -EEXIST) {
1083-
ldpp_dout(dpp, 20) << "race detected in initializing '" << obj_name_oid << "' with logging object name:'" << obj_name << "'. ret = " << ret << dendl;
1087+
ldpp_dout(dpp, 20) << "INFO: race detected in initializing '" << obj_name_oid << "' with logging object name:'" << obj_name << "'. ret = " << ret << dendl;
10841088
} else if (ret == -ECANCELED) {
1085-
ldpp_dout(dpp, 20) << "race detected in updating logging object name '" << obj_name << "' at '" << obj_name_oid << "'. ret = " << ret << dendl;
1089+
ldpp_dout(dpp, 20) << "INFO: race detected in updating logging object name '" << obj_name << "' at '" << obj_name_oid << "'. ret = " << ret << dendl;
10861090
} else if (ret < 0) {
1087-
ldpp_dout(dpp, 1) << "failed to set logging object name '" << obj_name << "' at '" << obj_name_oid << "'. ret = " << ret << dendl;
1091+
ldpp_dout(dpp, 1) << "ERROR: failed to set logging object name '" << obj_name << "' at '" << obj_name_oid << "'. ret = " << ret << dendl;
10881092
}
10891093
return ret;
10901094
}
10911095

1096+
int RadosBucket::remove_logging_object_name(const std::string& prefix,
1097+
optional_yield y,
1098+
const DoutPrefixProvider *dpp,
1099+
RGWObjVersionTracker* objv_tracker) {
1100+
rgw_pool data_pool;
1101+
const auto obj_name_oid = bucketlogging::object_name_oid(this, prefix);
1102+
if (!store->getRados()->get_obj_data_pool(get_placement_rule(), rgw_obj{get_key(), obj_name_oid}, &data_pool)) {
1103+
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_name() <<
1104+
"' when setting logging object name" << dendl;
1105+
return -EIO;
1106+
}
1107+
return rgw_delete_system_obj(dpp, store->svc()->sysobj,
1108+
data_pool,
1109+
obj_name_oid,
1110+
objv_tracker,
1111+
y);
1112+
}
1113+
10921114
std::string to_temp_object_name(const rgw::sal::Bucket* bucket, const std::string& obj_name) {
10931115
return fmt::format("{}__shadow_{}0",
10941116
bucket->get_bucket_id(),
10951117
obj_name);
10961118
}
10971119

1120+
int RadosBucket::remove_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) {
1121+
rgw_pool data_pool;
1122+
const rgw_obj head_obj{get_key(), obj_name};
1123+
const auto placement_rule = get_placement_rule();
1124+
1125+
if (!store->getRados()->get_obj_data_pool(placement_rule, head_obj, &data_pool)) {
1126+
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_name() <<
1127+
"' when deleting logging object" << dendl;
1128+
return -EIO;
1129+
}
1130+
1131+
const auto temp_obj_name = to_temp_object_name(this, obj_name);
1132+
return rgw_delete_system_obj(dpp, store->svc()->sysobj,
1133+
data_pool,
1134+
temp_obj_name,
1135+
nullptr,
1136+
y);
1137+
}
1138+
10981139
int RadosBucket::commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) {
10991140
rgw_pool data_pool;
11001141
const rgw_obj head_obj{get_key(), obj_name};
11011142
const auto placement_rule = get_placement_rule();
11021143

11031144
if (!store->getRados()->get_obj_data_pool(placement_rule, head_obj, &data_pool)) {
1104-
ldpp_dout(dpp, 1) << "failed to get data pool for bucket '" << get_name() <<
1145+
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_name() <<
11051146
"' when comitting logging object" << dendl;
11061147
return -EIO;
11071148
}
@@ -1110,7 +1151,6 @@ int RadosBucket::commit_logging_object(const std::string& obj_name, optional_yie
11101151
std::map<string, bufferlist> obj_attrs;
11111152
ceph::real_time mtime;
11121153
bufferlist bl_data;
1113-
// TODO: this is needed only for etag calculation
11141154
if (const auto ret = rgw_get_system_obj(store->svc()->sysobj,
11151155
data_pool,
11161156
temp_obj_name,
@@ -1120,10 +1160,13 @@ int RadosBucket::commit_logging_object(const std::string& obj_name, optional_yie
11201160
y,
11211161
dpp,
11221162
&obj_attrs,
1123-
nullptr); ret < 0) {
1124-
ldpp_dout(dpp, 1) << "faild to read logging data when comitting to object '" << temp_obj_name
1163+
nullptr); ret < 0 && ret != -ENOENT) {
1164+
ldpp_dout(dpp, 1) << "ERROR: failed to read logging data when comitting object '" << temp_obj_name
11251165
<< ". error: " << ret << dendl;
11261166
return ret;
1167+
} else if (ret == -ENOENT) {
1168+
ldpp_dout(dpp, 1) << "WARNING: temporary logging object '" << temp_obj_name << "' does not exists" << dendl;
1169+
return 0;
11271170
}
11281171

11291172
uint64_t size = bl_data.length();
@@ -1137,21 +1180,21 @@ int RadosBucket::commit_logging_object(const std::string& obj_name, optional_yie
11371180
nullptr, // no special placment for tail
11381181
get_key(),
11391182
head_obj); ret < 0) {
1140-
ldpp_dout(dpp, 1) << "failed to create manifest when comitting logging object. error: " <<
1183+
ldpp_dout(dpp, 1) << "ERROR: failed to create manifest when comitting logging object. error: " <<
11411184
ret << dendl;
11421185
return ret;
11431186
}
11441187

11451188
if (const auto ret = manifest_gen.create_next(size); ret < 0) {
1146-
ldpp_dout(dpp, 1) << "failed to add object to manifest when comitting logging object. error: " <<
1189+
ldpp_dout(dpp, 1) << "ERROR: failed to add object to manifest when comitting logging object. error: " <<
11471190
ret << dendl;
11481191
return ret;
11491192
}
11501193

11511194
if (const auto expected_temp_obj = manifest_gen.get_cur_obj(store->getRados());
11521195
temp_obj_name != expected_temp_obj.oid) {
11531196
// TODO: cleanup temporary object, commit would never succeed
1154-
ldpp_dout(dpp, 1) << "temporary logging object name mismatch: '" <<
1197+
ldpp_dout(dpp, 1) << "ERROR: temporary logging object name mismatch: '" <<
11551198
temp_obj_name << "' != '" << expected_temp_obj.oid << "'" << dendl;
11561199
return -EINVAL;
11571200
}
@@ -1182,11 +1225,11 @@ int RadosBucket::commit_logging_object(const std::string& obj_name, optional_yie
11821225
const req_context rctx{dpp, y, nullptr};
11831226
jspan_context trace{false, false};
11841227
if (const auto ret = head_obj_wop.write_meta(0, size, obj_attrs, rctx, trace); ret < 0) {
1185-
ldpp_dout(dpp, 1) << "failed to commit logging object '" << temp_obj_name <<
1186-
"' to bucket id '" << get_bucket_id() <<"'. error: " << ret << dendl;
1228+
ldpp_dout(dpp, 1) << "ERROR: failed to commit logging object '" << temp_obj_name <<
1229+
"' to bucket id '" << get_info().bucket <<"'. error: " << ret << dendl;
11871230
return ret;
11881231
}
1189-
ldpp_dout(dpp, 20) << "committed logging object '" << temp_obj_name <<
1232+
ldpp_dout(dpp, 20) << "INFO: committed logging object '" << temp_obj_name <<
11901233
"' with size of " << size << " bytes, to bucket '" << get_key() << "' as '" <<
11911234
obj_name << "'" << dendl;
11921235
return 0;
@@ -1204,30 +1247,30 @@ void bucket_logging_completion(rados_completion_t completion, void* args) {
12041247
auto* aio_comp = reinterpret_cast<librados::AioCompletionImpl*>(completion);
12051248
std::unique_ptr<BucketLoggingCompleteArg> logging_args(reinterpret_cast<BucketLoggingCompleteArg*>(args));
12061249
if (aio_comp->get_return_value() < 0) {
1207-
ldout(logging_args->cct, 1) << "failed to complete append to logging object '" << logging_args->obj_name <<
1250+
ldout(logging_args->cct, 1) << "ERROR: failed to complete append to logging object '" << logging_args->obj_name <<
12081251
"'. ret = " << aio_comp->get_return_value() << dendl;
12091252
} else {
1210-
ldout(logging_args->cct, 20) << "wrote " << logging_args->size << " bytes to logging object '" <<
1253+
ldout(logging_args->cct, 20) << "INFO: wrote " << logging_args->size << " bytes to logging object '" <<
12111254
logging_args->obj_name << "'" << dendl;
12121255
}
12131256
}
12141257

1215-
int RadosBucket::write_logging_object(const std::string& obj_name,
1216-
const std::string& record,
1217-
optional_yield y,
1258+
int RadosBucket::write_logging_object(const std::string& obj_name,
1259+
const std::string& record,
1260+
optional_yield y,
12181261
const DoutPrefixProvider *dpp,
12191262
bool async_completion) {
12201263
const auto temp_obj_name = to_temp_object_name(this, obj_name);
12211264
rgw_pool data_pool;
12221265
rgw_obj obj{get_key(), obj_name};
12231266
if (!store->getRados()->get_obj_data_pool(get_placement_rule(), obj, &data_pool)) {
1224-
ldpp_dout(dpp, 1) << "failed to get data pool for bucket '" << get_name() <<
1267+
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_name() <<
12251268
"' when writing logging object" << dendl;
12261269
return -EIO;
12271270
}
12281271
librados::IoCtx io_ctx;
12291272
if (const auto ret = rgw_init_ioctx(dpp, store->getRados()->get_rados_handle(), data_pool, io_ctx); ret < 0) {
1230-
ldpp_dout(dpp, 1) << "failed to get IO context for logging object from data pool:" << data_pool.to_str() << dendl;
1273+
ldpp_dout(dpp, 1) << "ERROR: failed to get IO context for logging object from data pool:" << data_pool.to_str() << dendl;
12311274
return -EIO;
12321275
}
12331276
bufferlist bl;
@@ -1242,7 +1285,7 @@ int RadosBucket::write_logging_object(const std::string& obj_name,
12421285
auto arg = std::make_unique<BucketLoggingCompleteArg>(temp_obj_name, record.length(), store->ctx());
12431286
completion->set_complete_callback(arg.get(), bucket_logging_completion);
12441287
if (const auto ret = io_ctx.aio_operate(temp_obj_name, completion.get(), &op); ret < 0) {
1245-
ldpp_dout(dpp, 1) << "failed to append to logging object '" << temp_obj_name <<
1288+
ldpp_dout(dpp, 1) << "ERROR: failed to append to logging object '" << temp_obj_name <<
12461289
"'. ret = " << ret << dendl;
12471290
return ret;
12481291
}
@@ -1251,11 +1294,11 @@ int RadosBucket::write_logging_object(const std::string& obj_name,
12511294
return 0;
12521295
}
12531296
if (const auto ret = rgw_rados_operate(dpp, io_ctx, temp_obj_name, &op, y); ret < 0) {
1254-
ldpp_dout(dpp, 1) << "failed to append to logging object '" << temp_obj_name <<
1297+
ldpp_dout(dpp, 1) << "ERROR: failed to append to logging object '" << temp_obj_name <<
12551298
"'. ret = " << ret << dendl;
12561299
return ret;
12571300
}
1258-
ldpp_dout(dpp, 20) << "wrote " << record.length() << " bytes to logging object '" <<
1301+
ldpp_dout(dpp, 20) << "INFO: wrote " << record.length() << " bytes to logging object '" <<
12591302
temp_obj_name << "'" << dendl;
12601303
return 0;
12611304
}

src/rgw/driver/rados/rgw_sal_rados.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -780,18 +780,23 @@ class RadosBucket : public StoreBucket {
780780
optional_yield y, const DoutPrefixProvider *dpp) override;
781781
int remove_topics(RGWObjVersionTracker* objv_tracker,
782782
optional_yield y, const DoutPrefixProvider *dpp) override;
783-
int get_logging_object_name(std::string& obj_name,
784-
const std::string& prefix,
785-
optional_yield y,
786-
const DoutPrefixProvider *dpp,
783+
int get_logging_object_name(std::string& obj_name,
784+
const std::string& prefix,
785+
optional_yield y,
786+
const DoutPrefixProvider *dpp,
787+
RGWObjVersionTracker* objv_tracker) override;
788+
int set_logging_object_name(const std::string& obj_name,
789+
const std::string& prefix,
790+
optional_yield y,
791+
const DoutPrefixProvider *dpp,
792+
bool new_obj,
787793
RGWObjVersionTracker* objv_tracker) override;
788-
int set_logging_object_name(const std::string& obj_name,
789-
const std::string& prefix,
790-
optional_yield y,
791-
const DoutPrefixProvider *dpp,
792-
bool new_obj,
794+
int remove_logging_object_name(const std::string& prefix,
795+
optional_yield y,
796+
const DoutPrefixProvider *dpp,
793797
RGWObjVersionTracker* objv_tracker) override;
794798
int commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) override;
799+
int remove_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) override;
795800
int write_logging_object(const std::string& obj_name, const std::string& record, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) override;
796801

797802
private:

src/rgw/radosgw-admin/radosgw-admin.cc

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ void usage()
171171
cout << " bucket sync disable disable bucket sync\n";
172172
cout << " bucket sync enable enable bucket sync\n";
173173
cout << " bucket radoslist list rados objects backing bucket's objects\n";
174-
cout << " bucket logging flush flush pending log records object of source bucket to the log bucket to bucket\n";
174+
cout << " bucket logging flush flush pending log records object of source bucket to the log bucket\n";
175+
cout << " bucket logging info get info on bucket logging configuration on source bucket or list of sources in log bucket\n";
175176
cout << " bi get retrieve bucket index object entries\n";
176177
cout << " bi put store bucket index object entries\n";
177178
cout << " bi list list raw bucket index entries\n";
@@ -701,6 +702,7 @@ enum class OPT {
701702
BUCKET_OBJECT_SHARD,
702703
BUCKET_RESYNC_ENCRYPTED_MULTIPART,
703704
BUCKET_LOGGING_FLUSH,
705+
BUCKET_LOGGING_INFO,
704706
POLICY,
705707
LOG_LIST,
706708
LOG_SHOW,
@@ -940,6 +942,7 @@ static SimpleCmd::Commands all_cmds = {
940942
{ "bucket object shard", OPT::BUCKET_OBJECT_SHARD },
941943
{ "bucket resync encrypted multipart", OPT::BUCKET_RESYNC_ENCRYPTED_MULTIPART },
942944
{ "bucket logging flush", OPT::BUCKET_LOGGING_FLUSH },
945+
{ "bucket logging info", OPT::BUCKET_LOGGING_INFO },
943946
{ "policy", OPT::POLICY },
944947
{ "log list", OPT::LOG_LIST },
945948
{ "log show", OPT::LOG_SHOW },
@@ -7750,6 +7753,47 @@ int main(int argc, const char **argv)
77507753
return 0;
77517754
}
77527755

7756+
if (opt_cmd == OPT::BUCKET_LOGGING_INFO) {
7757+
if (bucket_name.empty()) {
7758+
cerr << "ERROR: bucket not specified" << std::endl;
7759+
return EINVAL;
7760+
}
7761+
int ret = init_bucket(tenant, bucket_name, bucket_id, &bucket);
7762+
if (ret < 0) {
7763+
return -ret;
7764+
}
7765+
const auto& bucket_attrs = bucket->get_attrs();
7766+
auto iter = bucket_attrs.find(RGW_ATTR_BUCKET_LOGGING);
7767+
if (iter != bucket_attrs.end()) {
7768+
rgw::bucketlogging::configuration configuration;
7769+
try {
7770+
configuration.enabled = true;
7771+
decode(configuration, iter->second);
7772+
} catch (buffer::error& err) {
7773+
cerr << "ERROR: failed to decode logging attribute '" << RGW_ATTR_BUCKET_LOGGING
7774+
<< "'. error: " << err.what() << std::endl;
7775+
return EINVAL;
7776+
}
7777+
encode_json("logging", configuration, formatter.get());
7778+
formatter->flush(cout);
7779+
}
7780+
iter = bucket_attrs.find(RGW_ATTR_BUCKET_LOGGING_SOURCES);
7781+
if (iter != bucket_attrs.end()) {
7782+
rgw::bucketlogging::source_buckets sources;
7783+
try {
7784+
decode(sources, iter->second);
7785+
} catch (buffer::error& err) {
7786+
cerr << "ERROR: failed to decode logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
7787+
<< "'. error: " << err.what() << std::endl;
7788+
return EINVAL;
7789+
}
7790+
encode_json("logging_sources", sources, formatter.get());
7791+
formatter->flush(cout);
7792+
}
7793+
7794+
return 0;
7795+
}
7796+
77537797
if (opt_cmd == OPT::LOG_LIST) {
77547798
// filter by date?
77557799
if (date.size() && date.size() != 10) {

0 commit comments

Comments
 (0)