Skip to content

Commit 1ef3996

Browse files
author
gavinhgchen
committed
Add SetCheckPartCrc64() for MultiPutObjectReq
1 parent 890ad7b commit 1ef3996

File tree

6 files changed

+90
-36
lines changed

6 files changed

+90
-36
lines changed

include/op/file_upload_task.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ class FileUploadTask : public Poco::Runnable {
8282
void SetCaLocation(const std::string& ca_location);
8383
void SetSslCtxCb(SSLCtxCallback cb, void *data);
8484

85+
void SetPartCrc64(uint64_t crc64) {
86+
m_part_crc64 = crc64;
87+
}
88+
8589
private:
8690
std::string m_full_url;
8791
std::map<std::string, std::string> m_headers;
@@ -104,6 +108,8 @@ class FileUploadTask : public Poco::Runnable {
104108
std::string m_ca_location;
105109
SSLCtxCallback m_ssl_ctx_cb;
106110
void *m_user_data;
111+
112+
uint64_t m_part_crc64;
107113
};
108114

109115
} // namespace qcloud_cos

include/op/object_op.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ class ObjectOp : public BaseOp {
430430
const std::vector<std::string>& already_exist_parts,
431431
bool resume_flag, std::vector<std::string>* etags_ptr,
432432
std::vector<uint64_t>* part_numbers_ptr,
433+
uint64_t& crc64_file,
433434
const SharedTransferHandler& handler = nullptr,
434435
bool change_backup_domain = false);
435436

@@ -445,7 +446,8 @@ class ObjectOp : public BaseOp {
445446
void FillUploadTask(const std::string& upload_id, const std::string& host,
446447
const std::string& path, unsigned char* file_content_buf,
447448
uint64_t len, uint64_t part_number,
448-
FileUploadTask* task_ptr, bool sign_header_host);
449+
FileUploadTask* task_ptr, bool sign_header_host,
450+
uint64_t crc64);
449451

