@milaboratories/pl-drivers 1.5.49 → 1.5.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-drivers",
3
- "version": "1.5.49",
3
+ "version": "1.5.51",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },
@@ -30,14 +30,14 @@
30
30
  "tar-fs": "^3.0.8",
31
31
  "undici": "~7.5.0",
32
32
  "zod": "~3.23.8",
33
- "@milaboratories/ts-helpers": "^1.1.7",
34
- "@milaboratories/computable": "^2.4.6",
35
- "@milaboratories/pl-tree": "^1.5.8",
36
- "@milaboratories/pl-client": "^2.8.2",
37
- "@milaboratories/pl-model-common": "^1.13.8"
33
+ "@milaboratories/pl-client": "^2.9.0",
34
+ "@milaboratories/computable": "^2.4.7",
35
+ "@milaboratories/pl-model-common": "^1.14.0",
36
+ "@milaboratories/ts-helpers": "^1.2.0",
37
+ "@milaboratories/pl-tree": "^1.6.0"
38
38
  },
39
39
  "devDependencies": {
40
- "eslint": "^9.23.0",
40
+ "eslint": "^9.25.1",
41
41
  "@types/decompress": "^4.2.7",
42
42
  "typescript": "~5.5.4",
43
43
  "vite": "^5.4.11",
@@ -252,7 +252,7 @@ export class DownloadDriver implements BlobDriver {
252
252
  public getComputableContent(
253
253
  res: ResourceInfo | PlTreeEntry
254
254
  ): ComputableStableDefined<Uint8Array>{
255
- return Computable.make((ctx) =>
255
+ return Computable.make((ctx) =>
256
256
  this.getDownloadedBlob(res, ctx), {
257
257
  postprocessValue: (v) => v ? this.getContent(v.handle) : undefined
258
258
  }
@@ -26,7 +26,7 @@ import { scheduler } from 'node:timers/promises';
26
26
  import type { PollingOps } from './helpers/polling_ops';
27
27
  import type { ImportResourceSnapshot } from './types';
28
28
  import { IndexResourceSnapshot, UploadResourceSnapshot } from './types';
29
- import { nonRecoverableError, UploadTask } from './upload_task';
29
+ import { isMyUpload, nonRecoverableError, UploadTask } from './upload_task';
30
30
  import { WrongResourceTypeError } from './helpers/helpers';
31
31
 
32
32
  export function makeBlobImportSnapshot(
@@ -145,11 +145,12 @@ export class UploadDriver {
145
145
 
146
146
  this.idToProgress.set(res.id, newTask);
147
147
 
148
- if (newTask.shouldScheduleUpload())
148
+ if (newTask.shouldScheduleUpload()) {
149
149
  this.uploadQueue.push({
150
150
  fn: () => newTask.uploadBlobTask(),
151
151
  recoverableErrorPredicate: (e) => !nonRecoverableError(e),
152
152
  });
153
+ }
153
154
 
154
155
  newTask.setDoneIfOutputSet(res);
155
156
  return newTask.getProgress(w, callerId);
@@ -10,6 +10,7 @@ import { MTimeError, NoFileForUploading, UnexpectedEOF } from '../clients/upload
10
10
  import type { ImportResourceSnapshot } from './types';
11
11
  import { ImportFileHandleUploadData } from './types';
12
12
  import assert from 'node:assert';
13
+ import { ResourceInfo } from '@milaboratories/pl-tree';
13
14
 
14
15
  /** Holds all info needed to upload a file and a status of uploading
15
16
  * and indexing. Also, has a method to update a status of the progress.
@@ -58,49 +59,25 @@ export class UploadTask {
58
59
  }
59
60
 
60
61
  public shouldScheduleUpload(): boolean {
61
- return this.progress.isUpload && this.progress.isUploadSignMatch!;
62
+ return isMyUpload(this.progress);
62
63
  }
63
64
 
64
65
  /** Uploads a blob if it's not BlobIndex. */
65
66
  public async uploadBlobTask() {
66
- assert(isUpload(this.res), 'the upload operation can be done only for BlobUploads');
67
- const timeout = 10000; // 10 sec instead of standard 5 sec, things might be slow with a slow connection.
68
-
69
67
  try {
70
- if (this.isComputableDone()) return;
71
- const parts = await this.clientBlob.initUpload(this.res, { timeout });
72
- this.logger.info(
73
- `started to upload blob ${this.res.id},`
74
- + ` parts overall: ${parts.overall}, parts remained: ${parts.toUpload.length},`
75
- + ` number of concurrent uploads: ${this.nMaxUploads}`,
68
+ await uploadBlob(
69
+ this.logger,
70
+ this.clientBlob,
71
+ this.res,
72
+ this.uploadData!,
73
+ this.isComputableDone.bind(this),
74
+ {
75
+ nPartsWithThisUploadSpeed: this.nPartsWithThisUploadSpeed,
76
+ nPartsToIncreaseUpload: this.nPartsToIncreaseUpload,
77
+ currentSpeed: this.nMaxUploads,
78
+ maxSpeed: this.maxNConcurrentPartsUpload,
79
+ },
76
80
  );
77
-
78
- const partUploadFn = (part: bigint) => async (controller: AsyncPoolController) => {
79
- if (this.isComputableDone()) return;
80
- await this.clientBlob.partUpload(
81
- this.res,
82
- this.uploadData!.localPath,
83
- BigInt(this.uploadData!.modificationTime),
84
- part,
85
- { timeout }
86
- );
87
- this.logger.info(`uploaded chunk ${part}/${parts.overall} of resource: ${this.res.id}`);
88
-
89
- // if we had a network freeze, it will be increased slowly.
90
- this.nPartsWithThisUploadSpeed++;
91
- if (this.nPartsWithThisUploadSpeed >= this.nPartsToIncreaseUpload) {
92
- this.nPartsWithThisUploadSpeed = 0;
93
- this.nMaxUploads = increaseConcurrency(this.logger, this.nMaxUploads, this.maxNConcurrentPartsUpload);
94
- controller.setConcurrency(this.nMaxUploads);
95
- }
96
- };
97
-
98
- await asyncPool(this.nMaxUploads, parts.toUpload.map(partUploadFn));
99
-
100
- if (this.isComputableDone()) return;
101
- await this.clientBlob.finalize(this.res, { timeout });
102
-
103
- this.logger.info(`uploading of resource ${this.res.id} finished.`);
104
81
  this.change.markChanged();
105
82
  } catch (e: any) {
106
83
  this.setRetriableError(e);
@@ -207,6 +184,59 @@ export class UploadTask {
207
184
  }
208
185
  }
209
186
 
187
+ /** Uploads a blob if it's not BlobIndex. */
188
+ export async function uploadBlob(
189
+ logger: MiLogger,
190
+ clientBlob: ClientUpload,
191
+ res: ResourceInfo,
192
+ uploadData: ImportFileHandleUploadData,
193
+ isDoneFn: () => boolean,
194
+ speed: {
195
+ nPartsWithThisUploadSpeed: number,
196
+ nPartsToIncreaseUpload: number,
197
+ currentSpeed: number,
198
+ maxSpeed: number,
199
+ },
200
+ ) {
201
+ assert(isUpload(res), 'the upload operation can be done only for BlobUploads');
202
+ const timeout = 10000; // 10 sec instead of standard 5 sec, things might be slow with a slow connection.
203
+
204
+ if (isDoneFn()) return;
205
+ const parts = await clientBlob.initUpload(res, { timeout });
206
+ logger.info(
207
+ `started to upload blob ${res.id},`
208
+ + ` parts overall: ${parts.overall}, parts remained: ${parts.toUpload.length},`
209
+ + ` number of concurrent uploads: ${speed.currentSpeed}`,
210
+ );
211
+
212
+ const partUploadFn = (part: bigint) => async (controller: AsyncPoolController) => {
213
+ if (isDoneFn()) return;
214
+ await clientBlob.partUpload(
215
+ res,
216
+ uploadData.localPath,
217
+ BigInt(uploadData.modificationTime),
218
+ part,
219
+ { timeout }
220
+ );
221
+ logger.info(`uploaded chunk ${part}/${parts.overall} of resource: ${res.id}`);
222
+
223
+ // if we had a network freeze, it will be increased slowly.
224
+ speed.nPartsWithThisUploadSpeed++;
225
+ if (speed.nPartsWithThisUploadSpeed >= speed.nPartsToIncreaseUpload) {
226
+ speed.nPartsWithThisUploadSpeed = 0;
227
+ speed.currentSpeed = increaseConcurrency(logger, speed.currentSpeed, speed.maxSpeed);
228
+ controller.setConcurrency(speed.currentSpeed);
229
+ }
230
+ };
231
+
232
+ await asyncPool(speed.currentSpeed, parts.toUpload.map(partUploadFn));
233
+
234
+ if (isDoneFn()) return;
235
+ await clientBlob.finalize(res, { timeout });
236
+
237
+ logger.info(`uploading of resource ${res.id} finished.`);
238
+ }
239
+
210
240
  function newProgress(res: ImportResourceSnapshot, signer: Signer) {
211
241
  let isUploadSignMatch: boolean | undefined;
212
242
  let uploadData: ImportFileHandleUploadData | undefined;
@@ -223,10 +253,15 @@ function newProgress(res: ImportResourceSnapshot, signer: Signer) {
223
253
  isUpload: isUpload(res),
224
254
  isUploadSignMatch: isUploadSignMatch,
225
255
  lastError: undefined,
226
- },
256
+ } satisfies sdk.ImportProgress,
227
257
  };
228
258
  }
229
259
 
260
+ /** Returns true if we need to upload the blob that got from this progress. */
261
+ export function isMyUpload(p: sdk.ImportProgress): boolean {
262
+ return p.isUpload && (p.isUploadSignMatch ?? false);
263
+ }
264
+
230
265
  /** Creates a deep copy of progress,
231
266
  * since we do not want to pass a mutable object
232
267
  * to API, it led to bugs before.
@@ -256,7 +291,7 @@ function isImportResourceOutputSet(res: ImportResourceSnapshot) {
256
291
  : res.fields.incarnation !== undefined;
257
292
  }
258
293
 
259
- function isUpload(res: ImportResourceSnapshot) {
294
+ function isUpload(res: ResourceInfo) {
260
295
  return res.type.name.startsWith('BlobUpload');
261
296
  }
262
297
 
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export * from './drivers/download_blob';
9
9
  export * from './drivers/download_blob_url/driver';
10
10
  export * from './drivers/download_blob_url/snapshot';
11
11
  export * from './drivers/upload';
12
+ export * from './drivers/upload_task';
12
13
  export * from './drivers/logs_stream';
13
14
  export * from './drivers/logs';
14
15
  export * from './drivers/download_url';