return 0;
}
+static int get_part_obj_state(const DoutPrefixProvider* dpp, optional_yield y,
+ RGWRados* store, RGWBucketInfo& bucket_info,
+ RGWObjectCtx* rctx, RGWObjManifest* manifest,
+ int part_num, int* parts_count, bool prefetch,
+ RGWObjState** pstate, RGWObjManifest** pmanifest)
+{
+ // navigate to the requested part in the manifest
+ RGWObjManifest::obj_iterator end = manifest->obj_end(dpp);
+ if (end.get_cur_part_id() == 0) { // not multipart
+ ldpp_dout(dpp, 20) << "object does not have a multipart manifest" << dendl;
+ return -ERR_INVALID_PART;
+ }
+ if (parts_count) {
+ *parts_count = end.get_cur_part_id() - 1;
+ }
+ ldpp_dout(dpp, 20) << "seeking to part #" << part_num
+ << " in the object manifest" << dendl;
+ RGWObjManifest::obj_iterator iter = manifest->obj_find_part(dpp, part_num);
+ if (iter == end) { // part number not found
+ ldpp_dout(dpp, 20) << "failed to find part #" << part_num
+ << " in the object manifest" << dendl;
+ return -ERR_INVALID_PART;
+ }
+ auto head_obj = iter.get_location().get_head_obj();
+ if (!head_obj) { // iterator points to a tail object
+ ldpp_dout(dpp, 20) << "object manifest for part #" << part_num
+ << " points to a tail object" << dendl;
+ return -ERR_INVALID_PART;
+ }
+ const auto part_offset = iter.get_ofs();
+
+ // read the part's head object
+ if (prefetch) {
+ rctx->set_prefetch_data(*head_obj);
+ }
+ RGWObjStateManifest* sm = nullptr;
+ constexpr bool follow_olh = false; // parts aren't versioned
+ int r = store->get_obj_state(dpp, rctx, bucket_info, *head_obj,
+ &sm, follow_olh, y);
+ if (r < 0) {
+ return r;
+ }
+ *pstate = &sm->state;
+
+ // if the part has its own manifest, use it directly
+ if (sm->manifest) {
+ *pmanifest = &*sm->manifest;
+ return 0;
+ }
+
+ // create a new manifest for just this part
+ sm->manifest.emplace();
+ RGWObjManifest& part_manifest = *sm->manifest;
+ part_manifest.set_multipart_part_rule(iter.get_stripe_size(), part_num);
+
+ if (auto& prefix = iter.get_cur_override_prefix(); !prefix.empty()) {
+ // the part was reuploaded with a different prefix
+ part_manifest.set_prefix(prefix);
+ } else {
+ part_manifest.set_prefix(manifest->get_prefix());
+ }
+
+ RGWObjManifest::generator gen;
+ gen.create_begin(store->ctx(), &part_manifest,
+ manifest->get_head_placement_rule(),
+ &manifest->get_tail_placement().placement_rule,
+ head_obj->bucket, *head_obj);
+
+ // copy each of the part's stripes into the new manifest. the final call to
+ // create_next() uses the starting offset of the next part
+ do {
+ ++iter;
+ gen.create_next(iter.get_ofs() - part_offset);
+ } while (iter.get_cur_part_id() == part_num);
+
+ // update the object size
+ sm->state.size = part_manifest.get_obj_size();
+
+ *pmanifest = &part_manifest;
+ return 0;
+}
+
int RGWRados::Object::Read::prepare(optional_yield y, const DoutPrefixProvider *dpp)
{
RGWRados *store = source->get_store();
CephContext *cct = store->ctx();
+ RGWObjectCtx& obj_ctx = source->get_ctx();
bufferlist etag;
map<string, bufferlist>::iterator iter;
+ bool part_prefetch = false;
+ if (params.part_num) {
+ // prefetch from the part's head object instead of the multipart head
+ auto sm = obj_ctx.get_state(source->get_obj());
+ part_prefetch = std::exchange(sm->state.prefetch_data, false);
+ }
+
RGWObjState *astate;
RGWObjManifest *manifest = nullptr;
int r = source->get_state(dpp, &astate, &manifest, true, y);
return -ENOENT;
}
- const RGWBucketInfo& bucket_info = source->get_bucket_info();
+ RGWBucketInfo& bucket_info = source->get_bucket_info();
+
+ if (params.part_num) {
+ // use the manifest to redirect to the requested part number
+ if (!manifest) {
+ return -ERR_INVALID_PART;
+ }
+ r = get_part_obj_state(dpp, y, store, bucket_info, &source->get_ctx(),
+ manifest, *params.part_num, params.parts_count,
+ part_prefetch, &astate, &manifest);
+ if (r < 0) {
+ ldpp_dout(dpp, 4) << "failed to read part #" << *params.part_num
+ << ": " << cpp_strerror(r) << dendl;
+ return -ERR_INVALID_PART;
+ }
+ if (!astate->exists) {
+ ldpp_dout(dpp, 4) << "part #" << *params.part_num
+ << " does not exist" << dendl;
+ return -ERR_INVALID_PART;
+ }
+ }
state.obj = astate->obj;
store->obj_to_raw(bucket_info.placement_rule, state.obj, &state.head_obj);