Skip to content

Commit 1a693aa

Browse files
thiyaguk09gemini-code-assist[bot]pearigee
authored
feat(storage): Set CRC32C as the default checksum option (#7547)
* fix-Set crc32c as the default option * code fix Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Gabe Pearhill <86282859+pearigee@users.noreply.github.com>
1 parent 4ab95d8 commit 1a693aa

2 files changed

Lines changed: 66 additions & 6 deletions

File tree

handwritten/storage/src/transfer-manager.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export interface UploadFileInChunksOptions {
129129
uploadId?: string;
130130
autoAbortFailure?: boolean;
131131
partsMap?: Map<number, string>;
132-
validation?: 'md5' | false;
132+
validation?: 'md5' | 'crc32c' | false;
133133
headers?: {[key: string]: string};
134134
}
135135

@@ -142,7 +142,7 @@ export interface MultiPartUploadHelper {
142142
uploadPart(
143143
partNumber: number,
144144
chunk: Buffer,
145-
validation?: 'md5' | false,
145+
validation?: 'md5' | 'crc32c' | false,
146146
): Promise<void>;
147147
completeUpload(): Promise<GaxiosResponse | undefined>;
148148
abortUpload(): Promise<void>;
@@ -291,7 +291,7 @@ class XMLMultiPartUploadHelper implements MultiPartUploadHelper {
291291
async uploadPart(
292292
partNumber: number,
293293
chunk: Buffer,
294-
validation?: 'md5' | false,
294+
validation?: 'md5' | 'crc32c' | false,
295295
): Promise<void> {
296296
const url = `${this.baseUrl}?partNumber=${partNumber}&uploadId=${this.uploadId}`;
297297
let headers: Headers = this.#setGoogApiClientHeaders();
@@ -301,6 +301,10 @@ class XMLMultiPartUploadHelper implements MultiPartUploadHelper {
301301
headers = {
302302
'Content-MD5': hash,
303303
};
304+
} else if (validation === 'crc32c') {
305+
const crc = new CRC32C();
306+
crc.update(chunk);
307+
headers['x-goog-hash'] = `crc32c=${crc.toString()}`;
304308
}
305309

306310
return AsyncRetry(async bail => {
@@ -900,6 +904,7 @@ export class TransferManager {
900904
);
901905
let partNumber = 1;
902906
let promises: Promise<void>[] = [];
907+
const validation = options.validation ?? 'crc32c';
903908
try {
904909
if (options.uploadId === undefined) {
905910
await mpuHelper.initiateUpload(options.headers);
@@ -917,9 +922,7 @@ export class TransferManager {
917922
promises = [];
918923
}
919924
promises.push(
920-
limit(() =>
921-
mpuHelper.uploadPart(partNumber++, curChunk, options.validation),
922-
),
925+
limit(() => mpuHelper.uploadPart(partNumber++, curChunk, validation))
923926
);
924927
}
925928
await Promise.all(promises);

handwritten/storage/test/transfer-manager.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,5 +938,62 @@ describe('Transfer Manager', () => {
938938

939939
assert(called);
940940
});
941+
942+
it('should use CRC32C validation when specified', async () => {
943+
mockGeneratorFunction = (bucket, fileName, uploadId, partsMap) => {
944+
fakeHelper = sandbox.createStubInstance(FakeXMLHelper);
945+
fakeHelper.uploadId = uploadId || '';
946+
fakeHelper.partsMap = partsMap || new Map<number, string>();
947+
fakeHelper.initiateUpload.resolves();
948+
fakeHelper.uploadPart.callsFake((partNumber, chunk, validation) => {
949+
assert.strictEqual(validation, 'crc32c');
950+
951+
return Promise.resolve();
952+
});
953+
fakeHelper.completeUpload.resolves();
954+
fakeHelper.abortUpload.resolves();
955+
return fakeHelper;
956+
};
957+
958+
await transferManager.uploadFileInChunks(
959+
filePath,
960+
{validation: 'crc32c'},
961+
mockGeneratorFunction
962+
);
963+
964+
assert.strictEqual(fakeHelper.uploadPart.calledOnce, true);
965+
});
966+
967+
it('should apply crc32c validation by default', async () => {
968+
let assertionMade = false;
969+
970+
mockGeneratorFunction = (bucket, fileName, uploadId, partsMap) => {
971+
fakeHelper = sandbox.createStubInstance(FakeXMLHelper);
972+
fakeHelper.uploadId = uploadId || '';
973+
fakeHelper.partsMap = partsMap || new Map<number, string>();
974+
fakeHelper.initiateUpload.resolves();
975+
976+
fakeHelper.uploadPart.callsFake((partNumber, chunk, validation) => {
977+
// Confirm the validation is set to 'crc32c' by default.
978+
assert.strictEqual(validation, 'crc32c');
979+
assertionMade = true;
980+
return Promise.resolve();
981+
});
982+
983+
fakeHelper.completeUpload.resolves();
984+
fakeHelper.abortUpload.resolves();
985+
return fakeHelper;
986+
};
987+
988+
// Call the function without specifying any validation option.
989+
await transferManager.uploadFileInChunks(
990+
filePath,
991+
{},
992+
mockGeneratorFunction
993+
);
994+
995+
assert.strictEqual(fakeHelper.uploadPart.calledOnce, true);
996+
assert.strictEqual(assertionMade, true);
997+
});
941998
});
942999
});

0 commit comments

Comments
 (0)