在 Ceph 对象存储网关(RGW)处理分段上传(Multipart Upload)请求时,获取已创建的分段上传任务的元信息是一个关键步骤。该功能主要由 get_multipart_info() 函数完成,其核心职责是读取并解析存储在 .rgw.non-ec 池中的分段上传元数据对象,这些数据包含了访问控制列表(ACL)、数据布局规则(placement rule)以及其他必要的元数据。
get_multipart_info() 函数入口
首先,我们来看 get_multipart_info 函数的初始入口。该函数接收一个元数据对象的名称(meta_oid),并将其封装为 rgw_obj 对象,然后调用其重载版本。
static int get_multipart_info(RGWRados *store, struct req_state *s,
const string& meta_oid,
RGWAccessControlPolicy *policy,
map<string, bufferlist> *attrs,
multipart_upload_info *upload_info)
{
map<string, bufferlist>::iterator iter;
bufferlist header;
rgw_obj meta_obj;
meta_obj.init_ns(s->bucket, meta_oid, mp_ns); // mp_ns是RGW_OBJ_NS_MULTIPART,也就是multipart
meta_obj.set_in_extra_data(true);
return get_multipart_info(store, s, meta_obj, policy, attrs, upload_info);
}

在实际调用前,通常会有如下步骤,将对象名和上传ID初始化为一个 RGWMPObj,并从中获取元数据对象名。
RGWMPObj mp(s->object.name, multipart_upload_id);
op_ret = get_multipart_info(store, s, mp.get_meta(), nullptr, nullptr, &upload_info);
mp.get_meta() 的返回格式通常为 oid.upload_id.meta,这即是传入上述函数的 meta_oid 参数。
核心逻辑:读取并解析对象数据
封装好 rgw_obj 后,程序调用另一个重载的 get_multipart_info() 函数执行核心操作。这个函数主要分为两步:从存储后端读取对象头数据,然后解析其中的关键信息。
static int get_multipart_info(RGWRados *store, struct req_state *s,
const rgw_obj& obj,
RGWAccessControlPolicy *policy,
map<string, bufferlist> *attrs,
multipart_upload_info *upload_info)
{
// ... 变量声明等准备工作
int op_ret = get_obj_head(store, s, obj, attrs, pheadbl);
// ... 错误处理
// 1. 解析分段上传信息(multipart_upload_info)
if (upload_info && headbl.length() > 0) {
auto hiter = headbl.cbegin();
try {
decode(*upload_info, hiter);
}
// ... 异常捕获
}
// 2. 解析访问控制策略(ACL)
if (policy && attrs) {
for (auto& iter : *attrs) {
string name = iter.first;
if (name.compare(RGW_ATTR_ACL) == 0) {
bufferlist& bl = iter.second;
auto bli = bl.cbegin();
try {
decode(*policy, bli);
}
// ... 异常捕获
}
}
}
return 0;
}

get_obj_head 的内部工作
get_obj_head 函数是数据读取的关键,它主要调用了 RGWRados::Object::Read::prepare() 和 RGWRados::Object::Read::read() 两个方法。
-
prepare() 阶段:
- 确定需要读取的元数据对象在
.rgw.non-ec 池中的完整路径。该路径格式通常为 “<bucket_id>_” + “_multipart_” + <key-name> + “.” + <upload_id> + “.meta”,此对象正是在 init-multipart 阶段创建的临时元数据对象。
- 校验来自 HTTP 请求头(如
If-Match、If-None-Match 等)的读取条件。
-
read() 阶段:
- 向 Ceph 存储集群下发一个同步读请求,获取该元数据对象的全部内容(一个
bufferlist)。
信息解析与用途
在成功读取数据后,get_multipart_info 函数会进行解码:
multipart_upload_info:此结构体包含了目标对象遵循的数据放置规则(placement rule),这对于后续上传的分段(Part)数据写入哪个存储池至关重要。
RGWAccessControlPolicy:从对象的扩展属性(RGW_ATTR_ACL)中解码得出,定义了该分段上传任务的访问权限。
通过以上流程,RGW 便能够完整地恢复出一个分段上传任务的上下文信息,为后续的上传段(Upload Part)、完成分段上传(Complete Multipart Upload)等操作提供必要的依据。