为了便于说明,以代码默认的4M为例
- prepare
// prepare主要完成对manifest的初始化处理。
AtomicObjectProcessor::prepare
// 获取数据池的名称:head_pool
// alignment : rados对齐方式, 假设64K对齐。max_head_chunk_size : head的最大长度,假设为4M
// 假设 head_max_size = chunk_size = max_head_chunk_size = 4M
// stripe_size = 4M
manifest.set_trivial_rule(head_max_size, stripe_size);
// RGWObjManifestRule rule(0, 4M, 0, 4M); rules[0] = rule; max_head_size = 4M
manifest_gen.create_begin(store->ctx(), &manifest, bucket_info.placement_rule, &tail_placement_rule, head_obj.bucket, head_obj);
// manifest 填入数据: placement_rule bucket head_placement_rule obj head_size=0 last_ofs=0 prefix cur_stripe_size=4M cur_part_id=0
manifest->get_implicit_location(0, 4M, 0, NULL, &cur_obj);
rgw_raw_obj stripe_obj = manifest_gen.get_cur_obj(store->getRados());
r = writer.set_stripe_obj(stripe_obj); // RadosWriter writer;
chunk = ChunkProcessor(&writer, 4M);
stripe = StripeProcessor(&chunk, this, 4M);
// 此时manifest的处理如下
manifest.set_trivial_rule(head_max_size, stripe_size);
RGWObjManifestRule rule(0, 4M, 0, 4M); // start_part_num=0 start_ofs=4M part_size=0 stripe_max_size=4M
rules[0] = rule;
max_head_size = tail_ofs; // 4M
RGWObjManifest::generator::create_begin
manifest->set_tail_placement // tail_placement.placement_rule = placement_rule; tail_placement.bucket = _b;
manifest->set_head(head_placement_rule, _obj, 0); // head_size = 0
last_ofs = 0;
生成随机的prefix
此时head_size为0,cur_stripe_size = rule.stripe_max_size; // 4M
cur_part_id = rule.start_part_num; // 0
RGWObjManifest::get_implicit_location(0, 0, 0, nullptr, &cur_obj)
cur_obj->set_placement_rule(head_placement_rule);
*cur_obj = obj;
manifest->set_tail_instance(_obj.key.instance); // tail_instance
manifest->update_iterators(); // begin_iter.seek(0); end_iter.seek(obj_size); 此时obj_size=0
- 循环写对象到rados
fst = copy_source_range_fst; // 如果是range则该值不为0,否则为0
lst = copy_source_range_lst // 非copy或是range。非copy并且非range也要lst=0
lst = astate->accounted_size - 1; // copy但不是range
boost::optional<RGWPutObj_Compress> compressor; // 压缩,append不支持
std::unique_ptr<DataProcessor> encrypt; // 加密,如果加密和压缩都需要的情况下,则加密优先。append不支持。
DataProcessor *filter = processor.get(); // 默认既不加密也不压缩
op_ret = get_encrypt_filter(&encrypt, filter); // RGWPutObj_ObjStore_S3::get_encrypt_filter。filter作为pipe的成员变量
// 分片上传
res = get_obj_attrs(store, s, obj, xattrs); // 获取.meta的属性
res = rgw_s3_prepare_decrypt(s, xattrs, &block_crypt, crypt_http_responses);
filter->reset(new RGWPutObj_BlockEncrypt(s->cct, cb, std::move(block_crypt)));
// 整体上传
res = rgw_s3_prepare_encrypt(s, attrs, nullptr, &block_crypt, crypt_http_responses);
filter->reset(new RGWPutObj_BlockEncrypt(s->cct, cb, std::move(block_crypt)));
if (encrypt != nullptr) {
filter = &*encrypt;
} else if (compression_type != "none") {
plugin = get_compressor_plugin(s, compression_type);
compressor.emplace(s->cct, plugin, filter);
filter = &*compressor;
}
// 以下流程不考虑加密和压缩
do {
bufferlist data;
if (fst > lst) break;
// 非copy
len = get_data(data); // RGWPutObj_ObjStore_S3::get_data , 从消息中读取数据
// copy
uint64_t cur_lst = min(fst + s->cct->_conf->rgw_max_chunk_size - 1, lst);
op_ret = get_data(fst, cur_lst, data); // RGWPutObj::get_data , 从本rados读取数据
len = data.length();
s->content_length += len;
fst += len;
// len如果为0,说明读写完成
if (need_calc_md5) {
hash.Update((const unsigned char *)data.c_str(), data.length());
}
/* update torrrent */
torrent.update(data);
op_ret = filter->process(std::move(data), ofs); // HeadObjectProcessor::process
ofs += len;
} while (len > 0);
op_ret = filter->process({}, ofs); // 把尾部数据写入rados(chunk里面还有的数据)
// 写完成,在complete中需要写first_chunk以及meta
op_ret = processor->complete(s->obj_size, etag, &mtime, real_time(), attrs,
(delete_at ? *delete_at : real_time()), if_match, if_nomatch,
(user_data.empty() ? nullptr : &user_data), nullptr, nullptr, s->yield);
ret = rgw::notify::publish(s, obj.key, s->obj_size, mtime, etag, rgw::notify::ObjectCreatedPut, store);