Skip to content

Commit 28307aa

Browse files
authored
Merge pull request ceph#66110 from yuvalif/wip-yuval-73675
rgw/logging: fix source bucket cleanup process
2 parents a46507a + 494fb20 commit 28307aa

File tree

5 files changed

+117
-85
lines changed

5 files changed

+117
-85
lines changed

src/rgw/driver/rados/rgw_sal_rados.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,8 @@ int set_committed_logging_object(RadosStore* store,
11401140
bufferlist bl;
11411141
bl.append(last_committed);
11421142
librados::ObjectWriteOperation op;
1143+
// if object does not exist, we should not create the attribute
1144+
op.assert_exists();
11431145
op.setxattr(RGW_ATTR_COMMITTED_LOGGING_OBJ, std::move(bl));
11441146
return rgw_rados_operate(dpp, io_ctx, obj_name_oid, std::move(op), y);
11451147
}
@@ -1174,6 +1176,10 @@ int RadosBucket::get_logging_object_name(std::string& obj_name,
11741176
}
11751177
return ret;
11761178
}
1179+
if (bl.length() == 0) {
1180+
ldpp_dout(dpp, 1) << "ERROR: logging object name at '" << obj_name_oid << "' is empty" << dendl;
1181+
return -ENODATA;
1182+
}
11771183
obj_name = bl.to_str();
11781184
return 0;
11791185
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7884,6 +7884,12 @@ int main(int argc, const char **argv)
78847884
return 0;
78857885
}
78867886

7887+
// make sure that the logging source attribute is up-to-date
7888+
if (ret = rgw::bucketlogging::update_bucket_logging_sources(dpp(), target_bucket, bucket->get_key(), true, null_yield); ret < 0) {
7889+
cerr << "WARNING: failed to update logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
7890+
<< "' in logging target '" << target_bucket->get_key() << "'. error: " << cpp_strerror(ret) << std::endl;
7891+
}
7892+
78877893
std::string obj_name;
78887894
RGWObjVersionTracker objv_tracker;
78897895
ret = target_bucket->get_logging_object_name(obj_name, configuration.target_prefix, null_yield, dpp(), &objv_tracker);

src/rgw/rgw_bucket_logging.cc

