Skip to content

Commit ce15b5e

Browse files
ddelgrosso1shaffeeullahgcf-owl-bot[bot]
authored
feat: implement parallel operations (#2067) (#2109)
* feat: implement parallel operations (#2067) * feat: implement parallel operations * add more parallel operations * add header to test file * update import of fs/promises * fix pathing on windows, fix mocking of fs promises * add jsdoc headers to class and uploadMulti * add jsdoc comments to remaining functions * update comment wording * add experimental jsdoc tags * feat: add directory generator to performance test framework * clarify variable names and comments * capitalization * wip: transfer manager performance tests * feat: merged in application performance tests (#2100) * fix: fixed many bugs (#2102) * fix: cleaning up bugs * fix: fixed many bugs * fix: more work on transfer manager perf metrics (#2103) * fix: more work on transfer manager perf metrics * fix unit tests for tm * fix: performance test refactoring, comments (#2104) * refactor: refactor constants (#2105) * refactor: refactor constants * bug fixes * bug fixes * bug fixes * linter fixes, download to disk for performance test * rename transfer manager functions * remove callbacks from transfer manager * add more experimental tags, update comments * change signature of downloadManyFiles to accept array of strings or a folder name * linter fix * add transfer manager samples and samples tests Co-authored-by: Sameena Shaffeeullah <[email protected]> * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * feat: add crc32c validation option to chunked download, cleanup naming (#2110) * feat: add crc32c validation option to chunked download, cleanup naming in perf tests * close file in finally block Co-authored-by: Sameena Shaffeeullah <[email protected]> Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 2474615 commit ce15b5e

16 files changed

+1787
-128
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,10 @@ Samples are in the [`samples/`](https://github.com/googleapis/nodejs-storage/tre
131131
| Download Byte Range | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadByteRange.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadByteRange.js,samples/README.md) |
132132
| Download Encrypted File | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadEncryptedFile.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadEncryptedFile.js,samples/README.md) |
133133
| Download File | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadFile.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadFile.js,samples/README.md) |
134+
| Download a File in Chunks Utilzing Transfer Manager | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadFileInChunksWithTransferManager.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadFileInChunksWithTransferManager.js,samples/README.md) |
134135
| Download File Using Requester Pays | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadFileUsingRequesterPays.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadFileUsingRequesterPays.js,samples/README.md) |
135136
| Download Into Memory | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadIntoMemory.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadIntoMemory.js,samples/README.md) |
137+
| Download Many Files With Transfer Manager | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadManyFilesWithTransferManager.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadManyFilesWithTransferManager.js,samples/README.md) |
136138
| Storage Download Public File. | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/downloadPublicFile.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/downloadPublicFile.js,samples/README.md) |
137139
| Enable Bucket Lifecycle Management | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/enableBucketLifecycleManagement.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/enableBucketLifecycleManagement.js,samples/README.md) |
138140
| Storage Enable Bucket Versioning. | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/enableBucketVersioning.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/enableBucketVersioning.js,samples/README.md) |
@@ -207,6 +209,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/nodejs-storage/tre
207209
| Upload File | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/uploadFile.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/uploadFile.js,samples/README.md) |
208210
| Upload File With Kms Key | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/uploadFileWithKmsKey.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/uploadFileWithKmsKey.js,samples/README.md) |
209211
| Upload From Memory | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/uploadFromMemory.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/uploadFromMemory.js,samples/README.md) |
212+
| Upload Many Files With Transfer Manager | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/uploadManyFilesWithTransferManager.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/uploadManyFilesWithTransferManager.js,samples/README.md) |
210213
| Upload Without Authentication | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/uploadWithoutAuthentication.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/uploadWithoutAuthentication.js,samples/README.md) |
211214
| Upload Without Authentication Signed Url | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/uploadWithoutAuthenticationSignedUrl.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/uploadWithoutAuthenticationSignedUrl.js,samples/README.md) |
212215
| View Bucket Iam Members | [source code](https://github.com/googleapis/nodejs-storage/blob/main/samples/viewBucketIamMembers.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-storage&page=editor&open_in_editor=samples/viewBucketIamMembers.js,samples/README.md) |
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*!
2+
* Copyright 2022 Google LLC. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import yargs from 'yargs';
18+
import {promises as fsp, rmSync} from 'fs';
19+
import {Bucket, DownloadOptions, DownloadResponse, UploadOptions} from '../src';
20+
import {performance} from 'perf_hooks';
21+
// eslint-disable-next-line node/no-unsupported-features/node-builtins
22+
import {parentPort} from 'worker_threads';
23+
import {
24+
BLOCK_SIZE_IN_BYTES,
25+
DEFAULT_PROJECT_ID,
26+
DEFAULT_NUMBER_OF_OBJECTS,
27+
DEFAULT_SMALL_FILE_SIZE_BYTES,
28+
DEFAULT_LARGE_FILE_SIZE_BYTES,
29+
NODE_DEFAULT_HIGHWATER_MARK_BYTES,
30+
generateRandomDirectoryStructure,
31+
getValidationType,
32+
performanceTestSetup,
33+
TestResult,
34+
} from './performanceUtils';
35+
import {TRANSFER_MANAGER_TEST_TYPES} from './performanceTest';
36+
37+
const TEST_NAME_STRING = 'nodejs-perf-metrics-application';
38+
const DEFAULT_BUCKET_NAME = 'nodejs-perf-metrics-shaffeeullah';
39+
40+
let bucket: Bucket;
41+
42+
const checkType = getValidationType();
43+
44+
const argv = yargs(process.argv.slice(2))
45+
.options({
46+
bucket: {type: 'string', default: DEFAULT_BUCKET_NAME},
47+
small: {type: 'number', default: DEFAULT_SMALL_FILE_SIZE_BYTES},
48+
large: {type: 'number', default: DEFAULT_LARGE_FILE_SIZE_BYTES},
49+
projectid: {type: 'string', default: DEFAULT_PROJECT_ID},
50+
numobjects: {type: 'number', default: DEFAULT_NUMBER_OF_OBJECTS},
51+
})
52+
.parseSync();
53+
54+
/**
55+
* Main entry point. This function performs a test iteration and posts the message back
56+
* to the parent thread.
57+
*/
58+
async function main() {
59+
let result: TestResult = {
60+
op: '',
61+
objectSize: 0,
62+
appBufferSize: 0,
63+
libBufferSize: 0,
64+
crc32Enabled: false,
65+
md5Enabled: false,
66+
apiName: 'JSON',
67+
elapsedTimeUs: 0,
68+
cpuTimeUs: 0,
69+
status: '[OK]',
70+
};
71+
72+
({bucket} = await performanceTestSetup(argv.projectid, argv.bucket));
73+
74+
switch (argv.testtype) {
75+
case TRANSFER_MANAGER_TEST_TYPES.APPLICATION_UPLOAD_MULTIPLE_OBJECTS:
76+
result = await performWriteTest();
77+
break;
78+
case TRANSFER_MANAGER_TEST_TYPES.APPLICATION_DOWNLOAD_MULTIPLE_OBJECTS:
79+
result = await performReadTest();
80+
break;
81+
// case TRANSFER_MANAGER_TEST_TYPES.APPLICATION_LARGE_FILE_DOWNLOAD:
82+
// result = await performLargeReadTest();
83+
// break;
84+
default:
85+
break;
86+
}
87+
parentPort?.postMessage(result);
88+
}
89+
90+
async function uploadInParallel(
91+
bucket: Bucket,
92+
paths: string[],
93+
options: UploadOptions
94+
) {
95+
const promises = [];
96+
for (const index in paths) {
97+
const path = paths[index];
98+
const stat = await fsp.lstat(path);
99+
if (stat.isDirectory()) {
100+
continue;
101+
}
102+
options.destination = path;
103+
promises.push(bucket.upload(path, options));
104+
}
105+
await Promise.all(promises).catch(console.error);
106+
}
107+
108+
async function downloadInParallel(bucket: Bucket, options: DownloadOptions) {
109+
const promises: Promise<DownloadResponse>[] = [];
110+
const [files] = await bucket.getFiles();
111+
files.forEach(file => {
112+
promises.push(file.download(options));
113+
});
114+
await Promise.all(promises).catch(console.error);
115+
}
116+
117+
/**
118+
* Performs an iteration of the Write multiple objects test.
119+
*
120+
* @returns {Promise<TestResult>} Promise that resolves to a test result of an iteration.
121+
*/
122+
async function performWriteTest(): Promise<TestResult> {
123+
await bucket.deleteFiles(); //start clean
124+
125+
const creationInfo = generateRandomDirectoryStructure(
126+
argv.numobjects,
127+
TEST_NAME_STRING,
128+
argv.small,
129+
argv.large
130+
);
131+
132+
const start = performance.now();
133+
await uploadInParallel(bucket, creationInfo.paths, {validation: checkType});
134+
const end = performance.now();
135+
136+
await bucket.deleteFiles(); //cleanup files
137+
rmSync(TEST_NAME_STRING, {recursive: true, force: true});
138+
139+
const result: TestResult = {
140+
op: 'WRITE',
141+
objectSize: creationInfo.totalSizeInBytes,
142+
appBufferSize: BLOCK_SIZE_IN_BYTES,
143+
libBufferSize: NODE_DEFAULT_HIGHWATER_MARK_BYTES,
144+
crc32Enabled: checkType === 'crc32c',
145+
md5Enabled: checkType === 'md5',
146+
apiName: 'JSON',
147+
elapsedTimeUs: Math.round((end - start) * 1000),
148+
cpuTimeUs: -1,
149+
status: '[OK]',
150+
};
151+
return result;
152+
}
153+
154+
/**
155+
* Performs an iteration of the read multiple objects test.
156+
*
157+
* @returns {Promise<TestResult>} Promise that resolves to an array of test results for the iteration.
158+
*/
159+
async function performReadTest(): Promise<TestResult> {
160+
await bucket.deleteFiles(); // start clean
161+
const creationInfo = generateRandomDirectoryStructure(
162+
argv.numobjects,
163+
TEST_NAME_STRING,
164+
argv.small,
165+
argv.large
166+
);
167+
await uploadInParallel(bucket, creationInfo.paths, {validation: checkType});
168+
169+
const start = performance.now();
170+
await downloadInParallel(bucket, {validation: checkType});
171+
const end = performance.now();
172+
173+
const result: TestResult = {
174+
op: 'READ',
175+
objectSize: creationInfo.totalSizeInBytes,
176+
appBufferSize: BLOCK_SIZE_IN_BYTES,
177+
libBufferSize: NODE_DEFAULT_HIGHWATER_MARK_BYTES,
178+
crc32Enabled: checkType === 'crc32c',
179+
md5Enabled: checkType === 'md5',
180+
apiName: 'JSON',
181+
elapsedTimeUs: Math.round((end - start) * 1000),
182+
cpuTimeUs: -1,
183+
status: '[OK]',
184+
};
185+
186+
rmSync(TEST_NAME_STRING, {recursive: true, force: true});
187+
await bucket.deleteFiles(); //cleanup
188+
return result;
189+
}
190+
191+
main();

0 commit comments

Comments
 (0)