Skip to content

Commit 342d2c9

Browse files
Merge pull request #173 from tencentyun/feature_huberyxxiao_ae9ba00c
新增单线程断点上传接口
2 parents fcd7941 + 7559917 commit 342d2c9

File tree

13 files changed

+539
-16
lines changed

13 files changed

+539
-16
lines changed

demo/object_op_demo/multi_put_object_demo.cpp

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,9 @@ void AsyncPutObjectDemo(qcloud_cos::CosAPI& cos) {
278278
/*
279279
* 该 Demo 示范用户如何自行组合分块上传各接口进行对象上传
280280
* 分块操作基于初始化、上传分块、完成分块三个接口可以实现将对象切分为多个分块,然后再将这些分块上传到 cos,最后发起 Complete 完成分块上传
281-
* 与本节中的高级上传接口配置一样,可通过全局设置上传线程池大小、分块大小。该上传线程池上是每次上传独立的。
282281
* 本 Demo 中的上传分块接口 UploadPartData 仅支持传入流,最多支持10000分块,每个分块大小为1MB - 5GB,最后一个分块可以小于1MB
283282
*/
283+
284284
void PutPartDemo(qcloud_cos::CosAPI& cos) {
285285
std::string object_name = "big_file.txt";
286286

@@ -295,19 +295,36 @@ void PutPartDemo(qcloud_cos::CosAPI& cos) {
295295

296296
// 2. UploadPartData
297297
// UploadPartData 部分,可以根据实际选择分块数量和分块大小,这里以 2 个分块为例
298+
299+
// Complete 需要的两个列表:
298300
std::vector<std::string> etags;
299301
std::vector<uint64_t> part_numbers;
302+
300303
std::string upload_id = init_resp.GetUploadId();
301304
{
302305
uint64_t part_number = 1;
303-
// 模拟上传分块数据,这里以 1M 为例
304-
std::vector<char> data(1024 * 1024, 'A');
306+
// 模拟上传分块数据,这里以 100M 为例
307+
uint64_t copy_size = 1024 * 1024 * 100;
308+
std::vector<char> data(copy_size, 'A');
305309
std::string content(data.begin(), data.end());
306310
std::istringstream iss(content);
307311
qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
308312
req.SetPartNumber(part_number);
313+
// 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
314+
uint64_t traffic_limit = 8192*1024*10; // 100MB 文件 5M
315+
req.SetTrafficLimit(traffic_limit);
309316
qcloud_cos::UploadPartDataResp resp;
317+
std::chrono::time_point<std::chrono::steady_clock> start_ts, end_ts;
318+
start_ts = std::chrono::steady_clock::now();
310319
qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
320+
end_ts = std::chrono::steady_clock::now();
321+
auto time_consumed_ms =
322+
std::chrono::duration_cast<std::chrono::milliseconds>(end_ts - start_ts)
323+
.count();
324+
float rate =
325+
((float)copy_size / 1024 / 1024) / ((float)time_consumed_ms / 1000);
326+
SDK_LOG_ERR("send part_number: %d, send_size: %" PRIu64 " MB, time_consumed: %" PRIu64
327+
" ms, rate: %.2f MB/s , traffic_limit : %.2f MB", part_number, copy_size/ 1024 / 1024, time_consumed_ms, rate, traffic_limit/1024/1024/8.0);
311328
std::cout << "==================UploadPartDataResp1=====================" << std::endl;
312329
PrintResult(result, resp);
313330
std::cout << "==========================================================" << std::endl;
@@ -318,12 +335,38 @@ void PutPartDemo(qcloud_cos::CosAPI& cos) {
318335
}
319336
{
320337
uint64_t part_number = 2;
321-
std::istringstream iss("The last part can be smaller than 1MB");
338+
uint64_t copy_size = 1024 * 1024 * 100;
339+
std::vector<char> data(copy_size, 'A');
340+
std::string content(data.begin(), data.end());
341+
std::istringstream iss(content);
322342
qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
323343
req.SetPartNumber(part_number);
344+
// 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
345+
uint64_t traffic_limit = 8192 * 1024 * 5 ;
346+
req.SetTrafficLimit(traffic_limit);
347+
qcloud_cos::UploadPartDataResp resp;
348+
qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
349+
std::cout << "==================UploadPartDataResp2=====================" << std::endl;
350+
PrintResult(result, resp);
351+
std::cout << "==========================================================" << std::endl;
352+
if (result.IsSucc()) {
353+
part_numbers.push_back(part_number);
354+
etags.push_back(resp.GetEtag());
355+
}
356+
}
357+
{
358+
uint64_t part_number = 3;
359+
uint64_t copy_size = 1024 * 1024 * 10;
360+
std::vector<char> data(copy_size, 'A');
361+
std::string content(data.begin(), data.end());
362+
std::istringstream iss(content);
363+
qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
364+
req.SetPartNumber(part_number);
365+
// 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
366+
uint64_t traffic_limit = 8192 * 1024;
367+
req.SetTrafficLimit(traffic_limit);
324368
qcloud_cos::UploadPartDataResp resp;
325369
qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
326-
327370
std::cout << "==================UploadPartDataResp2=====================" << std::endl;
328371
PrintResult(result, resp);
329372
std::cout << "==========================================================" << std::endl;
@@ -348,11 +391,48 @@ void PutPartDemo(qcloud_cos::CosAPI& cos) {
348391

349392
return;
350393
}
394+
void PutObjectResumableSingleThreadSyncDemo(qcloud_cos::CosAPI& cos) {
395+
std::string local_file = "SingleThreadSync.txt";
396+
std::string object_name = "SingleThreadSync.txt";
397+
398+
qcloud_cos::PutObjectResumableSingleSyncReq req(bucket_name, object_name, local_file);
399+
req.AddHeader("x-cos-meta-ssss1","1xxxxxxx");
400+
req.AddHeader("x-cos-meta-ssss2","2xxxxxxx");
401+
req.AddHeader("x-cos-meta-ssss3","3xxxxxxx");
402+
req.AddHeader("x-cos-meta-ssss4","4xxxxxxx");
403+
uint64_t traffic_limit = 8192 * 1024;//1MB
404+
req.SetTrafficLimit(traffic_limit);
405+
//req.SetHttps();
406+
//req.SetSSLCtxCallback(SslCtxCallback, nullptr);
407+
qcloud_cos::PutObjectResumableSingleSyncResp resp;
408+
qcloud_cos::CosResult result = cos.PutObjectResumableSingleThreadSync(req, &resp);
409+
if (result.IsSucc()) {
410+
std::cout << "MultiUpload Succ." << std::endl;
411+
std::cout << resp.GetLocation() << std::endl;
412+
std::cout << resp.GetKey() << std::endl;
413+
std::cout << resp.GetBucket() << std::endl;
414+
std::cout << resp.GetEtag() << std::endl;
415+
} else {
416+
std::cout << "MultiUpload Fail." << std::endl;
417+
// 获取具体失败在哪一步
418+
std::string resp_tag = resp.GetRespTag();
419+
if ("Init" == resp_tag) {
420+
// print result
421+
} else if ("Upload" == resp_tag) {
422+
// print result
423+
} else if ("Complete" == resp_tag) {
424+
// print result
425+
}
426+
PrintResult(result, resp);
427+
}
428+
std::cout << "===========================================================" << std::endl;
429+
}
351430
int main() {
352431
qcloud_cos::CosAPI cos = InitCosAPI();
353432
CosSysConfig::SetLogLevel((LOG_LEVEL)COS_LOG_ERR);
354433
MultiUploadObjectDemo(cos);
355434
AsyncMultiPutObjectDemo(cos);
356435
AsyncPutObjectDemo(cos);
357436
PutPartDemo(cos);
358-
}
437+
PutObjectResumableSingleThreadSyncDemo(cos);
438+
}

include/cos_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@ class CosAPI {
758758
CosResult MultiGetObject(const MultiGetObjectReq& req,
759759
MultiGetObjectResp* resp);
760760

761+
CosResult PutObjectResumableSingleThreadSync(const PutObjectResumableSingleSyncReq& req,
762+
PutObjectResumableSingleSyncResp* resp);
763+
761764
/* Resumable接口 */
762765

763766
/// \brief 封装了初始化分块上传、分块上传、完成分块上传三步,支持断点续传

include/cos_defines.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
namespace qcloud_cos {
1414

15-
#define COS_CPP_SDK_VERSON "v5.5.15"
15+
#define COS_CPP_SDK_VERSON "v5.5.16"
1616

1717
/// 路径分隔符
1818
const char kPathDelimiter[] = "/";

include/op/object_op.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ class ObjectOp : public BaseOp {
180180
const SharedTransferHandler& handler = nullptr,
181181
bool change_backup_domain = false);
182182

183+
/// \brief 单线程同步分块上传
184+
///
185+
/// \return result
186+
CosResult UploadObjectResumableSingleThreadSync(const PutObjectByFileReq& req,
187+
PutObjectResumableSingleSyncResp* resp);
188+
183189
/// \brief 舍弃一个分块上传并删除已上传的块
184190
///
185191
/// \param req AbortMultiUpload请求
@@ -427,6 +433,11 @@ class ObjectOp : public BaseOp {
427433
const SharedTransferHandler& handler = nullptr,
428434
bool change_backup_domain = false);
429435

436+
CosResult SingleThreadUpload(const PutObjectByFileReq& req, const std::string& upload_id,
437+
const std::vector<std::string>& already_exist_parts,
438+
bool resume_flag, std::vector<std::string>* etags_ptr,
439+
std::vector<uint64_t>* part_numbers_ptr, PutObjectByFileResp* resp);
440+
430441
/// \brief 读取文件内容, 并返回读取的长度
431442
// uint64_t GetContent(const std::string& src, std::string* file_content) const;
432443

include/request/object_req.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,17 @@ class MultiGetObjectReq : public GetObjectByFileReq {
17221722
virtual ~MultiGetObjectReq() {}
17231723
};
17241724

1725+
class PutObjectResumableSingleSyncReq : public PutObjectByFileReq {
1726+
public:
1727+
PutObjectResumableSingleSyncReq(const std::string& bucket_name,
1728+
const std::string& object_name,
1729+
const std::string& local_file_path)
1730+
: PutObjectByFileReq(bucket_name, object_name, local_file_path) {
1731+
SetCheckCRC64(true);
1732+
}
1733+
virtual ~PutObjectResumableSingleSyncReq() {}
1734+
};
1735+
17251736
/* Async接口 */
17261737

17271738
#if 0

include/response/object_resp.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,41 @@ class MultiGetObjectResp : public GetObjectByFileResp {
670670
~MultiGetObjectResp() {}
671671
};
672672

673+
class PutObjectResumableSingleSyncResp : public GetObjectByFileResp {
674+
public:
675+
PutObjectResumableSingleSyncResp() {}
676+
677+
virtual ~PutObjectResumableSingleSyncResp() {}
678+
679+
std::string GetRespTag() { return m_resp_tag; }
680+
681+
std::string GetLocation() const { return m_location; }
682+
683+
std::string GetKey() const { return m_key; }
684+
685+
std::string GetBucket() const { return m_bucket; }
686+
687+
void CopyFrom(const InitMultiUploadResp& resp);
688+
689+
void CopyFrom(const PutObjectByFileResp& resp);
690+
691+
void CopyFrom(const CompleteMultiUploadResp& resp);
692+
693+
/// \brief Server端加密使用的算法
694+
std::string GetXCosServerSideEncryption() const {
695+
return GetHeader("x-cos-server-side-encryption");
696+
}
697+
698+
private:
699+
std::string m_location; // Object的外网访问域名
700+
std::string m_bucket;
701+
std::string m_key;
702+
std::string m_upload_id;
703+
704+
// FIXME(sevenyou) 先这么搞吧
705+
std::string m_resp_tag; // 用于区分是哪一种response
706+
};
707+
673708
/* Async接口 */
674709

675710
//typedef PutObjectByFileResp PutObjectAsyncResp;

src/cos_api.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,11 @@ CosResult CosAPI::MultiPutObject(const MultiPutObjectReq& req,
586586
return result;
587587
}
588588

589+
CosResult CosAPI::PutObjectResumableSingleThreadSync(const PutObjectResumableSingleSyncReq& req,
590+
PutObjectResumableSingleSyncResp* resp){
591+
return m_object_op.UploadObjectResumableSingleThreadSync(static_cast<PutObjectByFileReq>(req), resp);
592+
}
593+
589594
CosResult CosAPI::AbortMultiUpload(const AbortMultiUploadReq& req,
590595
AbortMultiUploadResp* resp) {
591596
CosResult result = m_object_op.AbortMultiUpload(req, resp);

0 commit comments

Comments
 (0)