void dump(ceph::Formatter *f) const;
static void generate_test_instances(std::list<cls_rgw_gc_set_entry_op*>& ls);
+
+ size_t estimate_encoded_size() const {
+ constexpr size_t start_overhead = sizeof(__u8) + sizeof(__u8) + sizeof(ceph_le32); // version and length prefix
+ constexpr size_t expr_secs_overhead = sizeof(__u32); // expiration_seconds_overhead
+ return start_overhead + expr_secs_overhead + info.estimate_encoded_size();
+ }
};
WRITE_CLASS_ENCODER(cls_rgw_gc_set_entry_op)
ls.back()->name = "name";
ls.back()->instance = "instance";
}
+
+ size_t estimate_encoded_size() const {
+ constexpr size_t start_overhead = sizeof(__u8) + sizeof(__u8) + sizeof(ceph_le32); // version and length prefix
+ constexpr size_t string_overhead = sizeof(__u32); // strings are encoded with 32-bit length prefix
+ return start_overhead +
+ string_overhead + name.size() +
+ string_overhead + instance.size();
+ }
};
WRITE_CLASS_ENCODER(cls_rgw_obj_key)
ls.back()->key.name = "myoid";
ls.back()->loc = "mykey";
}
+
+ size_t estimate_encoded_size() const {
+ constexpr size_t start_overhead = sizeof(__u8) + sizeof(__u8) + sizeof(ceph_le32); // version and length prefix
+ constexpr size_t string_overhead = sizeof(__u32); // strings are encoded with 32-bit length prefix
+ return start_overhead +
+ string_overhead + pool.size() +
+ string_overhead + key.name.size() +
+ string_overhead + loc.size() +
+ key.estimate_encoded_size();
+ }
};
WRITE_CLASS_ENCODER(cls_rgw_obj)
bool empty() {
return objs.empty();
}
+
+ size_t estimate_encoded_size() const {
+ constexpr size_t start_overhead = sizeof(__u8) + sizeof(__u8) + sizeof(ceph_le32);
+ constexpr size_t size_overhead = sizeof(__u32); // size of the chain
+ size_t chain_overhead = 0;
+ for (auto& it : objs) {
+ chain_overhead += it.estimate_encoded_size();
+ }
+ return (start_overhead + size_overhead + chain_overhead);
+ }
};
WRITE_CLASS_ENCODER(cls_rgw_obj_chain)
ceph_timespec ts{ceph_le32(21), ceph_le32(32)};
ls.back()->time = ceph::real_clock::from_ceph_timespec(ts);
}
+
+ size_t estimate_encoded_size() const {
+ constexpr size_t start_overhead = sizeof(__u8) + sizeof(__u8) + sizeof(ceph_le32); // version and length prefix
+ constexpr size_t string_overhead = sizeof(__u32); // strings are encoded with 32-bit length prefix
+ constexpr size_t time_overhead = 2 * sizeof(ceph_le32); // time is stored as tv_sec and tv_nsec
+ return start_overhead + string_overhead + tag.size() +
+ time_overhead + chain.estimate_encoded_size();
+ }
};
WRITE_CLASS_ENCODER(cls_rgw_gc_obj_info)
return rgw_shards_mod(XXH64(tag.c_str(), tag.size(), seed), max_objs);
}
-int RGWGC::send_chain(cls_rgw_obj_chain& chain, const string& tag)
+std::tuple<int, std::optional<cls_rgw_obj_chain>> RGWGC::send_split_chain(const cls_rgw_obj_chain& chain, const std::string& tag)
+{
+ ldpp_dout(this, 20) << "RGWGC::send_split_chain - tag is: " << tag << dendl;
+
+ if (cct->_conf->rgw_max_chunk_size) {
+ cls_rgw_obj_chain broken_chain;
+ ldpp_dout(this, 20) << "RGWGC::send_split_chain - rgw_max_chunk_size is: " << cct->_conf->rgw_max_chunk_size << dendl;
+
+ for (auto it = chain.objs.begin(); it != chain.objs.end(); it++) {
+ ldpp_dout(this, 20) << "RGWGC::send_split_chain - adding obj with name: " << it->key << dendl;
+ broken_chain.objs.emplace_back(*it);
+ cls_rgw_gc_obj_info info;
+ info.tag = tag;
+ info.chain = broken_chain;
+ cls_rgw_gc_set_entry_op op;
+ op.info = info;
+ size_t total_encoded_size = op.estimate_encoded_size();
+ ldpp_dout(this, 20) << "RGWGC::send_split_chain - total_encoded_size is: " << total_encoded_size << dendl;
+
+ if (total_encoded_size > cct->_conf->rgw_max_chunk_size) { //dont add to chain, and send to gc
+ broken_chain.objs.pop_back();
+ --it;
+ ldpp_dout(this, 20) << "RGWGC::send_split_chain - more than, dont add to broken chain and send chain" << dendl;
+ auto ret = send_chain(broken_chain, tag);
+ if (ret < 0) {
+ broken_chain.objs.insert(broken_chain.objs.end(), it, chain.objs.end()); // add all the remainder objs to the list to be deleted inline
+ ldpp_dout(this, 0) << "RGWGC::send_split_chain - send chain returned error: " << ret << dendl;
+ return {ret, {broken_chain}};
+ }
+ broken_chain.objs.clear();
+ }
+ }
+ if (!broken_chain.objs.empty()) { //when the chain is smaller than or equal to rgw_max_chunk_size
+ ldpp_dout(this, 20) << "RGWGC::send_split_chain - sending leftover objects" << dendl;
+ auto ret = send_chain(broken_chain, tag);
+ if (ret < 0) {
+ ldpp_dout(this, 0) << "RGWGC::send_split_chain - send chain returned error: " << ret << dendl;
+ return {ret, {broken_chain}};
+ }
+ }
+ } else {
+ auto ret = send_chain(chain, tag);
+ if (ret < 0) {
+ ldpp_dout(this, 0) << "RGWGC::send_split_chain - send chain returned error: " << ret << dendl;
+ return {ret, {std::move(chain)}};
+ }
+ }
+ return {0, {}};
+}
+
+int RGWGC::send_chain(const cls_rgw_obj_chain& chain, const string& tag)
{
ObjectWriteOperation op;
cls_rgw_gc_obj_info info;
static constexpr uint64_t seed = 8675309;
int tag_index(const std::string& tag);
+ int send_chain(const cls_rgw_obj_chain& chain, const std::string& tag);
class GCWorker : public Thread {
const DoutPrefixProvider *dpp;
finalize();
}
std::vector<bool> transitioned_objects_cache;
- int send_chain(cls_rgw_obj_chain& chain, const std::string& tag);
+ std::tuple<int, std::optional<cls_rgw_obj_chain>> send_split_chain(const cls_rgw_obj_chain& chain, const std::string& tag);
// asynchronously defer garbage collection on an object that's still being read
int async_defer_chain(const std::string& tag, const cls_rgw_obj_chain& info);
//Delete objects inline just in case gc hasn't been initialised, prevents crashes
store->delete_objs_inline(dpp, chain, tag);
} else {
- auto ret = store->gc->send_chain(chain, tag); // do it synchronously
- if (ret < 0) {
+ auto [ret, leftover_chain] = store->gc->send_split_chain(chain, tag); // do it synchronously
+ if (ret < 0 && leftover_chain) {
//Delete objects inline if send chain to gc fails
- store->delete_objs_inline(dpp, chain, tag);
+ store->delete_objs_inline(dpp, *leftover_chain, tag);
}
}
return 0;
}
}
-int RGWRados::send_chain_to_gc(cls_rgw_obj_chain& chain, const string& tag)
+std::tuple<int, std::optional<cls_rgw_obj_chain>> RGWRados::send_chain_to_gc(cls_rgw_obj_chain& chain, const string& tag)
{
if (chain.empty()) {
- return 0;
+ return {0, std::nullopt};
}
- return gc->send_chain(chain, tag);
+ return gc->send_split_chain(chain, tag);
}
void RGWRados::delete_objs_inline(const DoutPrefixProvider *dpp, cls_rgw_obj_chain& chain, const string& tag)
int unlock(const rgw_pool& pool, const std::string& oid, rgw_zone_id& zone_id, std::string& owner_id);
void update_gc_chain(const DoutPrefixProvider *dpp, rgw_obj& head_obj, RGWObjManifest& manifest, cls_rgw_obj_chain *chain);
- int send_chain_to_gc(cls_rgw_obj_chain& chain, const std::string& tag);
+ std::tuple<int, std::optional<cls_rgw_obj_chain>> send_chain_to_gc(cls_rgw_obj_chain& chain, const std::string& tag);
void delete_objs_inline(const DoutPrefixProvider *dpp, cls_rgw_obj_chain& chain, const std::string& tag);
int gc_operate(const DoutPrefixProvider *dpp, std::string& oid, librados::ObjectWriteOperation *op);
int gc_aio_operate(const std::string& oid, librados::AioCompletion *c,
store->getRados()->delete_objs_inline(dpp, chain, mp_obj.get_upload_id());
} else {
/* use upload id as tag and do it synchronously */
- ret = store->getRados()->send_chain_to_gc(chain, mp_obj.get_upload_id());
- if (ret < 0) {
+ auto [ret, leftover_chain] = store->getRados()->send_chain_to_gc(chain, mp_obj.get_upload_id());
+ if (ret < 0 && leftover_chain) {
ldpp_dout(dpp, 5) << __func__ << ": gc->send_chain() returned " << ret << dendl;
if (ret == -ENOENT) {
return -ERR_NO_SUCH_UPLOAD;
}
//Delete objects inline if send chain to gc fails
- store->getRados()->delete_objs_inline(dpp, chain, mp_obj.get_upload_id());
+ store->getRados()->delete_objs_inline(dpp, *leftover_chain, mp_obj.get_upload_id());
}
}