@@ -4658,7 +4658,9 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
46584658 RGWObjState *astate = NULL ;
46594659 RGWObjManifest *amanifest = nullptr ;
46604660
4661- ret = get_obj_state (dpp, &obj_ctx, src_bucket_info, src_obj, &astate, &amanifest, y);
4661+ constexpr bool follow_olh = true ;
4662+ ret = get_obj_state (dpp, &obj_ctx, src_bucket_info, src_obj,
4663+ &astate, &amanifest, follow_olh, y);
46624664 if (ret < 0 ) {
46634665 return ret;
46644666 }
@@ -5885,48 +5887,38 @@ static bool has_olh_tag(map<string, bufferlist>& attrs)
58855887int RGWRados::get_olh_target_state (const DoutPrefixProvider *dpp, RGWObjectCtx&
58865888 obj_ctx, RGWBucketInfo& bucket_info,
58875889 const rgw_obj& obj, RGWObjState *olh_state,
5888- RGWObjState **target_state,
5889- RGWObjManifest **target_manifest, optional_yield y)
5890+ RGWObjStateManifest **psm, optional_yield y)
58905891{
58915892 ceph_assert (olh_state->is_olh );
58925893
58935894 rgw_obj target;
5894- int r = RGWRados::follow_olh (dpp, bucket_info, obj_ctx, olh_state, obj, &target, y); /* might return -EAGAIN */
5895+ int r = RGWRados::follow_olh (dpp, bucket_info, obj_ctx, olh_state,
5896+ obj, &target, y); /* might return -EAGAIN */
58955897 if (r < 0 ) {
58965898 return r;
58975899 }
58985900
5899- r = get_obj_state (dpp, &obj_ctx, bucket_info, target, target_state,
5900- target_manifest, false , y);
5901- if (r < 0 ) {
5902- return r;
5903- }
5904-
5905- return 0 ;
5901+ return get_obj_state (dpp, &obj_ctx, bucket_info, target, psm, false , y);
59065902}
59075903
59085904int RGWRados::get_obj_state_impl (const DoutPrefixProvider *dpp, RGWObjectCtx *octx,
5909- RGWBucketInfo& bucket_info, const rgw_obj& obj,
5910- RGWObjState **state, RGWObjManifest** manifest ,
5911- bool follow_olh, optional_yield y, bool assume_noent)
5905+ RGWBucketInfo& bucket_info, const rgw_obj& obj,
5906+ RGWObjStateManifest** psm, bool follow_olh ,
5907+ optional_yield y, bool assume_noent)
59125908{
59135909 if (obj.empty ()) {
59145910 return -EINVAL;
59155911 }
59165912
59175913 bool need_follow_olh = follow_olh && obj.key .instance .empty ();
5918- *manifest = nullptr ;
59195914
59205915 RGWObjStateManifest *sm = octx->get_state (obj);
59215916 RGWObjState *s = &(sm->state );
59225917 ldpp_dout (dpp, 20 ) << " get_obj_state: octx=" << (void *)octx << " obj=" << obj << " state=" << (void *)s << " s->prefetch_data=" << s->prefetch_data << dendl;
5923- *state = s;
5924- if (sm->manifest ) {
5925- *manifest = &(*sm->manifest );
5926- }
5918+ *psm = sm;
59275919 if (s->has_attrs ) {
59285920 if (s->is_olh && need_follow_olh) {
5929- return get_olh_target_state (dpp, *octx, bucket_info, obj, s, state, manifest , y);
5921+ return get_olh_target_state (dpp, *octx, bucket_info, obj, s, psm , y);
59305922 }
59315923 return 0 ;
59325924 }
@@ -6018,7 +6010,6 @@ int RGWRados::get_obj_state_impl(const DoutPrefixProvider *dpp, RGWObjectCtx *oc
60186010 ldpp_dout (dpp, 0 ) << " ERROR: couldn't decode manifest" << dendl;
60196011 return -EIO;
60206012 }
6021- *manifest = &(*sm->manifest );
60226013 ldpp_dout (dpp, 10 ) << " manifest: total_size = " << sm->manifest ->get_obj_size () << dendl;
60236014 if (cct->_conf ->subsys .should_gather <ceph_subsys_rgw, 20 >() && \
60246015 sm->manifest ->has_explicit_objs ()) {
@@ -6078,7 +6069,7 @@ int RGWRados::get_obj_state_impl(const DoutPrefixProvider *dpp, RGWObjectCtx *oc
60786069 ldpp_dout (dpp, 20 ) << __func__ << " : setting s->olh_tag to " << string (s->olh_tag .c_str (), s->olh_tag .length ()) << dendl;
60796070
60806071 if (need_follow_olh) {
6081- return get_olh_target_state (dpp, *octx, bucket_info, obj, s, state, manifest , y);
6072+ return get_olh_target_state (dpp, *octx, bucket_info, obj, s, psm , y);
60826073 } else if (obj.key .have_null_instance () && !sm->manifest ) {
60836074 // read null version, and the head object only have olh info
60846075 s->exists = false ;
@@ -6089,18 +6080,45 @@ int RGWRados::get_obj_state_impl(const DoutPrefixProvider *dpp, RGWObjectCtx *oc
60896080 return 0 ;
60906081}
60916082
6092- int RGWRados::get_obj_state (const DoutPrefixProvider *dpp, RGWObjectCtx *octx, RGWBucketInfo& bucket_info, const rgw_obj& obj, RGWObjState **state, RGWObjManifest** manifest,
6093- bool follow_olh, optional_yield y, bool assume_noent)
6083+ int RGWRados::get_obj_state (const DoutPrefixProvider *dpp, RGWObjectCtx *octx,
6084+ RGWBucketInfo& bucket_info, const rgw_obj& obj,
6085+ RGWObjStateManifest** psm, bool follow_olh,
6086+ optional_yield y, bool assume_noent)
60946087{
60956088 int ret;
60966089
60976090 do {
6098- ret = get_obj_state_impl (dpp, octx, bucket_info, obj, state, manifest, follow_olh, y, assume_noent);
6091+ ret = get_obj_state_impl (dpp, octx, bucket_info, obj, psm,
6092+ follow_olh, y, assume_noent);
60996093 } while (ret == -EAGAIN);
61006094
61016095 return ret;
61026096}
61036097
6098+ int RGWRados::get_obj_state (const DoutPrefixProvider *dpp, RGWObjectCtx *rctx,
6099+ RGWBucketInfo& bucket_info, const rgw_obj& obj,
6100+ RGWObjState** pstate, RGWObjManifest** pmanifest,
6101+ bool follow_olh, optional_yield y, bool assume_noent)
6102+ {
6103+ RGWObjStateManifest* sm = nullptr ;
6104+ int r = get_obj_state (dpp, rctx, bucket_info, obj, &sm,
6105+ follow_olh, y, assume_noent);
6106+ if (r < 0 ) {
6107+ return r;
6108+ }
6109+ if (pstate) {
6110+ *pstate = &sm->state ;
6111+ }
6112+ if (pmanifest) {
6113+ if (sm->manifest ) {
6114+ *pmanifest = &(*sm->manifest );
6115+ } else {
6116+ *pmanifest = nullptr ;
6117+ }
6118+ }
6119+ return 0 ;
6120+ }
6121+
61046122int RGWRados::Object::get_manifest (const DoutPrefixProvider *dpp, RGWObjManifest **pmanifest, optional_yield y)
61056123{
61066124 RGWObjState *astate;
@@ -6509,15 +6527,108 @@ int RGWRados::set_attrs(const DoutPrefixProvider *dpp, RGWObjectCtx* octx, RGWBu
65096527 return 0 ;
65106528}
65116529
6530+ static int get_part_obj_state (const DoutPrefixProvider* dpp, optional_yield y,
6531+ RGWRados* store, RGWBucketInfo& bucket_info,
6532+ RGWObjectCtx* rctx, RGWObjManifest* manifest,
6533+ int part_num, int * parts_count, bool prefetch,
6534+ RGWObjState** pstate, RGWObjManifest** pmanifest)
6535+ {
6536+ if (!manifest) {
6537+ return -ERR_INVALID_PART;
6538+ }
6539+ // navigate to the requested part in the manifest
6540+ RGWObjManifest::obj_iterator end = manifest->obj_end (dpp);
6541+ if (end.get_cur_part_id () == 0 ) { // not multipart
6542+ ldpp_dout (dpp, 20 ) << " object does not have a multipart manifest" << dendl;
6543+ return -ERR_INVALID_PART;
6544+ }
6545+ if (parts_count) {
6546+ *parts_count = end.get_cur_part_id () - 1 ;
6547+ }
6548+ ldpp_dout (dpp, 20 ) << " seeking to part #" << part_num
6549+ << " in the object manifest" << dendl;
6550+ RGWObjManifest::obj_iterator iter = manifest->obj_find_part (dpp, part_num);
6551+ if (iter == end) { // part number not found
6552+ ldpp_dout (dpp, 20 ) << " failed to find part #" << part_num
6553+ << " in the object manifest" << dendl;
6554+ return -ERR_INVALID_PART;
6555+ }
6556+ auto head_obj = iter.get_location ().get_head_obj ();
6557+ if (!head_obj) { // iterator points to a tail object
6558+ ldpp_dout (dpp, 20 ) << " object manifest for part #" << part_num
6559+ << " points to a tail object" << dendl;
6560+ return -ERR_INVALID_PART;
6561+ }
6562+ const auto part_offset = iter.get_ofs ();
6563+
6564+ // read the part's head object
6565+ if (prefetch) {
6566+ rctx->set_prefetch_data (*head_obj);
6567+ }
6568+ RGWObjStateManifest* sm = nullptr ;
6569+ constexpr bool follow_olh = false ; // parts aren't versioned
6570+ int r = store->get_obj_state (dpp, rctx, bucket_info, *head_obj,
6571+ &sm, follow_olh, y);
6572+ if (r < 0 ) {
6573+ return r;
6574+ }
6575+ *pstate = &sm->state ;
6576+
6577+ // if the part has its own manifest, use it directly
6578+ if (sm->manifest ) {
6579+ *pmanifest = &*sm->manifest ;
6580+ return 0 ;
6581+ }
6582+
6583+ // create a new manifest for just this part
6584+ sm->manifest .emplace ();
6585+ RGWObjManifest& part_manifest = *sm->manifest ;
6586+ part_manifest.set_multipart_part_rule (iter.get_stripe_size (), part_num);
6587+
6588+ if (auto & prefix = iter.get_cur_override_prefix (); !prefix.empty ()) {
6589+ // the part was reuploaded with a different prefix
6590+ part_manifest.set_prefix (prefix);
6591+ } else {
6592+ part_manifest.set_prefix (manifest->get_prefix ());
6593+ }
6594+
6595+ RGWObjManifest::generator gen;
6596+ gen.create_begin (store->ctx (), &part_manifest,
6597+ manifest->get_head_placement_rule (),
6598+ &manifest->get_tail_placement ().placement_rule ,
6599+ head_obj->bucket , *head_obj);
6600+
6601+ // copy each of the part's stripes into the new manifest. the final call to
6602+ // create_next() uses the starting offset of the next part
6603+ do {
6604+ ++iter;
6605+ gen.create_next (iter.get_ofs () - part_offset);
6606+ } while (iter.get_cur_part_id () == part_num);
6607+
6608+ // update the object size
6609+ sm->state .size = part_manifest.get_obj_size ();
6610+
6611+ *pmanifest = &part_manifest;
6612+ return 0 ;
6613+ }
6614+
65126615int RGWRados::Object::Read::prepare (optional_yield y, const DoutPrefixProvider *dpp)
65136616{
65146617 RGWRados *store = source->get_store ();
65156618 CephContext *cct = store->ctx ();
6619+ RGWObjectCtx& obj_ctx = source->get_ctx ();
65166620
65176621 bufferlist etag;
65186622
65196623 map<string, bufferlist>::iterator iter;
65206624
6625+ bool part_prefetch = false ;
6626+ if (params.part_num ) {
6627+ // prefetch from the part's head object instead of the multipart head
6628+ auto sm = obj_ctx.get_state (source->get_obj ());
6629+ part_prefetch = std::exchange (sm->state .prefetch_data , false );
6630+ }
6631+
65216632 RGWObjState *astate;
65226633 RGWObjManifest *manifest = nullptr ;
65236634 int r = source->get_state (dpp, &astate, &manifest, true , y);
@@ -6528,7 +6639,32 @@ int RGWRados::Object::Read::prepare(optional_yield y, const DoutPrefixProvider *
65286639 return -ENOENT;
65296640 }
65306641
6531- const RGWBucketInfo& bucket_info = source->get_bucket_info ();
6642+ RGWBucketInfo& bucket_info = source->get_bucket_info ();
6643+
6644+ if (params.part_num ) {
6645+ int parts_count = 0 ;
6646+ // use the manifest to redirect to the requested part number
6647+ r = get_part_obj_state (dpp, y, store, bucket_info, &source->get_ctx (),
6648+ manifest, *params.part_num , &parts_count,
6649+ part_prefetch, &astate, &manifest);
6650+ if (r == -ERR_INVALID_PART && *params.part_num == 1 ) {
6651+ // for non-multipart uploads, treat requests for the first part as a
6652+ // request for the entire range. this behavior is expected by the java
6653+ // sdk's TransferManager.download()
6654+ ldpp_dout (dpp, 4 ) << " requested part #" << *params.part_num
6655+ << " : " << cpp_strerror (r) << dendl;
6656+ } else if (r < 0 ) {
6657+ ldpp_dout (dpp, 4 ) << " failed to read part #" << *params.part_num
6658+ << " : " << cpp_strerror (r) << dendl;
6659+ return -ERR_INVALID_PART;
6660+ } else if (!astate->exists ) {
6661+ ldpp_dout (dpp, 4 ) << " part #" << *params.part_num
6662+ << " does not exist" << dendl;
6663+ return -ERR_INVALID_PART;
6664+ } else {
6665+ params.parts_count = parts_count;
6666+ }
6667+ }
65326668
65336669 state.obj = astate->obj ;
65346670 store->obj_to_raw (bucket_info.placement_rule , state.obj , &state.head_obj );
0 commit comments