450452
void FillCopyTask(const std::string& upload_id, const std::string& host,
451453
const std::string& path, uint64_t part_number,

include/request/object_req.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ class PutObjectByFileReq : public PutObjectReq {
375375
#if defined(_WIN32)
376376
mb_is_widechar_path = false;
377377
#endif
378+
mb_check_part_crc64 = false;
378379
}
379380

380381
virtual ~PutObjectByFileReq() {}
@@ -392,6 +393,15 @@ class PutObjectByFileReq : public PutObjectReq {
392393
m_local_file_path = local_file_path;
393394
}
394395

396+
// MultiPutObjectReq: use crc64 instead of md5 for consistency check
397+
void SetCheckPartCrc64(bool part_crc64) {
398+
mb_check_part_crc64 = part_crc64;
399+
}
400+
401+
bool CheckPartCrc64() const {
402+
return mb_check_part_crc64;
403+
}
404+
395405
std::string GetLocalFilePath() const { return m_local_file_path; }
396406

397407
#if defined(_WIN32)
@@ -411,6 +421,7 @@ class PutObjectByFileReq : public PutObjectReq {
411421
#if defined(_WIN32)
412422
bool mb_is_widechar_path; // 标识文件路径是否为宽字符
413423
#endif
424+
bool mb_check_part_crc64;
414425
};
415426

416427
class DeleteObjectReq : public ObjectReq {

src/op/file_upload_task.cpp

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "util/http_sender.h"
77
#include "util/string_util.h"
88
#include "util/codec_util.h"
9+
#include "util/crc64.h"
910
#ifdef USE_OPENSSL_MD5
1011
#include <openssl/md5.h>
1112
#endif
@@ -32,7 +33,8 @@ FileUploadTask::FileUploadTask(const std::string& full_url,
3233
m_verify_cert(verify_cert),
3334
m_ca_location(ca_location),
3435
m_ssl_ctx_cb(ssl_ctx_cb),
35-
m_user_data(user_data) {}
36+
m_user_data(user_data),
37+
m_part_crc64(0) {}
3638

3739
FileUploadTask::FileUploadTask(
3840
const std::string& full_url,
@@ -58,7 +60,8 @@ FileUploadTask::FileUploadTask(
5860
m_verify_cert(verify_cert),
5961
m_ca_location(ca_location),
6062
m_ssl_ctx_cb(ssl_ctx_cb),
61-
m_user_data(user_data) {}
63+
m_user_data(user_data),
64+
m_part_crc64(0) {}
6265

6366
FileUploadTask::FileUploadTask(
6467
const std::string& full_url,
@@ -84,7 +87,8 @@ FileUploadTask::FileUploadTask(
8487
m_verify_cert(verify_cert),
8588
m_ca_location(ca_location),
8689
m_ssl_ctx_cb(ssl_ctx_cb),
87-
m_user_data(user_data) {}
90+
m_user_data(user_data),
91+
m_part_crc64(0) {}
8892

8993
void FileUploadTask::run() {
9094
m_resp = "";
@@ -154,12 +158,13 @@ void FileUploadTask::SetSslCtxCb(SSLCtxCallback cb, void *data) {
154158

155159
void FileUploadTask::UploadTask() {
156160
std::string md5_str;
157-
#ifdef USE_OPENSSL_MD5
158-
unsigned char digest[MD5_DIGEST_LENGTH];
159-
MD5((const unsigned char *)m_data_buf_ptr, m_data_len, digest);
160-
md5_str = CodecUtil::DigestToHex(digest, MD5_DIGEST_LENGTH);
161-
#else
162-
{
161+
// 没有crc64则默认走md5校验
162+
if (m_part_crc64 == 0) {
163+
#ifdef USE_OPENSSL_MD5
164+
unsigned char digest[MD5_DIGEST_LENGTH];
165+
MD5((const unsigned char *)m_data_buf_ptr, m_data_len, digest);
166+
md5_str = CodecUtil::DigestToHex(digest, MD5_DIGEST_LENGTH);
167+
#else
163168
// 计算上传的md5
164169
Poco::MD5Engine md5;
165170
std::string body((const char*)m_data_buf_ptr, m_data_len);
@@ -168,8 +173,8 @@ void FileUploadTask::UploadTask() {
168173
Poco::StreamCopier::copyStream(istr, dos);
169174
dos.close();
170175
md5_str = Poco::DigestEngine::digestToHex(md5.digest());
176+
#endif
171177
}
172-
#endif
173178

174179
int loop = 0;
175180
do {
@@ -204,16 +209,31 @@ void FileUploadTask::UploadTask() {
204209
continue;
205210
}
206211

207-
std::map<std::string, std::string>::const_iterator c_itr =
208-
m_resp_headers.find("ETag");
209-
if (c_itr == m_resp_headers.end() ||
210-
StringUtil::Trim(c_itr->second, "\"") != md5_str) {
211-
SDK_LOG_ERR(
212-
"Response etag is not correct, try again. Expect md5 is %s, but "
213-
"return etag is %s.",
214-
md5_str.c_str(), StringUtil::Trim(c_itr->second, "\"").c_str());
215-
m_is_task_success = false;
216-
continue;
212+
// crc64一致性校验
213+
if (m_part_crc64 != 0) {
214+
std::map<std::string, std::string>::const_iterator c_itr =
215+
m_resp_headers.find(kRespHeaderXCosHashCrc64Ecma);
216+
if (c_itr == m_resp_headers.end() ||
217+
StringUtil::StringToUint64(c_itr->second) != m_part_crc64) {
218+
SDK_LOG_ERR(
219+
"Response x-cos-hash-crc64ecma is not correct, try again. Expect crc64 is %" PRIu64 ", but "
220+
"return crc64 is %s",
221+
m_part_crc64, c_itr->second.c_str());
222+
m_is_task_success = false;
223+
continue;
224+
}
225+
} else {
226+
std::map<std::string, std::string>::const_iterator c_itr =
227+
m_resp_headers.find("ETag");
228+
if (c_itr == m_resp_headers.end() ||
229+
StringUtil::Trim(c_itr->second, "\"") != md5_str) {
230+
SDK_LOG_ERR(
231+
"Response etag is not correct, try again. Expect md5 is %s, but "
232+
"return etag is %s.",
233+
md5_str.c_str(), StringUtil::Trim(c_itr->second, "\"").c_str());
234+
m_is_task_success = false;
235+
continue;
236+
}
217237
}
218238

219239
m_is_task_success = true;

src/op/object_op.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -704,9 +704,11 @@ CosResult ObjectOp::MultiUploadObject(const PutObjectByFileReq& req,
704704
}
705705

706706
CosResult upload_result;
707+
708+
uint64_t crc64_origin = 0;
707709
upload_result =
708710
MultiThreadUpload(req, resume_uploadid, already_exist_parts, resume_flag,
709-
&etags, &part_numbers, handler, change_backup_domain);
711+
&etags, &part_numbers, crc64_origin, handler, change_backup_domain);
710712
// Cancel way
711713
if (handler && !handler->ShouldContinue()) {
712714
SetResultAndLogError(upload_result, "Request canceled by user");
@@ -759,16 +761,6 @@ CosResult ObjectOp::MultiUploadObject(const PutObjectByFileReq& req,
759761
// check crc64 if needed
760762
if (req.CheckCRC64() && comp_result.IsSucc() &&
761763
!comp_resp.GetXCosHashCrc64Ecma().empty()) {
762-
uint64_t crc64_origin = 0;
763-
#if defined(_WIN32)
764-
if (req.IsWideCharPath()) {
765-
crc64_origin = FileUtil::GetFileCrc64(req.GetWideCharLocalFilePath());
766-
} else {
767-
crc64_origin = FileUtil::GetFileCrc64(req.GetLocalFilePath());
768-
}
769-
#else
770-
crc64_origin = FileUtil::GetFileCrc64(req.GetLocalFilePath());
771-
#endif
772764
uint64_t crc64_server_resp =
773765
StringUtil::StringToUint64(comp_resp.GetXCosHashCrc64Ecma());
774766
if (crc64_server_resp != crc64_origin) {
@@ -1704,6 +1696,7 @@ CosResult ObjectOp::MultiThreadUpload(
17041696
const std::vector<std::string>& already_exist_parts, bool resume_flag,
17051697
std::vector<std::string>* etags_ptr,
17061698
std::vector<uint64_t>* part_numbers_ptr,
1699+
uint64_t& crc64_file,
17071700
const SharedTransferHandler& handler,
17081701
bool change_backup_domain) {
17091702
CosResult result;
@@ -1790,6 +1783,7 @@ CosResult ObjectOp::MultiThreadUpload(
17901783

17911784
Poco::ThreadPool tp(pool_size);
17921785

1786+
crc64_file = 0;
17931787
// 3. 多线程upload
17941788
{
17951789
uint64_t part_number = 1;
@@ -1813,6 +1807,7 @@ CosResult ObjectOp::MultiThreadUpload(
18131807
", offset=%" PRIu64 ", len=%" PRIu64,
18141808
task_index, file_size, offset, read_len);
18151809

1810+
uint64_t crc64_part = 0;
18161811
// Check the resume
18171812
FileUploadTask* ptask = pptaskArr[task_index];
18181813

@@ -1828,11 +1823,25 @@ CosResult ObjectOp::MultiThreadUpload(
18281823
handler->UpdateProgress(read_len);
18291824
}
18301825
} else {
1826+
// 计算每个part的crc64值
1827+
if (req.CheckPartCrc64()) {
1828+
crc64_part = CRC64::CalcCRC(crc64_part, static_cast<void*>(file_content_buf[task_index]), read_len);
1829+
}
18311830
FillUploadTask(upload_id, host, path, file_content_buf[task_index],
1832-
read_len, part_number, ptask, req.SignHeaderHost());
1831+
read_len, part_number, ptask, req.SignHeaderHost(), crc64_part);
18331832
tp.start(*ptask);
18341833
}
18351834

1835+
// 根据每个part流式计算整个文件的crc64值
1836+
if (req.CheckCRC64()) {
1837+
// 如果已经计算了part的crc64值,只需要直接流式合并即可
1838+
if (crc64_part != 0) {
1839+
crc64_file = CRC64::CombineCRC(crc64_file, crc64_part, read_len);
1840+
} else {
1841+
crc64_file = CRC64::CalcCRC(crc64_file, static_cast<void*>(file_content_buf[task_index]), read_len);
1842+
}
1843+
}
1844+
18361845
offset += read_len;
18371846
part_numbers_ptr->push_back(part_number);
18381847
++part_number;
@@ -1987,8 +1996,10 @@ CosResult ObjectOp::SingleThreadUpload(
19871996
part_number, file_size, offset, read_len);
19881997

19891998
// 提前计算整个文件的crc64,用于整个合并分块完成后做crc64校验
1990-
crc64 = CRC64::CalcCRC(crc64, static_cast<void*>(file_content_buf),
1991-
static_cast<size_t>(read_len));
1999+
if (req.CheckCRC64()) {
2000+
crc64 = CRC64::CalcCRC(crc64, static_cast<void*>(file_content_buf),
2001+
static_cast<size_t>(read_len));
2002+
}
19922003

19932004
// Check the resume
19942005

@@ -2082,7 +2093,8 @@ uint64_t ObjectOp::GetContent(const std::string& src,
20822093
void ObjectOp::FillUploadTask(const std::string& upload_id,
20832094
const std::string& host, const std::string& path,
20842095
unsigned char* file_content_buf, uint64_t len,
2085-
uint64_t part_number, FileUploadTask* task_ptr, bool sign_header_host) {
2096+
uint64_t part_number, FileUploadTask* task_ptr,
2097+
bool sign_header_host, uint64_t crc64) {
20862098
std::map<std::string, std::string> req_params;
20872099
req_params.insert(std::make_pair("uploadId", upload_id));
20882100
req_params.insert(
@@ -2113,6 +2125,7 @@ void ObjectOp::FillUploadTask(const std::string& upload_id,
21132125
task_ptr->AddHeaders(req_headers);
21142126
task_ptr->SetUploadBuf(file_content_buf, len);
21152127
task_ptr->SetPartNumber(part_number);
2128+
task_ptr->SetPartCrc64(crc64);
21162129
}
21172130

21182131
void ObjectOp::FillCopyTask(const std::string& upload_id,

unittest/src/object_op_test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,7 @@ TEST_F(ObjectOpTest, MultiPutObjectTest_OneStep) {
22512251
// 2. 上传
22522252
MultiPutObjectReq req(m_bucket_name, object_name, filename);
22532253
req.SetXCosServerSideEncryption("AES256");
2254+
req.SetCheckPartCrc64(true);
22542255
MultiPutObjectResp resp;
22552256

22562257
CosResult result = m_client->MultiPutObject(req, &resp);
@@ -3430,6 +3431,7 @@ TEST_F(ObjectOpTest, MultiUploadVaryPartSizeAndThreadPoolSize) {
34303431
MultiPutObjectReq multiupload_req(m_bucket_name, object_name, local_file);
34313432
MultiPutObjectResp multiupload_resp;
34323433
ASSERT_TRUE(multiupload_req.CheckCRC64());
3434+
multiupload_req.SetCheckPartCrc64(true);
34333435

34343436
// upload object
34353437
CosResult multiupload_result =

0 commit comments

Comments
 (0)