Lines changed: 100 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,6 @@ int commit_logging_object(const configuration& conf,
328328
<< ret << dendl;
329329
return ret;
330330
}
331-
return commit_logging_object(conf, target_bucket, dpp, y, last_committed);
332-
}
333-
334-
int commit_logging_object(const configuration& conf,
335-
const std::unique_ptr<rgw::sal::Bucket>& target_bucket,
336-
const DoutPrefixProvider *dpp,
337-
optional_yield y,
338-
std::string* last_committed) {
339331
std::string obj_name;
340332
if (const int ret = target_bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, nullptr); ret < 0) {
341333
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of logging bucket '" <<
@@ -509,6 +501,12 @@ int log_record(rgw::sal::Driver* driver,
509501
return ret;
510502
}
511503

504+
// make sure that the logging source attribute is up-to-date
505+
if (ret = update_bucket_logging_sources(dpp, target_bucket, s->bucket->get_key(), true, y); ret < 0) {
506+
ldpp_dout(dpp, 5) << "WARNING: could not update bucket logging source '" <<
507+
s->bucket->get_key() << "' in logging bucket '" << target_bucket_id << "' attribute, during record logging. ret = " << ret << dendl;
508+
}
509+
512510
const auto region = driver->get_zone()->get_zonegroup().get_api_name();
513511
std::string obj_name;
514512
RGWObjVersionTracker objv_tracker;
@@ -795,8 +793,7 @@ int update_bucket_logging_sources(const DoutPrefixProvider* dpp, std::unique_ptr
795793
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
796794
<< "' for bucket '" << bucket->get_key() << "' when updating logging sources. error: " << err.what() << dendl;
797795
}
798-
ldpp_dout(dpp, 20) << "INFO: logging source '" << src_bucket_id << "' already " <<
799-
(add ? "added to" : "removed from") << " bucket '" << bucket->get_key() << "'" << dendl;
796+
// no change
800797
return 0;
801798
}, y);
802799
}
@@ -810,53 +807,59 @@ int bucket_deletion_cleanup(const DoutPrefixProvider* dpp,
810807
// and also delete the object holding the pending object name
811808
auto& attrs = bucket->get_attrs();
812809
if (const auto iter = attrs.find(RGW_ATTR_BUCKET_LOGGING_SOURCES); iter != attrs.end()) {
810+
source_buckets sources;
813811
try {
814-
source_buckets sources;
815812
ceph::decode(sources, iter->second);
816-
for (const auto& source : sources) {
817-
std::unique_ptr<rgw::sal::Bucket> src_bucket;
818-
if (const int ret = driver->load_bucket(dpp, source, &src_bucket, y); ret < 0) {
819-
ldpp_dout(dpp, 5) << "WARNING: failed to get logging source bucket '" << source << "' for logging bucket '" <<
813+
} catch (buffer::error& err) {
814+
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
815+
<< "' for logging bucket '" << bucket->get_key() << "'. error: " << err.what() << dendl;
816+
return -EIO;
817+
}
818+
// since we removed the attribute, we should not return error code from now on
819+
// any retry, would find no attribute and return success
820+
for (const auto& source : sources) {
821+
std::unique_ptr<rgw::sal::Bucket> src_bucket;
822+
if (const int ret = driver->load_bucket(dpp, source, &src_bucket, y); ret < 0) {
823+
ldpp_dout(dpp, 5) << "WARNING: failed to get logging source bucket '" << source << "' for logging bucket '" <<
824+
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
825+
continue;
826+
}
827+
auto& src_attrs = src_bucket->get_attrs();
828+
if (const auto iter = src_attrs.find(RGW_ATTR_BUCKET_LOGGING); iter != src_attrs.end()) {
829+
configuration conf;
830+
try {
831+
auto bl_iter = iter->second.cbegin();
832+
decode(conf, bl_iter);
833+
} catch (buffer::error& err) {
834+
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging attribute '" << RGW_ATTR_BUCKET_LOGGING
835+
<< "' of bucket '" << src_bucket->get_key() << "' during cleanup. error: " << err.what() << dendl;
836+
continue;
837+
}
838+
std::string obj_name;
839+
RGWObjVersionTracker objv;
840+
if (const int ret = bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, &objv); ret < 0) {
841+
ldpp_dout(dpp, 5) << "WARNING: failed to get logging object name for logging bucket '" << bucket->get_key() <<
842+
"' during cleanup. ret = " << ret << dendl;
843+
continue;
844+
}
845+
if (const int ret = bucket->remove_logging_object_name(conf.target_prefix, y, dpp, &objv); ret < 0) {
846+
ldpp_dout(dpp, 5) << "WARNING: failed to delete object holding bucket logging object name for logging bucket '" <<
820847
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
821848
continue;
822849
}
823-
auto& src_attrs = src_bucket->get_attrs();
824-
if (const auto iter = src_attrs.find(RGW_ATTR_BUCKET_LOGGING); iter != src_attrs.end()) {
825-
configuration conf;
826-
try {
827-
auto bl_iter = iter->second.cbegin();
828-
decode(conf, bl_iter);
829-
std::string obj_name;
830-
RGWObjVersionTracker objv;
831-
if (const int ret = bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, &objv); ret < 0) {
832-
ldpp_dout(dpp, 5) << "WARNING: failed to get logging object name for logging bucket '" << bucket->get_key() <<
833-
"' during cleanup. ret = " << ret << dendl;
834-
continue;
835-
}
836-
if (const int ret = bucket->remove_logging_object(obj_name, y, dpp); ret < 0) {
837-
ldpp_dout(dpp, 5) << "WARNING: failed to delete pending logging object '" << obj_name << "' for logging bucket '" <<
838-
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
839-
continue;
840-
}
841-
ldpp_dout(dpp, 20) << "INFO: successfully deleted pending logging object '" << obj_name << "' from deleted logging bucket '" <<
842-
bucket->get_key() << "'" << dendl;
843-
if (const int ret = bucket->remove_logging_object_name(conf.target_prefix, y, dpp, &objv); ret < 0) {
844-
ldpp_dout(dpp, 5) << "WARNING: failed to delete object holding bucket logging object name for logging bucket '" <<
845-
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
846-
continue;
847-
}
848-
ldpp_dout(dpp, 20) << "INFO: successfully deleted object holding bucket logging object name from deleted logging bucket '" <<
849-
bucket->get_key() << "'" << dendl;
850-
} catch (buffer::error& err) {
851-
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging attribute '" << RGW_ATTR_BUCKET_LOGGING
852-
<< "' of bucket '" << src_bucket->get_key() << "' during cleanup. error: " << err.what() << dendl;
853-
}
850+
ldpp_dout(dpp, 20) << "INFO: successfully deleted object holding bucket logging object name from deleted logging bucket '" <<
851+
bucket->get_key() << "'" << dendl;
852+
if (const int ret = bucket->remove_logging_object(obj_name, y, dpp); ret < 0) {
853+
ldpp_dout(dpp, 5) << "WARNING: failed to delete pending logging object '" << obj_name << "' for logging bucket '" <<
854+
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
855+
continue;
854856
}
857+
ldpp_dout(dpp, 20) << "INFO: successfully deleted pending logging object '" << obj_name << "' from deleted logging bucket '" <<
858+
bucket->get_key() << "'" << dendl;
859+
} else {
860+
ldpp_dout(dpp, 5) << "WARNING: no logging attribute '" << RGW_ATTR_BUCKET_LOGGING
861+
<< "' found in logging source bucket '" << src_bucket->get_key() << "' during cleanup" << dendl;
855862
}
856-
} catch (buffer::error& err) {
857-
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
858-
<< "' for logging bucket '" << bucket->get_key() << "'. error: " << err.what() << dendl;
859-
return -EIO;
860863
}
861864
}
862865

@@ -881,7 +884,7 @@ int source_bucket_cleanup(const DoutPrefixProvider* dpp,
881884
conf = std::move(tmp_conf);
882885
} catch (buffer::error& err) {
883886
ldpp_dout(dpp, 5) << "WARNING: failed to decode existing logging attribute '" << RGW_ATTR_BUCKET_LOGGING
884-
<< "' of bucket '" << bucket->get_key() << "' during cleanup. error: " << err.what() << dendl;
887+
<< "' of bucket '" << bucket->get_key() << "' during source cleanup. error: " << err.what() << dendl;
885888
return -EIO;
886889
}
887890
if (remove_attr) {
@@ -894,34 +897,67 @@ int source_bucket_cleanup(const DoutPrefixProvider* dpp,
894897
}, y); ret < 0) {
895898
if (remove_attr) {
896899
ldpp_dout(dpp, 5) << "WARNING: failed to remove logging attribute '" << RGW_ATTR_BUCKET_LOGGING <<
897-
"' from bucket '" << bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
900+
"' from bucket '" << bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
898901
}
899902
return ret;
900903
}
904+
if (last_committed) {
905+
last_committed->clear();
906+
}
901907
if (!conf) {
902908
// no logging attribute found
903909
return 0;
904910
}
905-
const auto& info = bucket->get_info();
906-
if (const int ret = commit_logging_object(*conf, dpp, driver, info.bucket.tenant, y, last_committed); ret < 0) {
907-
ldpp_dout(dpp, 5) << "WARNING: could not commit pending logging object of bucket '" <<
908-
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
909-
} else {
910-
ldpp_dout(dpp, 20) << "INFO: successfully committed pending logging object of bucket '" << bucket->get_key() << "'" << dendl;
911-
}
911+
// since we removed the attribute, we should not return error code from now on
912+
// any retry, would find no attribute and return success
912913
rgw_bucket target_bucket_id;
914+
const auto& info = bucket->get_info();
913915
if (const int ret = get_bucket_id(conf->target_bucket, info.bucket.tenant, target_bucket_id); ret < 0) {
914916
ldpp_dout(dpp, 5) << "WARNING: failed to parse logging bucket '" <<
915-
conf->target_bucket << "' during cleanup. ret = " << ret << dendl;
917+
conf->target_bucket << "' during source cleanup. ret = " << ret << dendl;
918+
return 0;
919+
}
920+
std::unique_ptr<rgw::sal::Bucket> target_bucket;
921+
const int ret = driver->load_bucket(dpp, target_bucket_id, &target_bucket, y);
922+
if (ret < 0) {
923+
ldpp_dout(dpp, 5) << "WARNING: failed to get logging bucket '" << target_bucket_id <<
924+
"' when doing source cleanup. ret = " << ret << dendl;
916925
return 0;
917926
}
918-
if (const int ret = update_bucket_logging_sources(dpp, driver, target_bucket_id, bucket->get_key(), false, y); ret < 0) {
927+
if (const int ret = update_bucket_logging_sources(dpp, target_bucket, bucket->get_key(), false, y); ret < 0) {
919928
ldpp_dout(dpp, 5) << "WARNING: could not update bucket logging source '" <<
920-
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
929+
bucket->get_key() << "' in logging bucket '" << target_bucket_id << "' attribute, during source cleanup. ret = " << ret << dendl;
930+
}
931+
std::string obj_name;
932+
RGWObjVersionTracker objv;
933+
if (const int ret = target_bucket->get_logging_object_name(obj_name, conf->target_prefix, y, dpp, &objv); ret < 0) {
934+
ldpp_dout(dpp, 5) << "WARNING: failed to get logging object name for logging bucket '" << bucket->get_key() <<
935+
"' during source cleanup. ret = " << ret << dendl;
936+
// if name cannot be fetched, we should not commit or remove the object holding the name
937+
// it is better to leak an object than to cause a possible data loss
921938
return 0;
922939
}
923-
ldpp_dout(dpp, 20) << "INFO: successfully updated bucket logging source '" <<
924-
bucket->get_key() << "' during cleanup"<< dendl;
940+
if (const int ret = target_bucket->remove_logging_object_name(conf->target_prefix, y, dpp, &objv); ret < 0) {
941+
ldpp_dout(dpp, 5) << "WARNING: failed to delete object holding bucket logging object name for bucket '" <<
942+
bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
943+
// this could be because of a race someone else trying to commit the object
944+
// (another bucket cleanup with shared prefix, rollover or an explicit commit)
945+
// and since committing the object twice will cause data loss, we should not try to commit it here
946+
return 0;
947+
}
948+
ldpp_dout(dpp, 20) << "INFO: successfully deleted object holding bucket logging object name for bucket '" <<
949+
bucket->get_key() << "' during source cleanup" << dendl;
950+
// since the object holding the name was deleted, we cannot fetch the last commited name from it
951+
if (const int ret = target_bucket->commit_logging_object(obj_name, y, dpp, conf->target_prefix, nullptr); ret < 0) {
952+
ldpp_dout(dpp, 5) << "WARNING: could not commit pending logging object of bucket '" <<
953+
bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
954+
return 0;
955+
}
956+
ldpp_dout(dpp, 20) << "INFO: successfully committed pending logging object of bucket '" <<
957+
bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
958+
if (last_committed) {
959+
*last_committed = obj_name;
960+
}
925961
return 0;
926962
}
927963

src/rgw/rgw_bucket_logging.h

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -186,27 +186,6 @@ int rollover_logging_object(const configuration& conf,
186186
std::string* last_committed,
187187
std::string* err_message = nullptr);
188188

189-
// commit the pending log object to the log bucket
190-
// use this for cleanup, when new pending object is not needed
191-
// and target bucket is known
192-
// if "last_committed" is not null, it will be set to the name of the last committed object
193-
int commit_logging_object(const configuration& conf,
194-
const std::unique_ptr<rgw::sal::Bucket>& target_bucket,
195-
const DoutPrefixProvider *dpp,
196-
optional_yield y,
197-
std::string* last_committed);
198-
199-
// commit the pending log object to the log bucket
200-
// use this for cleanup, when new pending object is not needed
201-
// and target bucket shoud be loaded based on the configuration
202-
// if "last_committed" is not null, it will be set to the name of the last committed object
203-
int commit_logging_object(const configuration& conf,
204-
const DoutPrefixProvider *dpp,
205-
rgw::sal::Driver* driver,
206-
const std::string& tenant_name,
207-
optional_yield y,
208-
std::string* last_committed);
209-
210189
// return the oid of the object holding the name of the temporary logging object
211190
// bucket - log bucket
212191
// prefix - logging prefix from configuration. should be used when multiple buckets log into the same log bucket

src/rgw/rgw_rest_bucket_logging.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,11 @@ class RGWPostBucketLoggingOp : public RGWDefaultResponseOp {
417417

418418
void execute(optional_yield y) override {
419419
const auto& target_bucket_id = target_bucket->get_key();
420+
// make sure that the logging source attribute is up-to-date
421+
if (const auto ret = rgw::bucketlogging::update_bucket_logging_sources(this, target_bucket, source_bucket->get_key(), true, y); ret < 0) {
422+
ldpp_dout(this, 5) << "WARNING: failed to update logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
423+
<< "' in logging target '" << target_bucket_id << "'. error: " << ret << dendl;
424+
}
420425
std::string obj_name;
421426
RGWObjVersionTracker objv_tracker;
422427
op_ret = target_bucket->get_logging_object_name(obj_name, configuration.target_prefix, y, this, &objv_tracker);

0 commit comments

Comments
 (0)