Skip to content

Commit

Permalink
fix(perf): pull hashes without refreshing metadata (#1419)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenplusplus committed Mar 23, 2021
1 parent d0c165c commit f3ec627
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 97 deletions.
68 changes: 39 additions & 29 deletions src/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1211,8 +1211,6 @@ class File extends ServiceObject<File> {
let crc32c = true;
let md5 = false;

let refreshedMetadata = false;

if (typeof options.validation === 'string') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(options as any).validation = (options.validation as string).toLowerCase();
Expand All @@ -1222,6 +1220,8 @@ class File extends ServiceObject<File> {
crc32c = false;
}

const shouldRunValidation = !rangeRequest && (crc32c || md5);

if (rangeRequest) {
if (
typeof options.validation === 'string' ||
Expand Down Expand Up @@ -1268,6 +1268,8 @@ class File extends ServiceObject<File> {
qs: query,
};

const hashes: {crc32c?: string; md5?: string} = {};

this.requestStream(reqOpts)
.on('error', err => {
throughStream.destroy(err);
Expand Down Expand Up @@ -1307,10 +1309,22 @@ class File extends ServiceObject<File> {

const headers = rawResponseStream.toJSON().headers;
isServedCompressed = headers['content-encoding'] === 'gzip';
const shouldRunValidation = !rangeRequest && (crc32c || md5);
const throughStreams: Writable[] = [];

if (shouldRunValidation) {
// The x-goog-hash header should be set with a crc32c and md5 hash.
// ex: headers['x-goog-hash'] = 'crc32c=xxxx,md5=xxxx'
if (typeof headers['x-goog-hash'] === 'string') {
headers['x-goog-hash']
.split(',')
.forEach((hashKeyValPair: string) => {
const delimiterIndex = hashKeyValPair.indexOf('=');
const hashType = hashKeyValPair.substr(0, delimiterIndex);
const hashValue = hashKeyValPair.substr(delimiterIndex + 1);
hashes[hashType as 'crc32c' | 'md5'] = hashValue;
});
}

validateStream = hashStreamValidation({crc32c, md5});
throughStreams.push(validateStream);
}
Expand Down Expand Up @@ -1338,46 +1352,42 @@ class File extends ServiceObject<File> {
// our chance to validate the data and let the user know if anything went
// wrong.
let onCompleteCalled = false;
const onComplete = (err: Error | null) => {
if (err) {
onCompleteCalled = true;
throughStream.destroy(err);
const onComplete = async (err: Error | null) => {
if (onCompleteCalled) {
return;
}

if (rangeRequest) {
onCompleteCalled = true;
throughStream.end();
return;
}
onCompleteCalled = true;

if (!refreshedMetadata) {
refreshedMetadata = true;
this.getMetadata({userProject: options.userProject}, onComplete);
if (err) {
throughStream.destroy(err);
return;
}

if (onCompleteCalled) {
if (rangeRequest || !shouldRunValidation) {
throughStream.end();
return;
}

onCompleteCalled = true;

// TODO(https://github.com/googleapis/nodejs-storage/issues/709):
// Remove once the backend issue is fixed.
// If object is stored compressed (having metadata.contentEncoding === 'gzip')
// and was served decompressed, then skip checksum validation because the
// remote checksum is computed against the compressed version of the object.
if (this.metadata.contentEncoding === 'gzip' && !isServedCompressed) {
throughStream.end();
return;
// If object is stored compressed (having
// metadata.contentEncoding === 'gzip') and was served decompressed,
// then skip checksum validation because the remote checksum is computed
// against the compressed version of the object.
if (!isServedCompressed) {
try {
await this.getMetadata({userProject: options.userProject});
} catch (e) {
throughStream.destroy(e);
return;
}
if (this.metadata.contentEncoding === 'gzip') {
throughStream.end();
return;
}
}

const hashes = {
crc32c: this.metadata.crc32c,
md5: this.metadata.md5Hash,
};

// If we're doing validation, assume the worst-- a data integrity
// mismatch. If not, these tests won't be performed, and we can assume
// the best.
Expand Down
Loading

0 comments on commit f3ec627

Please sign in to comment.