@milaboratories/pl-middle-layer 1.64.28 → 1.64.29
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/dist/middle_layer/driver_kit.cjs +3 -1
- package/dist/middle_layer/driver_kit.cjs.map +1 -1
- package/dist/middle_layer/driver_kit.js +3 -1
- package/dist/middle_layer/driver_kit.js.map +1 -1
- package/dist/middle_layer/ops.cjs +8 -2
- package/dist/middle_layer/ops.cjs.map +1 -1
- package/dist/middle_layer/ops.d.ts +15 -3
- package/dist/middle_layer/ops.d.ts.map +1 -1
- package/dist/middle_layer/ops.js +8 -2
- package/dist/middle_layer/ops.js.map +1 -1
- package/dist/pool/driver.cjs +20 -8
- package/dist/pool/driver.cjs.map +1 -1
- package/dist/pool/driver.d.ts +8 -1
- package/dist/pool/driver.d.ts.map +1 -1
- package/dist/pool/driver.js +20 -8
- package/dist/pool/driver.js.map +1 -1
- package/dist/pool/index.d.ts +1 -1
- package/package.json +13 -13
- package/src/middle_layer/driver_kit.ts +2 -0
- package/src/middle_layer/ops.ts +27 -2
- package/src/pool/driver.ts +28 -11
|
@@ -32,7 +32,9 @@ async function initDriverKit(pl, workdir, frontendDownloadPath, _ops) {
|
|
|
32
32
|
blobDriver,
|
|
33
33
|
logger: ops.logger,
|
|
34
34
|
spillPath: ops.pframesSpillPath,
|
|
35
|
-
|
|
35
|
+
cachePath: ops.parquetCachePath,
|
|
36
|
+
options: ops.pFrameDriverOps,
|
|
37
|
+
cacheOps: ops.parquetCacheOps
|
|
36
38
|
}),
|
|
37
39
|
frontendDriver: new _milaboratories_pl_drivers.DownloadUrlDriver(ops.logger, pl.httpDispatcher, frontendDownloadPath, signer, ops.frontendDownloadDriverOps)
|
|
38
40
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver_kit.cjs","names":["DefaultDriverKitOpsSettings","DefaultDriverKitOpsPaths","HmacSha256Signer","DownloadDriver","DownloadBlobToURLDriver","UploadDriver","LogsStreamDriver","LogsDriver","LsDriver","createPFrameDriver","DownloadUrlDriver"],"sources":["../../src/middle_layer/driver_kit.ts"],"sourcesContent":["import type { PlClient } from \"@milaboratories/pl-client\";\nimport type { InternalLsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n createDownloadClient,\n createLogsClient,\n createUploadBlobClient,\n createUploadProgressClient,\n DownloadDriver,\n DownloadBlobToURLDriver,\n LogsDriver,\n LogsStreamDriver,\n LsDriver,\n UploadDriver,\n DownloadUrlDriver,\n} from \"@milaboratories/pl-drivers\";\nimport type * as Sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { isAsyncDisposable } from \"@milaboratories/helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { InternalPFrameDriver } from \"../pool\";\nimport { createPFrameDriver } from \"../pool\";\nimport type { DriverKitOps, DriverKitOpsConstructor } from \"./ops\";\nimport { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings } from \"./ops\";\n\n/**\n * Drivers offered by the middle-layer for internal consumers,\n * like configuration rendering routines.\n *\n * This intertface is basically a version of the DriverKit from\n * UI SDK with extended API.\n * */\nexport interface MiddleLayerDriverKit extends Sdk.DriverKit, AsyncDisposable {\n /** Dispose the driver kit and all its resources. */\n dispose(): Promise<void>;\n\n // override with wider interface\n readonly blobDriver: DownloadDriver;\n // override with wider interface\n readonly blobToURLDriver: DownloadBlobToURLDriver;\n // override with wider interface\n readonly logDriver: LogsDriver;\n // override with wider interface\n readonly lsDriver: InternalLsDriver;\n // override with wider interface\n readonly pFrameDriver: InternalPFrameDriver;\n // override with wider interface\n readonly frontendDriver: DownloadUrlDriver;\n\n /**\n * Signer is initialized from local secret in drivers initialization routine,\n * so constitutes a part of the driver kit\n * */\n readonly signer: Signer;\n\n /**\n * Used to retrieve upload progress, and initiate upload porecesses driven by\n * upload requests from block outputs.\n * */\n readonly uploadDriver: UploadDriver;\n}\n\nexport async function initDriverKit(\n pl: PlClient,\n workdir: string,\n frontendDownloadPath: string,\n _ops: DriverKitOpsConstructor,\n): Promise<MiddleLayerDriverKit> {\n const ops: DriverKitOps = {\n ...DefaultDriverKitOpsSettings,\n ...DefaultDriverKitOpsPaths(workdir),\n ..._ops,\n };\n\n const signer = new HmacSha256Signer(ops.localSecret);\n\n const downloadClient = createDownloadClient(ops.logger, pl, ops.localProjections);\n const logsClient = createLogsClient(pl, ops.logger);\n const uploadBlobClient = createUploadBlobClient(pl, ops.logger);\n const uploadProgressClient = createUploadProgressClient(pl, ops.logger);\n\n const blobDriver = await DownloadDriver.init(\n ops.logger,\n downloadClient,\n logsClient,\n ops.blobDownloadPath,\n ops.blobDownloadRangesCachePath,\n signer,\n ops.blobDriverOps,\n );\n\n const blobToURLDriver = new DownloadBlobToURLDriver(\n ops.logger,\n signer,\n downloadClient,\n ops.downloadBlobToURLPath,\n ops.downloadBlobToURLDriverOps,\n );\n\n const uploadDriver = new UploadDriver(\n ops.logger,\n signer,\n uploadBlobClient,\n uploadProgressClient,\n ops.uploadDriverOps,\n );\n const logsStreamDriver = new LogsStreamDriver(ops.logger, logsClient, ops.logStreamDriverOps);\n const logDriver = new LogsDriver(ops.logger, logsStreamDriver, blobDriver);\n const lsDriver = await LsDriver.init(\n ops.logger,\n pl,\n signer,\n ops.localProjections,\n ops.openFileDialogCallback,\n ops.virtualLocalStoragesOverride,\n );\n\n const pFrameDriver = await createPFrameDriver({\n blobDriver,\n logger: ops.logger,\n spillPath: ops.pframesSpillPath,\n options: ops.pFrameDriverOps,\n });\n\n const frontendDownloadDriver = new DownloadUrlDriver(\n ops.logger,\n pl.httpDispatcher,\n frontendDownloadPath,\n signer,\n ops.frontendDownloadDriverOps,\n );\n\n const driverKit = {\n blobDriver,\n blobToURLDriver: blobToURLDriver,\n logDriver,\n lsDriver,\n signer,\n uploadDriver,\n pFrameDriver,\n frontendDriver: frontendDownloadDriver,\n };\n\n const dispose = async () => {\n const disposePromises = Object.values(driverKit).flatMap((driver) =>\n isAsyncDisposable(driver) ? [driver[Symbol.asyncDispose]()] : [],\n );\n await Promise.all(disposePromises);\n };\n\n return {\n ...driverKit,\n dispose,\n [Symbol.asyncDispose]: dispose,\n };\n}\n"],"mappings":";;;;;;;;AA6DA,eAAsB,cACpB,IACA,SACA,sBACA,MAC+B;CAC/B,MAAM,MAAoB;EACxB,GAAGA,YAAAA;EACH,GAAGC,YAAAA,yBAAyB,QAAQ;EACpC,GAAG;EACJ;CAED,MAAM,SAAS,IAAIC,2BAAAA,iBAAiB,IAAI,YAAY;CAEpD,MAAM,kBAAA,GAAA,2BAAA,sBAAsC,IAAI,QAAQ,IAAI,IAAI,iBAAiB;CACjF,MAAM,cAAA,GAAA,2BAAA,kBAA8B,IAAI,IAAI,OAAO;CACnD,MAAM,oBAAA,GAAA,2BAAA,wBAA0C,IAAI,IAAI,OAAO;CAC/D,MAAM,wBAAA,GAAA,2BAAA,4BAAkD,IAAI,IAAI,OAAO;CAEvE,MAAM,aAAa,MAAMC,2BAAAA,eAAe,KACtC,IAAI,QACJ,gBACA,YACA,IAAI,kBACJ,IAAI,6BACJ,QACA,IAAI,cACL;CAED,MAAM,kBAAkB,IAAIC,2BAAAA,wBAC1B,IAAI,QACJ,QACA,gBACA,IAAI,uBACJ,IAAI,2BACL;CAED,MAAM,eAAe,IAAIC,2BAAAA,aACvB,IAAI,QACJ,QACA,kBACA,sBACA,IAAI,gBACL;CACD,MAAM,mBAAmB,IAAIC,2BAAAA,iBAAiB,IAAI,QAAQ,YAAY,IAAI,mBAAmB;
|
|
1
|
+
{"version":3,"file":"driver_kit.cjs","names":["DefaultDriverKitOpsSettings","DefaultDriverKitOpsPaths","HmacSha256Signer","DownloadDriver","DownloadBlobToURLDriver","UploadDriver","LogsStreamDriver","LogsDriver","LsDriver","createPFrameDriver","DownloadUrlDriver"],"sources":["../../src/middle_layer/driver_kit.ts"],"sourcesContent":["import type { PlClient } from \"@milaboratories/pl-client\";\nimport type { InternalLsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n createDownloadClient,\n createLogsClient,\n createUploadBlobClient,\n createUploadProgressClient,\n DownloadDriver,\n DownloadBlobToURLDriver,\n LogsDriver,\n LogsStreamDriver,\n LsDriver,\n UploadDriver,\n DownloadUrlDriver,\n} from \"@milaboratories/pl-drivers\";\nimport type * as Sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { isAsyncDisposable } from \"@milaboratories/helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { InternalPFrameDriver } from \"../pool\";\nimport { createPFrameDriver } from \"../pool\";\nimport type { DriverKitOps, DriverKitOpsConstructor } from \"./ops\";\nimport { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings } from \"./ops\";\n\n/**\n * Drivers offered by the middle-layer for internal consumers,\n * like configuration rendering routines.\n *\n * This intertface is basically a version of the DriverKit from\n * UI SDK with extended API.\n * */\nexport interface MiddleLayerDriverKit extends Sdk.DriverKit, AsyncDisposable {\n /** Dispose the driver kit and all its resources. */\n dispose(): Promise<void>;\n\n // override with wider interface\n readonly blobDriver: DownloadDriver;\n // override with wider interface\n readonly blobToURLDriver: DownloadBlobToURLDriver;\n // override with wider interface\n readonly logDriver: LogsDriver;\n // override with wider interface\n readonly lsDriver: InternalLsDriver;\n // override with wider interface\n readonly pFrameDriver: InternalPFrameDriver;\n // override with wider interface\n readonly frontendDriver: DownloadUrlDriver;\n\n /**\n * Signer is initialized from local secret in drivers initialization routine,\n * so constitutes a part of the driver kit\n * */\n readonly signer: Signer;\n\n /**\n * Used to retrieve upload progress, and initiate upload porecesses driven by\n * upload requests from block outputs.\n * */\n readonly uploadDriver: UploadDriver;\n}\n\nexport async function initDriverKit(\n pl: PlClient,\n workdir: string,\n frontendDownloadPath: string,\n _ops: DriverKitOpsConstructor,\n): Promise<MiddleLayerDriverKit> {\n const ops: DriverKitOps = {\n ...DefaultDriverKitOpsSettings,\n ...DefaultDriverKitOpsPaths(workdir),\n ..._ops,\n };\n\n const signer = new HmacSha256Signer(ops.localSecret);\n\n const downloadClient = createDownloadClient(ops.logger, pl, ops.localProjections);\n const logsClient = createLogsClient(pl, ops.logger);\n const uploadBlobClient = createUploadBlobClient(pl, ops.logger);\n const uploadProgressClient = createUploadProgressClient(pl, ops.logger);\n\n const blobDriver = await DownloadDriver.init(\n ops.logger,\n downloadClient,\n logsClient,\n ops.blobDownloadPath,\n ops.blobDownloadRangesCachePath,\n signer,\n ops.blobDriverOps,\n );\n\n const blobToURLDriver = new DownloadBlobToURLDriver(\n ops.logger,\n signer,\n downloadClient,\n ops.downloadBlobToURLPath,\n ops.downloadBlobToURLDriverOps,\n );\n\n const uploadDriver = new UploadDriver(\n ops.logger,\n signer,\n uploadBlobClient,\n uploadProgressClient,\n ops.uploadDriverOps,\n );\n const logsStreamDriver = new LogsStreamDriver(ops.logger, logsClient, ops.logStreamDriverOps);\n const logDriver = new LogsDriver(ops.logger, logsStreamDriver, blobDriver);\n const lsDriver = await LsDriver.init(\n ops.logger,\n pl,\n signer,\n ops.localProjections,\n ops.openFileDialogCallback,\n ops.virtualLocalStoragesOverride,\n );\n\n const pFrameDriver = await createPFrameDriver({\n blobDriver,\n logger: ops.logger,\n spillPath: ops.pframesSpillPath,\n cachePath: ops.parquetCachePath,\n options: ops.pFrameDriverOps,\n cacheOps: ops.parquetCacheOps,\n });\n\n const frontendDownloadDriver = new DownloadUrlDriver(\n ops.logger,\n pl.httpDispatcher,\n frontendDownloadPath,\n signer,\n ops.frontendDownloadDriverOps,\n );\n\n const driverKit = {\n blobDriver,\n blobToURLDriver: blobToURLDriver,\n logDriver,\n lsDriver,\n signer,\n uploadDriver,\n pFrameDriver,\n frontendDriver: frontendDownloadDriver,\n };\n\n const dispose = async () => {\n const disposePromises = Object.values(driverKit).flatMap((driver) =>\n isAsyncDisposable(driver) ? [driver[Symbol.asyncDispose]()] : [],\n );\n await Promise.all(disposePromises);\n };\n\n return {\n ...driverKit,\n dispose,\n [Symbol.asyncDispose]: dispose,\n };\n}\n"],"mappings":";;;;;;;;AA6DA,eAAsB,cACpB,IACA,SACA,sBACA,MAC+B;CAC/B,MAAM,MAAoB;EACxB,GAAGA,YAAAA;EACH,GAAGC,YAAAA,yBAAyB,QAAQ;EACpC,GAAG;EACJ;CAED,MAAM,SAAS,IAAIC,2BAAAA,iBAAiB,IAAI,YAAY;CAEpD,MAAM,kBAAA,GAAA,2BAAA,sBAAsC,IAAI,QAAQ,IAAI,IAAI,iBAAiB;CACjF,MAAM,cAAA,GAAA,2BAAA,kBAA8B,IAAI,IAAI,OAAO;CACnD,MAAM,oBAAA,GAAA,2BAAA,wBAA0C,IAAI,IAAI,OAAO;CAC/D,MAAM,wBAAA,GAAA,2BAAA,4BAAkD,IAAI,IAAI,OAAO;CAEvE,MAAM,aAAa,MAAMC,2BAAAA,eAAe,KACtC,IAAI,QACJ,gBACA,YACA,IAAI,kBACJ,IAAI,6BACJ,QACA,IAAI,cACL;CAED,MAAM,kBAAkB,IAAIC,2BAAAA,wBAC1B,IAAI,QACJ,QACA,gBACA,IAAI,uBACJ,IAAI,2BACL;CAED,MAAM,eAAe,IAAIC,2BAAAA,aACvB,IAAI,QACJ,QACA,kBACA,sBACA,IAAI,gBACL;CACD,MAAM,mBAAmB,IAAIC,2BAAAA,iBAAiB,IAAI,QAAQ,YAAY,IAAI,mBAAmB;CA4B7F,MAAM,YAAY;EAChB;EACiB;EACjB,WA9BgB,IAAIC,2BAAAA,WAAW,IAAI,QAAQ,kBAAkB,WAAW;EA+BxE,UA9Be,MAAMC,2BAAAA,SAAS,KAC9B,IAAI,QACJ,IACA,QACA,IAAI,kBACJ,IAAI,wBACJ,IAAI,6BACL;EAwBC;EACA;EACA,cAxBmB,MAAMC,eAAAA,mBAAmB;GAC5C;GACA,QAAQ,IAAI;GACZ,WAAW,IAAI;GACf,WAAW,IAAI;GACf,SAAS,IAAI;GACb,UAAU,IAAI;GACf,CAAC;EAkBA,gBAhB6B,IAAIC,2BAAAA,kBACjC,IAAI,QACJ,GAAG,gBACH,sBACA,QACA,IAAI,0BACL;EAWA;CAED,MAAM,UAAU,YAAY;EAC1B,MAAM,kBAAkB,OAAO,OAAO,UAAU,CAAC,SAAS,YAAA,GAAA,wBAAA,mBACtC,OAAO,GAAG,CAAC,OAAO,OAAO,eAAe,CAAC,GAAG,EAAE,CACjE;AACD,QAAM,QAAQ,IAAI,gBAAgB;;AAGpC,QAAO;EACL,GAAG;EACH;GACC,OAAO,eAAe;EACxB"}
|
|
@@ -31,7 +31,9 @@ async function initDriverKit(pl, workdir, frontendDownloadPath, _ops) {
|
|
|
31
31
|
blobDriver,
|
|
32
32
|
logger: ops.logger,
|
|
33
33
|
spillPath: ops.pframesSpillPath,
|
|
34
|
-
|
|
34
|
+
cachePath: ops.parquetCachePath,
|
|
35
|
+
options: ops.pFrameDriverOps,
|
|
36
|
+
cacheOps: ops.parquetCacheOps
|
|
35
37
|
}),
|
|
36
38
|
frontendDriver: new DownloadUrlDriver(ops.logger, pl.httpDispatcher, frontendDownloadPath, signer, ops.frontendDownloadDriverOps)
|
|
37
39
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver_kit.js","names":[],"sources":["../../src/middle_layer/driver_kit.ts"],"sourcesContent":["import type { PlClient } from \"@milaboratories/pl-client\";\nimport type { InternalLsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n createDownloadClient,\n createLogsClient,\n createUploadBlobClient,\n createUploadProgressClient,\n DownloadDriver,\n DownloadBlobToURLDriver,\n LogsDriver,\n LogsStreamDriver,\n LsDriver,\n UploadDriver,\n DownloadUrlDriver,\n} from \"@milaboratories/pl-drivers\";\nimport type * as Sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { isAsyncDisposable } from \"@milaboratories/helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { InternalPFrameDriver } from \"../pool\";\nimport { createPFrameDriver } from \"../pool\";\nimport type { DriverKitOps, DriverKitOpsConstructor } from \"./ops\";\nimport { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings } from \"./ops\";\n\n/**\n * Drivers offered by the middle-layer for internal consumers,\n * like configuration rendering routines.\n *\n * This intertface is basically a version of the DriverKit from\n * UI SDK with extended API.\n * */\nexport interface MiddleLayerDriverKit extends Sdk.DriverKit, AsyncDisposable {\n /** Dispose the driver kit and all its resources. */\n dispose(): Promise<void>;\n\n // override with wider interface\n readonly blobDriver: DownloadDriver;\n // override with wider interface\n readonly blobToURLDriver: DownloadBlobToURLDriver;\n // override with wider interface\n readonly logDriver: LogsDriver;\n // override with wider interface\n readonly lsDriver: InternalLsDriver;\n // override with wider interface\n readonly pFrameDriver: InternalPFrameDriver;\n // override with wider interface\n readonly frontendDriver: DownloadUrlDriver;\n\n /**\n * Signer is initialized from local secret in drivers initialization routine,\n * so constitutes a part of the driver kit\n * */\n readonly signer: Signer;\n\n /**\n * Used to retrieve upload progress, and initiate upload porecesses driven by\n * upload requests from block outputs.\n * */\n readonly uploadDriver: UploadDriver;\n}\n\nexport async function initDriverKit(\n pl: PlClient,\n workdir: string,\n frontendDownloadPath: string,\n _ops: DriverKitOpsConstructor,\n): Promise<MiddleLayerDriverKit> {\n const ops: DriverKitOps = {\n ...DefaultDriverKitOpsSettings,\n ...DefaultDriverKitOpsPaths(workdir),\n ..._ops,\n };\n\n const signer = new HmacSha256Signer(ops.localSecret);\n\n const downloadClient = createDownloadClient(ops.logger, pl, ops.localProjections);\n const logsClient = createLogsClient(pl, ops.logger);\n const uploadBlobClient = createUploadBlobClient(pl, ops.logger);\n const uploadProgressClient = createUploadProgressClient(pl, ops.logger);\n\n const blobDriver = await DownloadDriver.init(\n ops.logger,\n downloadClient,\n logsClient,\n ops.blobDownloadPath,\n ops.blobDownloadRangesCachePath,\n signer,\n ops.blobDriverOps,\n );\n\n const blobToURLDriver = new DownloadBlobToURLDriver(\n ops.logger,\n signer,\n downloadClient,\n ops.downloadBlobToURLPath,\n ops.downloadBlobToURLDriverOps,\n );\n\n const uploadDriver = new UploadDriver(\n ops.logger,\n signer,\n uploadBlobClient,\n uploadProgressClient,\n ops.uploadDriverOps,\n );\n const logsStreamDriver = new LogsStreamDriver(ops.logger, logsClient, ops.logStreamDriverOps);\n const logDriver = new LogsDriver(ops.logger, logsStreamDriver, blobDriver);\n const lsDriver = await LsDriver.init(\n ops.logger,\n pl,\n signer,\n ops.localProjections,\n ops.openFileDialogCallback,\n ops.virtualLocalStoragesOverride,\n );\n\n const pFrameDriver = await createPFrameDriver({\n blobDriver,\n logger: ops.logger,\n spillPath: ops.pframesSpillPath,\n options: ops.pFrameDriverOps,\n });\n\n const frontendDownloadDriver = new DownloadUrlDriver(\n ops.logger,\n pl.httpDispatcher,\n frontendDownloadPath,\n signer,\n ops.frontendDownloadDriverOps,\n );\n\n const driverKit = {\n blobDriver,\n blobToURLDriver: blobToURLDriver,\n logDriver,\n lsDriver,\n signer,\n uploadDriver,\n pFrameDriver,\n frontendDriver: frontendDownloadDriver,\n };\n\n const dispose = async () => {\n const disposePromises = Object.values(driverKit).flatMap((driver) =>\n isAsyncDisposable(driver) ? [driver[Symbol.asyncDispose]()] : [],\n );\n await Promise.all(disposePromises);\n };\n\n return {\n ...driverKit,\n dispose,\n [Symbol.asyncDispose]: dispose,\n };\n}\n"],"mappings":";;;;;;;AA6DA,eAAsB,cACpB,IACA,SACA,sBACA,MAC+B;CAC/B,MAAM,MAAoB;EACxB,GAAG;EACH,GAAG,yBAAyB,QAAQ;EACpC,GAAG;EACJ;CAED,MAAM,SAAS,IAAI,iBAAiB,IAAI,YAAY;CAEpD,MAAM,iBAAiB,qBAAqB,IAAI,QAAQ,IAAI,IAAI,iBAAiB;CACjF,MAAM,aAAa,iBAAiB,IAAI,IAAI,OAAO;CACnD,MAAM,mBAAmB,uBAAuB,IAAI,IAAI,OAAO;CAC/D,MAAM,uBAAuB,2BAA2B,IAAI,IAAI,OAAO;CAEvE,MAAM,aAAa,MAAM,eAAe,KACtC,IAAI,QACJ,gBACA,YACA,IAAI,kBACJ,IAAI,6BACJ,QACA,IAAI,cACL;CAED,MAAM,kBAAkB,IAAI,wBAC1B,IAAI,QACJ,QACA,gBACA,IAAI,uBACJ,IAAI,2BACL;CAED,MAAM,eAAe,IAAI,aACvB,IAAI,QACJ,QACA,kBACA,sBACA,IAAI,gBACL;CACD,MAAM,mBAAmB,IAAI,iBAAiB,IAAI,QAAQ,YAAY,IAAI,mBAAmB;
|
|
1
|
+
{"version":3,"file":"driver_kit.js","names":[],"sources":["../../src/middle_layer/driver_kit.ts"],"sourcesContent":["import type { PlClient } from \"@milaboratories/pl-client\";\nimport type { InternalLsDriver } from \"@milaboratories/pl-drivers\";\nimport {\n createDownloadClient,\n createLogsClient,\n createUploadBlobClient,\n createUploadProgressClient,\n DownloadDriver,\n DownloadBlobToURLDriver,\n LogsDriver,\n LogsStreamDriver,\n LsDriver,\n UploadDriver,\n DownloadUrlDriver,\n} from \"@milaboratories/pl-drivers\";\nimport type * as Sdk from \"@milaboratories/pl-model-common\";\nimport type { Signer } from \"@milaboratories/ts-helpers\";\nimport { isAsyncDisposable } from \"@milaboratories/helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { InternalPFrameDriver } from \"../pool\";\nimport { createPFrameDriver } from \"../pool\";\nimport type { DriverKitOps, DriverKitOpsConstructor } from \"./ops\";\nimport { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings } from \"./ops\";\n\n/**\n * Drivers offered by the middle-layer for internal consumers,\n * like configuration rendering routines.\n *\n * This intertface is basically a version of the DriverKit from\n * UI SDK with extended API.\n * */\nexport interface MiddleLayerDriverKit extends Sdk.DriverKit, AsyncDisposable {\n /** Dispose the driver kit and all its resources. */\n dispose(): Promise<void>;\n\n // override with wider interface\n readonly blobDriver: DownloadDriver;\n // override with wider interface\n readonly blobToURLDriver: DownloadBlobToURLDriver;\n // override with wider interface\n readonly logDriver: LogsDriver;\n // override with wider interface\n readonly lsDriver: InternalLsDriver;\n // override with wider interface\n readonly pFrameDriver: InternalPFrameDriver;\n // override with wider interface\n readonly frontendDriver: DownloadUrlDriver;\n\n /**\n * Signer is initialized from local secret in drivers initialization routine,\n * so constitutes a part of the driver kit\n * */\n readonly signer: Signer;\n\n /**\n * Used to retrieve upload progress, and initiate upload porecesses driven by\n * upload requests from block outputs.\n * */\n readonly uploadDriver: UploadDriver;\n}\n\nexport async function initDriverKit(\n pl: PlClient,\n workdir: string,\n frontendDownloadPath: string,\n _ops: DriverKitOpsConstructor,\n): Promise<MiddleLayerDriverKit> {\n const ops: DriverKitOps = {\n ...DefaultDriverKitOpsSettings,\n ...DefaultDriverKitOpsPaths(workdir),\n ..._ops,\n };\n\n const signer = new HmacSha256Signer(ops.localSecret);\n\n const downloadClient = createDownloadClient(ops.logger, pl, ops.localProjections);\n const logsClient = createLogsClient(pl, ops.logger);\n const uploadBlobClient = createUploadBlobClient(pl, ops.logger);\n const uploadProgressClient = createUploadProgressClient(pl, ops.logger);\n\n const blobDriver = await DownloadDriver.init(\n ops.logger,\n downloadClient,\n logsClient,\n ops.blobDownloadPath,\n ops.blobDownloadRangesCachePath,\n signer,\n ops.blobDriverOps,\n );\n\n const blobToURLDriver = new DownloadBlobToURLDriver(\n ops.logger,\n signer,\n downloadClient,\n ops.downloadBlobToURLPath,\n ops.downloadBlobToURLDriverOps,\n );\n\n const uploadDriver = new UploadDriver(\n ops.logger,\n signer,\n uploadBlobClient,\n uploadProgressClient,\n ops.uploadDriverOps,\n );\n const logsStreamDriver = new LogsStreamDriver(ops.logger, logsClient, ops.logStreamDriverOps);\n const logDriver = new LogsDriver(ops.logger, logsStreamDriver, blobDriver);\n const lsDriver = await LsDriver.init(\n ops.logger,\n pl,\n signer,\n ops.localProjections,\n ops.openFileDialogCallback,\n ops.virtualLocalStoragesOverride,\n );\n\n const pFrameDriver = await createPFrameDriver({\n blobDriver,\n logger: ops.logger,\n spillPath: ops.pframesSpillPath,\n cachePath: ops.parquetCachePath,\n options: ops.pFrameDriverOps,\n cacheOps: ops.parquetCacheOps,\n });\n\n const frontendDownloadDriver = new DownloadUrlDriver(\n ops.logger,\n pl.httpDispatcher,\n frontendDownloadPath,\n signer,\n ops.frontendDownloadDriverOps,\n );\n\n const driverKit = {\n blobDriver,\n blobToURLDriver: blobToURLDriver,\n logDriver,\n lsDriver,\n signer,\n uploadDriver,\n pFrameDriver,\n frontendDriver: frontendDownloadDriver,\n };\n\n const dispose = async () => {\n const disposePromises = Object.values(driverKit).flatMap((driver) =>\n isAsyncDisposable(driver) ? [driver[Symbol.asyncDispose]()] : [],\n );\n await Promise.all(disposePromises);\n };\n\n return {\n ...driverKit,\n dispose,\n [Symbol.asyncDispose]: dispose,\n };\n}\n"],"mappings":";;;;;;;AA6DA,eAAsB,cACpB,IACA,SACA,sBACA,MAC+B;CAC/B,MAAM,MAAoB;EACxB,GAAG;EACH,GAAG,yBAAyB,QAAQ;EACpC,GAAG;EACJ;CAED,MAAM,SAAS,IAAI,iBAAiB,IAAI,YAAY;CAEpD,MAAM,iBAAiB,qBAAqB,IAAI,QAAQ,IAAI,IAAI,iBAAiB;CACjF,MAAM,aAAa,iBAAiB,IAAI,IAAI,OAAO;CACnD,MAAM,mBAAmB,uBAAuB,IAAI,IAAI,OAAO;CAC/D,MAAM,uBAAuB,2BAA2B,IAAI,IAAI,OAAO;CAEvE,MAAM,aAAa,MAAM,eAAe,KACtC,IAAI,QACJ,gBACA,YACA,IAAI,kBACJ,IAAI,6BACJ,QACA,IAAI,cACL;CAED,MAAM,kBAAkB,IAAI,wBAC1B,IAAI,QACJ,QACA,gBACA,IAAI,uBACJ,IAAI,2BACL;CAED,MAAM,eAAe,IAAI,aACvB,IAAI,QACJ,QACA,kBACA,sBACA,IAAI,gBACL;CACD,MAAM,mBAAmB,IAAI,iBAAiB,IAAI,QAAQ,YAAY,IAAI,mBAAmB;CA4B7F,MAAM,YAAY;EAChB;EACiB;EACjB,WA9BgB,IAAI,WAAW,IAAI,QAAQ,kBAAkB,WAAW;EA+BxE,UA9Be,MAAM,SAAS,KAC9B,IAAI,QACJ,IACA,QACA,IAAI,kBACJ,IAAI,wBACJ,IAAI,6BACL;EAwBC;EACA;EACA,cAxBmB,MAAM,mBAAmB;GAC5C;GACA,QAAQ,IAAI;GACZ,WAAW,IAAI;GACf,WAAW,IAAI;GACf,SAAS,IAAI;GACb,UAAU,IAAI;GACf,CAAC;EAkBA,gBAhB6B,IAAI,kBACjC,IAAI,QACJ,GAAG,gBACH,sBACA,QACA,IAAI,0BACL;EAWA;CAED,MAAM,UAAU,YAAY;EAC1B,MAAM,kBAAkB,OAAO,OAAO,UAAU,CAAC,SAAS,WACxD,kBAAkB,OAAO,GAAG,CAAC,OAAO,OAAO,eAAe,CAAC,GAAG,EAAE,CACjE;AACD,QAAM,QAAQ,IAAI,gBAAgB;;AAGpC,QAAO;EACL,GAAG;EACH;GACC,OAAO,eAAe;EACxB"}
|
|
@@ -32,14 +32,20 @@ const DefaultDriverKitOpsSettings = {
|
|
|
32
32
|
pollingInterval: 1e3,
|
|
33
33
|
stopPollingDelay: 1e3
|
|
34
34
|
},
|
|
35
|
-
pFrameDriverOps: require_driver.PFrameDriverOpsDefaults
|
|
35
|
+
pFrameDriverOps: require_driver.PFrameDriverOpsDefaults,
|
|
36
|
+
parquetCacheOps: {
|
|
37
|
+
maxSizeBytes: 8 * 1024 * 1024 * 1024,
|
|
38
|
+
admissionFraction: .2,
|
|
39
|
+
maxFilesTracked: 5e4
|
|
40
|
+
}
|
|
36
41
|
};
|
|
37
42
|
function DefaultDriverKitOpsPaths(workDir) {
|
|
38
43
|
return {
|
|
39
44
|
blobDownloadPath: node_path.default.join(workDir, "download"),
|
|
40
45
|
blobDownloadRangesCachePath: node_path.default.join(workDir, "downloadRangesCache"),
|
|
41
46
|
downloadBlobToURLPath: node_path.default.join(workDir, "downloadToURL"),
|
|
42
|
-
pframesSpillPath: node_path.default.join(workDir, "pframes")
|
|
47
|
+
pframesSpillPath: node_path.default.join(workDir, "pframes"),
|
|
48
|
+
parquetCachePath: node_path.default.join(workDir, "parquetCache")
|
|
43
49
|
};
|
|
44
50
|
}
|
|
45
51
|
/** Some defaults fot MiddleLayerOps. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ops.cjs","names":["ConsoleLoggerAdapter","PFrameDriverOpsDefaults","path"],"sources":["../../src/middle_layer/ops.ts"],"sourcesContent":["import type { TemporalSynchronizedTreeOps } from \"./types\";\nimport type {\n DownloadBlobToURLDriverOps,\n DownloadDriverOps,\n DownloadUrlDriverOps,\n OpenFileDialogCallback,\n VirtualLocalStorageSpec,\n} from \"@milaboratories/pl-drivers\";\nimport type { UploadDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { LogsStreamDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConsoleLoggerAdapter } from \"@milaboratories/ts-helpers\";\nimport type { LocalStorageProjection } from \"@milaboratories/pl-drivers\";\nimport path from \"node:path\";\nimport { PFrameDriverOpsDefaults, type PFrameDriverOps } from \"../pool\";\n\n/** Paths part of {@link DriverKitOps}. */\nexport type DriverKitOpsPaths = {\n /** Common root where to put downloaded blobs / downloaded blob cache */\n readonly blobDownloadPath: string;\n\n /** Common root for a cache for range queries. */\n readonly blobDownloadRangesCachePath: string;\n\n /** Common root where to put downloaded blobs with */\n readonly downloadBlobToURLPath: string;\n\n /**\n * List of pl storages that have projections in local file system.\n *\n * This option affect two drivers:\n *\n * (1) LS driver generates \"index\" handles instead of \"upload\" for paths inside those locations\n *\n * (2) Download driver directly serves content retrieval requests for blobs from listed storages,\n * and don't apply any caching for such blobs (i.e. preventing duplication of files for Downloaded\n * type handles, making OnDemand and Downloaded handles equivalent)\n *\n * */\n readonly localProjections: LocalStorageProjection[];\n\n /**\n * List of virtual storages that will allow homogeneous access to local FSs through LS API.\n * If undefined, default list will be created.\n * */\n readonly virtualLocalStoragesOverride?: VirtualLocalStorageSpec[];\n\n /** Path to the directory where pframes will spill temporary files and store materialized views */\n readonly pframesSpillPath: string;\n};\n\n/** Options required to initialize full set of middle layer driver kit */\nexport type DriverKitOpsSettings = {\n //\n // Common\n //\n\n readonly logger: MiLogger;\n\n //\n // Signer\n //\n\n /**\n * Local secret, that is used to sign and verify different pieces of information\n * that can be used to access local data, like local paths for ongoing uploads.\n *\n * Use {@link MiddleLayer.generateLocalSecret} to generate sufficiently random string.\n * */\n readonly localSecret: string;\n\n //\n // Blob Driver\n //\n\n /**\n * Settings related to the download driver making operations with blobs. This driver is also used\n * to download logs when source process terminates and log terns into a blob\n */\n readonly blobDriverOps: DownloadDriverOps;\n\n //\n // Frontend Driver\n //\n\n /** Settings related to the frontend driver that downloads frontends. */\n readonly frontendDownloadDriverOps: DownloadUrlDriverOps;\n\n //\n // Blob To URL Driver\n //\n\n readonly downloadBlobToURLDriverOps: DownloadBlobToURLDriverOps;\n\n //\n // Upload Driver\n //\n\n /**\n * Settings related to the upload driver that actually performs upload and helps render upload\n * and indexing progresses from related pl resources.\n * */\n readonly uploadDriverOps: UploadDriverOps;\n\n //\n // Log streaming ops\n // (static logs are served via the blob driver)\n //\n\n /** Settings related to the streaming log driver */\n readonly logStreamDriverOps: LogsStreamDriverOps;\n\n //\n // LS Driver\n //\n\n /**\n * Callback to access system file open dialog, must be provided by the environment,\n * to allow for {@link showOpenSingleFileDialog} / {@link showOpenMultipleFilesDialog}\n * calls from the UI.\n */\n readonly openFileDialogCallback: OpenFileDialogCallback;\n\n //\n // PFrame Driver\n //\n\n /** Settings related to the PFrame driver */\n readonly pFrameDriverOps: PFrameDriverOps;\n};\n\nexport type DriverKitOps = DriverKitOpsPaths & DriverKitOpsSettings;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultDriverKitOpsSettings: Pick<\n DriverKitOpsSettings,\n | \"logger\"\n | \"blobDriverOps\"\n | \"frontendDownloadDriverOps\"\n | \"downloadBlobToURLDriverOps\"\n | \"uploadDriverOps\"\n | \"logStreamDriverOps\"\n | \"pFrameDriverOps\"\n> = {\n logger: new ConsoleLoggerAdapter(),\n blobDriverOps: {\n cacheSoftSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n rangesCacheMaxSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n nConcurrentDownloads: 10,\n },\n frontendDownloadDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n withGunzip: true,\n nConcurrentDownloads: 50,\n },\n downloadBlobToURLDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n nConcurrentDownloads: 10,\n },\n uploadDriverOps: {\n nConcurrentPartUploads: 10,\n nConcurrentGetProgresses: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n logStreamDriverOps: {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n pFrameDriverOps: PFrameDriverOpsDefaults,\n};\n\nexport function DefaultDriverKitOpsPaths(\n workDir: string,\n): Pick<\n DriverKitOpsPaths,\n \"blobDownloadPath\" | \"blobDownloadRangesCachePath\" | \"downloadBlobToURLPath\" | \"pframesSpillPath\"\n> {\n return {\n blobDownloadPath: path.join(workDir, \"download\"),\n blobDownloadRangesCachePath: path.join(workDir, \"downloadRangesCache\"),\n downloadBlobToURLPath: path.join(workDir, \"downloadToURL\"),\n pframesSpillPath: path.join(workDir, \"pframes\"),\n };\n}\n\n/** Fields with default values are marked as optional here. */\nexport type DriverKitOpsConstructor = Omit<\n DriverKitOpsSettings,\n keyof typeof DefaultDriverKitOpsSettings\n> &\n Partial<typeof DefaultDriverKitOpsSettings> &\n Omit<DriverKitOpsPaths, keyof ReturnType<typeof DefaultDriverKitOpsPaths>> &\n Partial<ReturnType<typeof DefaultDriverKitOpsPaths>>;\n\nexport type MiddleLayerOpsPaths = DriverKitOpsPaths & {\n /** Common root where to put frontend code. */\n readonly frontendDownloadPath: string;\n};\n\n/** Debug options for middle layer. */\nexport type MiddleLayerDebugOptions = {\n /** If true, will dump initial tree state to the file with root resource id as name. */\n dumpInitialTreeState: boolean;\n};\n\n/** Configuration controlling different aspects of middle layer behaviour. */\nexport type MiddleLayerOpsSettings = DriverKitOpsSettings & {\n /** Debug options. */\n readonly debugOps: MiddleLayerDebugOptions;\n\n /** Contain temporal options controlling how often should pl trees be\n * synchronized with the pl server. */\n readonly defaultTreeOptions: TemporalSynchronizedTreeOps;\n\n /** Defines interval in milliseconds for running periodic project maintenance job.\n * Project maintenance includes background staging rendering and cached outputs cleanup. */\n readonly projectRefreshInterval: number;\n\n /** How often to check for dev block updates */\n readonly devBlockUpdateRecheckInterval: number;\n\n /** Prioritize this channel if update is available in this block */\n readonly preferredUpdateChannel?: string;\n};\n\nexport type MiddleLayerOps = MiddleLayerOpsSettings & MiddleLayerOpsPaths;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultMiddleLayerOpsSettings: Pick<\n MiddleLayerOps,\n | keyof typeof DefaultDriverKitOpsSettings\n | \"defaultTreeOptions\"\n | \"projectRefreshInterval\"\n | \"devBlockUpdateRecheckInterval\"\n | \"debugOps\"\n> = {\n ...DefaultDriverKitOpsSettings,\n defaultTreeOptions: {\n pollingInterval: 200,\n stopPollingDelay: 2500,\n initialTreeLoadingTimeout: 100 * 60 * 60 * 1000, // disable timeout for loading project tree (100 hours)\n },\n debugOps: {\n dumpInitialTreeState: false,\n },\n devBlockUpdateRecheckInterval: 1000,\n projectRefreshInterval: 2000,\n};\n\nexport function DefaultMiddleLayerOpsPaths(\n workDir: string,\n): Pick<\n MiddleLayerOpsPaths,\n keyof ReturnType<typeof DefaultDriverKitOpsPaths> | \"frontendDownloadPath\"\n> {\n return {\n ...DefaultDriverKitOpsPaths(workDir),\n frontendDownloadPath: path.join(workDir, \"frontend\"),\n };\n}\n\nexport type MiddleLayerOpsConstructor = Omit<\n MiddleLayerOpsSettings,\n keyof typeof DefaultMiddleLayerOpsSettings\n> &\n Partial<typeof DefaultMiddleLayerOpsSettings> &\n Omit<MiddleLayerOpsPaths, keyof Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>> &\n Partial<Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>>;\n"],"mappings":";;;;;;;AAsIA,MAAa,8BAST;CACF,QAAQ,4CAAIA,sBAAsB;CAClC,eAAe;EACb,oBAAoB,IAAI,OAAO,OAAO;EACtC,yBAAyB,IAAI,OAAO,OAAO;EAC3C,sBAAsB;EACvB;CACD,2BAA2B;EACzB,oBAAoB,IAAI,OAAO,OAAO;EACtC,YAAY;EACZ,sBAAsB;EACvB;CACD,4BAA4B;EAC1B,oBAAoB,IAAI,OAAO,OAAO;EACtC,sBAAsB;EACvB;CACD,iBAAiB;EACf,wBAAwB;EACxB,0BAA0B;EAC1B,iBAAiB;EACjB,kBAAkB;EACnB;CACD,oBAAoB;EAClB,oBAAoB;EACpB,iBAAiB;EACjB,kBAAkB;EACnB;CACD,iBAAiBC,eAAAA;CAClB;AAED,SAAgB,yBACd,SAIA;AACA,QAAO;EACL,kBAAkBC,UAAAA,QAAK,KAAK,SAAS,WAAW;EAChD,6BAA6BA,UAAAA,QAAK,KAAK,SAAS,sBAAsB;EACtE,uBAAuBA,UAAAA,QAAK,KAAK,SAAS,gBAAgB;EAC1D,kBAAkBA,UAAAA,QAAK,KAAK,SAAS,UAAU;EAChD;;;AA8CH,MAAa,gCAOT;CACF,GAAG;CACH,oBAAoB;EAClB,iBAAiB;EACjB,kBAAkB;EAClB,2BAA2B,MAAW,KAAK;EAC5C;CACD,UAAU,EACR,sBAAsB,OACvB;CACD,+BAA+B;CAC/B,wBAAwB;CACzB;AAED,SAAgB,2BACd,SAIA;AACA,QAAO;EACL,GAAG,yBAAyB,QAAQ;EACpC,sBAAsBA,UAAAA,QAAK,KAAK,SAAS,WAAW;EACrD"}
|
|
1
|
+
{"version":3,"file":"ops.cjs","names":["ConsoleLoggerAdapter","PFrameDriverOpsDefaults","path"],"sources":["../../src/middle_layer/ops.ts"],"sourcesContent":["import type { TemporalSynchronizedTreeOps } from \"./types\";\nimport type {\n DownloadBlobToURLDriverOps,\n DownloadDriverOps,\n DownloadUrlDriverOps,\n OpenFileDialogCallback,\n VirtualLocalStorageSpec,\n} from \"@milaboratories/pl-drivers\";\nimport type { UploadDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { LogsStreamDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConsoleLoggerAdapter } from \"@milaboratories/ts-helpers\";\nimport type { LocalStorageProjection } from \"@milaboratories/pl-drivers\";\nimport path from \"node:path\";\nimport { PFrameDriverOpsDefaults, type PFrameDriverOps, type ParquetCacheOps } from \"../pool\";\n\n/** Paths part of {@link DriverKitOps}. */\nexport type DriverKitOpsPaths = {\n /** Common root where to put downloaded blobs / downloaded blob cache */\n readonly blobDownloadPath: string;\n\n /** Common root for a cache for range queries. */\n readonly blobDownloadRangesCachePath: string;\n\n /** Common root where to put downloaded blobs with */\n readonly downloadBlobToURLPath: string;\n\n /**\n * List of pl storages that have projections in local file system.\n *\n * This option affect two drivers:\n *\n * (1) LS driver generates \"index\" handles instead of \"upload\" for paths inside those locations\n *\n * (2) Download driver directly serves content retrieval requests for blobs from listed storages,\n * and don't apply any caching for such blobs (i.e. preventing duplication of files for Downloaded\n * type handles, making OnDemand and Downloaded handles equivalent)\n *\n * */\n readonly localProjections: LocalStorageProjection[];\n\n /**\n * List of virtual storages that will allow homogeneous access to local FSs through LS API.\n * If undefined, default list will be created.\n * */\n readonly virtualLocalStoragesOverride?: VirtualLocalStorageSpec[];\n\n /** Path to the directory where pframes will spill temporary files and store materialized views */\n readonly pframesSpillPath: string;\n\n /**\n * Path to the directory backing the persistent parquet blob cache. Unlike\n * {@link pframesSpillPath} this directory is NOT emptied on startup - the cache\n * (and its lifetime counters) is meant to survive restarts.\n */\n readonly parquetCachePath: string;\n};\n\n/** Options required to initialize full set of middle layer driver kit */\nexport type DriverKitOpsSettings = {\n //\n // Common\n //\n\n readonly logger: MiLogger;\n\n //\n // Signer\n //\n\n /**\n * Local secret, that is used to sign and verify different pieces of information\n * that can be used to access local data, like local paths for ongoing uploads.\n *\n * Use {@link MiddleLayer.generateLocalSecret} to generate sufficiently random string.\n * */\n readonly localSecret: string;\n\n //\n // Blob Driver\n //\n\n /**\n * Settings related to the download driver making operations with blobs. This driver is also used\n * to download logs when source process terminates and log terns into a blob\n */\n readonly blobDriverOps: DownloadDriverOps;\n\n //\n // Frontend Driver\n //\n\n /** Settings related to the frontend driver that downloads frontends. */\n readonly frontendDownloadDriverOps: DownloadUrlDriverOps;\n\n //\n // Blob To URL Driver\n //\n\n readonly downloadBlobToURLDriverOps: DownloadBlobToURLDriverOps;\n\n //\n // Upload Driver\n //\n\n /**\n * Settings related to the upload driver that actually performs upload and helps render upload\n * and indexing progresses from related pl resources.\n * */\n readonly uploadDriverOps: UploadDriverOps;\n\n //\n // Log streaming ops\n // (static logs are served via the blob driver)\n //\n\n /** Settings related to the streaming log driver */\n readonly logStreamDriverOps: LogsStreamDriverOps;\n\n //\n // LS Driver\n //\n\n /**\n * Callback to access system file open dialog, must be provided by the environment,\n * to allow for {@link showOpenSingleFileDialog} / {@link showOpenMultipleFilesDialog}\n * calls from the UI.\n */\n readonly openFileDialogCallback: OpenFileDialogCallback;\n\n //\n // PFrame Driver\n //\n\n /** Settings related to the PFrame driver */\n readonly pFrameDriverOps: PFrameDriverOps;\n\n /**\n * Tuning for the persistent parquet blob cache. Its directory is\n * {@link DriverKitOpsPaths.parquetCachePath}; this carries only the\n * size/eviction knobs.\n */\n readonly parquetCacheOps: ParquetCacheOps;\n};\n\nexport type DriverKitOps = DriverKitOpsPaths & DriverKitOpsSettings;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultDriverKitOpsSettings: Pick<\n DriverKitOpsSettings,\n | \"logger\"\n | \"blobDriverOps\"\n | \"frontendDownloadDriverOps\"\n | \"downloadBlobToURLDriverOps\"\n | \"uploadDriverOps\"\n | \"logStreamDriverOps\"\n | \"pFrameDriverOps\"\n | \"parquetCacheOps\"\n> = {\n logger: new ConsoleLoggerAdapter(),\n blobDriverOps: {\n cacheSoftSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n rangesCacheMaxSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n nConcurrentDownloads: 10,\n },\n frontendDownloadDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n withGunzip: true,\n nConcurrentDownloads: 50,\n },\n downloadBlobToURLDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n nConcurrentDownloads: 10,\n },\n uploadDriverOps: {\n nConcurrentPartUploads: 10,\n nConcurrentGetProgresses: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n logStreamDriverOps: {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n pFrameDriverOps: PFrameDriverOpsDefaults,\n parquetCacheOps: {\n maxSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n admissionFraction: 0.2, // a single file may occupy at most 20% of the budget\n maxFilesTracked: 50_000, // ghost (previously-evicted) files remembered to guide readmission\n },\n};\n\nexport function DefaultDriverKitOpsPaths(\n workDir: string,\n): Pick<\n DriverKitOpsPaths,\n | \"blobDownloadPath\"\n | \"blobDownloadRangesCachePath\"\n | \"downloadBlobToURLPath\"\n | \"pframesSpillPath\"\n | \"parquetCachePath\"\n> {\n return {\n blobDownloadPath: path.join(workDir, \"download\"),\n blobDownloadRangesCachePath: path.join(workDir, \"downloadRangesCache\"),\n downloadBlobToURLPath: path.join(workDir, \"downloadToURL\"),\n pframesSpillPath: path.join(workDir, \"pframes\"),\n parquetCachePath: path.join(workDir, \"parquetCache\"),\n };\n}\n\n/** Fields with default values are marked as optional here. */\nexport type DriverKitOpsConstructor = Omit<\n DriverKitOpsSettings,\n keyof typeof DefaultDriverKitOpsSettings\n> &\n Partial<typeof DefaultDriverKitOpsSettings> &\n Omit<DriverKitOpsPaths, keyof ReturnType<typeof DefaultDriverKitOpsPaths>> &\n Partial<ReturnType<typeof DefaultDriverKitOpsPaths>>;\n\nexport type MiddleLayerOpsPaths = DriverKitOpsPaths & {\n /** Common root where to put frontend code. */\n readonly frontendDownloadPath: string;\n};\n\n/** Debug options for middle layer. */\nexport type MiddleLayerDebugOptions = {\n /** If true, will dump initial tree state to the file with root resource id as name. */\n dumpInitialTreeState: boolean;\n};\n\n/** Configuration controlling different aspects of middle layer behaviour. */\nexport type MiddleLayerOpsSettings = DriverKitOpsSettings & {\n /** Debug options. */\n readonly debugOps: MiddleLayerDebugOptions;\n\n /** Contain temporal options controlling how often should pl trees be\n * synchronized with the pl server. */\n readonly defaultTreeOptions: TemporalSynchronizedTreeOps;\n\n /** Defines interval in milliseconds for running periodic project maintenance job.\n * Project maintenance includes background staging rendering and cached outputs cleanup. */\n readonly projectRefreshInterval: number;\n\n /** How often to check for dev block updates */\n readonly devBlockUpdateRecheckInterval: number;\n\n /** Prioritize this channel if update is available in this block */\n readonly preferredUpdateChannel?: string;\n};\n\nexport type MiddleLayerOps = MiddleLayerOpsSettings & MiddleLayerOpsPaths;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultMiddleLayerOpsSettings: Pick<\n MiddleLayerOps,\n | keyof typeof DefaultDriverKitOpsSettings\n | \"defaultTreeOptions\"\n | \"projectRefreshInterval\"\n | \"devBlockUpdateRecheckInterval\"\n | \"debugOps\"\n> = {\n ...DefaultDriverKitOpsSettings,\n defaultTreeOptions: {\n pollingInterval: 200,\n stopPollingDelay: 2500,\n initialTreeLoadingTimeout: 100 * 60 * 60 * 1000, // disable timeout for loading project tree (100 hours)\n },\n debugOps: {\n dumpInitialTreeState: false,\n },\n devBlockUpdateRecheckInterval: 1000,\n projectRefreshInterval: 2000,\n};\n\nexport function DefaultMiddleLayerOpsPaths(\n workDir: string,\n): Pick<\n MiddleLayerOpsPaths,\n keyof ReturnType<typeof DefaultDriverKitOpsPaths> | \"frontendDownloadPath\"\n> {\n return {\n ...DefaultDriverKitOpsPaths(workDir),\n frontendDownloadPath: path.join(workDir, \"frontend\"),\n };\n}\n\nexport type MiddleLayerOpsConstructor = Omit<\n MiddleLayerOpsSettings,\n keyof typeof DefaultMiddleLayerOpsSettings\n> &\n Partial<typeof DefaultMiddleLayerOpsSettings> &\n Omit<MiddleLayerOpsPaths, keyof Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>> &\n Partial<Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>>;\n"],"mappings":";;;;;;;AAoJA,MAAa,8BAUT;CACF,QAAQ,4CAAIA,sBAAsB;CAClC,eAAe;EACb,oBAAoB,IAAI,OAAO,OAAO;EACtC,yBAAyB,IAAI,OAAO,OAAO;EAC3C,sBAAsB;EACvB;CACD,2BAA2B;EACzB,oBAAoB,IAAI,OAAO,OAAO;EACtC,YAAY;EACZ,sBAAsB;EACvB;CACD,4BAA4B;EAC1B,oBAAoB,IAAI,OAAO,OAAO;EACtC,sBAAsB;EACvB;CACD,iBAAiB;EACf,wBAAwB;EACxB,0BAA0B;EAC1B,iBAAiB;EACjB,kBAAkB;EACnB;CACD,oBAAoB;EAClB,oBAAoB;EACpB,iBAAiB;EACjB,kBAAkB;EACnB;CACD,iBAAiBC,eAAAA;CACjB,iBAAiB;EACf,cAAc,IAAI,OAAO,OAAO;EAChC,mBAAmB;EACnB,iBAAiB;EAClB;CACF;AAED,SAAgB,yBACd,SAQA;AACA,QAAO;EACL,kBAAkBC,UAAAA,QAAK,KAAK,SAAS,WAAW;EAChD,6BAA6BA,UAAAA,QAAK,KAAK,SAAS,sBAAsB;EACtE,uBAAuBA,UAAAA,QAAK,KAAK,SAAS,gBAAgB;EAC1D,kBAAkBA,UAAAA,QAAK,KAAK,SAAS,UAAU;EAC/C,kBAAkBA,UAAAA,QAAK,KAAK,SAAS,eAAe;EACrD;;;AA8CH,MAAa,gCAOT;CACF,GAAG;CACH,oBAAoB;EAClB,iBAAiB;EACjB,kBAAkB;EAClB,2BAA2B,MAAW,KAAK;EAC5C;CACD,UAAU,EACR,sBAAsB,OACvB;CACD,+BAA+B;CAC/B,wBAAwB;CACzB;AAED,SAAgB,2BACd,SAIA;AACA,QAAO;EACL,GAAG,yBAAyB,QAAQ;EACpC,sBAAsBA,UAAAA,QAAK,KAAK,SAAS,WAAW;EACrD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TemporalSynchronizedTreeOps } from "./types.js";
|
|
2
|
-
import { PFrameDriverOps } from "../pool/driver.js";
|
|
2
|
+
import { PFrameDriverOps, ParquetCacheOps } from "../pool/driver.js";
|
|
3
3
|
import { MiLogger } from "@milaboratories/ts-helpers";
|
|
4
4
|
import { DownloadBlobToURLDriverOps, DownloadDriverOps, DownloadUrlDriverOps, LocalStorageProjection, LogsStreamDriverOps, OpenFileDialogCallback, UploadDriverOps, VirtualLocalStorageSpec } from "@milaboratories/pl-drivers";
|
|
5
5
|
|
|
@@ -28,6 +28,12 @@ type DriverKitOpsPaths = {
|
|
|
28
28
|
* */
|
|
29
29
|
readonly virtualLocalStoragesOverride?: VirtualLocalStorageSpec[]; /** Path to the directory where pframes will spill temporary files and store materialized views */
|
|
30
30
|
readonly pframesSpillPath: string;
|
|
31
|
+
/**
|
|
32
|
+
* Path to the directory backing the persistent parquet blob cache. Unlike
|
|
33
|
+
* {@link pframesSpillPath} this directory is NOT emptied on startup - the cache
|
|
34
|
+
* (and its lifetime counters) is meant to survive restarts.
|
|
35
|
+
*/
|
|
36
|
+
readonly parquetCachePath: string;
|
|
31
37
|
};
|
|
32
38
|
/** Options required to initialize full set of middle layer driver kit */
|
|
33
39
|
type DriverKitOpsSettings = {
|
|
@@ -59,11 +65,17 @@ type DriverKitOpsSettings = {
|
|
|
59
65
|
*/
|
|
60
66
|
readonly openFileDialogCallback: OpenFileDialogCallback; /** Settings related to the PFrame driver */
|
|
61
67
|
readonly pFrameDriverOps: PFrameDriverOps;
|
|
68
|
+
/**
|
|
69
|
+
* Tuning for the persistent parquet blob cache. Its directory is
|
|
70
|
+
* {@link DriverKitOpsPaths.parquetCachePath}; this carries only the
|
|
71
|
+
* size/eviction knobs.
|
|
72
|
+
*/
|
|
73
|
+
readonly parquetCacheOps: ParquetCacheOps;
|
|
62
74
|
};
|
|
63
75
|
type DriverKitOps = DriverKitOpsPaths & DriverKitOpsSettings;
|
|
64
76
|
/** Some defaults fot MiddleLayerOps. */
|
|
65
|
-
declare const DefaultDriverKitOpsSettings: Pick<DriverKitOpsSettings, "logger" | "blobDriverOps" | "frontendDownloadDriverOps" | "downloadBlobToURLDriverOps" | "uploadDriverOps" | "logStreamDriverOps" | "pFrameDriverOps">;
|
|
66
|
-
declare function DefaultDriverKitOpsPaths(workDir: string): Pick<DriverKitOpsPaths, "blobDownloadPath" | "blobDownloadRangesCachePath" | "downloadBlobToURLPath" | "pframesSpillPath">;
|
|
77
|
+
declare const DefaultDriverKitOpsSettings: Pick<DriverKitOpsSettings, "logger" | "blobDriverOps" | "frontendDownloadDriverOps" | "downloadBlobToURLDriverOps" | "uploadDriverOps" | "logStreamDriverOps" | "pFrameDriverOps" | "parquetCacheOps">;
|
|
78
|
+
declare function DefaultDriverKitOpsPaths(workDir: string): Pick<DriverKitOpsPaths, "blobDownloadPath" | "blobDownloadRangesCachePath" | "downloadBlobToURLPath" | "pframesSpillPath" | "parquetCachePath">;
|
|
67
79
|
/** Fields with default values are marked as optional here. */
|
|
68
80
|
type DriverKitOpsConstructor = Omit<DriverKitOpsSettings, keyof typeof DefaultDriverKitOpsSettings> & Partial<typeof DefaultDriverKitOpsSettings> & Omit<DriverKitOpsPaths, keyof ReturnType<typeof DefaultDriverKitOpsPaths>> & Partial<ReturnType<typeof DefaultDriverKitOpsPaths>>;
|
|
69
81
|
type MiddleLayerOpsPaths = DriverKitOpsPaths & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ops.d.ts","names":[],"sources":["../../src/middle_layer/ops.ts"],"mappings":";;;;;;AAiBA;AAAA,KAAY,iBAAA;mFAED,gBAAA;EAAA,SAGA,2BAAA,UAGA;EAAA,SAAA,qBAAA;EAckB
|
|
1
|
+
{"version":3,"file":"ops.d.ts","names":[],"sources":["../../src/middle_layer/ops.ts"],"mappings":";;;;;;AAiBA;AAAA,KAAY,iBAAA;mFAED,gBAAA;EAAA,SAGA,2BAAA,UAGA;EAAA,SAAA,qBAAA;EAckB;;;;;;;AAoB7B;;;;;EApB6B,SAAlB,gBAAA,EAAkB,sBAAA;EA4DU;;;;EAAA,SAtD5B,4BAAA,GAA+B,uBAAA,IAiGd;EAAA,SA9FjB,gBAAA;EA8FgC;;;;;EAAA,SAvFhC,gBAAA;AAAA;;KAIC,oBAAA;EAAA,SAKD,MAAA,EAAQ,QAAA;EA6CR;;;;;;EAAA,SAjCA,WAAA;EA2DiB;;;;EAAA,SAjDjB,aAAA,EAAe,iBAAA,EA2Dd;EAAA,SApDD,yBAAA,EAA2B,oBAAA;EAAA,SAM3B,0BAAA,EAA4B,0BAAA;EA8CZ;;AAG3B;;EAH2B,SApChB,eAAA,EAAiB,eAAA,EAuCc;EAAA,SA/B/B,kBAAA,EAAoB,mBAAA;EA4Ef;;;;;EAAA,SAjEL,sBAAA,EAAwB,sBAAA,EAoEjC;EAAA,SA7DS,eAAA,EAAiB,eAAA;EA6DT;AAiBnB;;;;EAjBmB,SAtDR,eAAA,EAAiB,eAAA;AAAA;AAAA,KAGhB,YAAA,GAAe,iBAAA,GAAoB,oBAAA;;cAGlC,2BAAA,EAA6B,IAAA,CACxC,oBAAA;AAAA,iBA4Cc,wBAAA,CACd,OAAA,WACC,IAAA,CACD,iBAAA;;KAiBU,uBAAA,GAA0B,IAAA,CACpC,oBAAA,eACa,2BAAA,IAEb,OAAA,QAAe,2BAAA,IACf,IAAA,CAAK,iBAAA,QAAyB,UAAA,QAAkB,wBAAA,KAChD,OAAA,CAAQ,UAAA,QAAkB,wBAAA;AAAA,KAEhB,mBAAA,GAAsB,iBAAA;EAFxB,uDAIC,oBAAA;AAAA;;KAIC,uBAAA;EAbV,uFAeA,oBAAA;AAAA;;KAIU,sBAAA,GAAyB,oBAAA;EAf9B,8BAiBI,QAAA,EAAU,uBAAA;EAjB6B;;EAAA,SAqBvC,kBAAA,EAAoB,2BAAA;EApBH;;EAAA,SAwBjB,sBAAA,UAtBC;EAAA,SAyBD,6BAAA;WAGA,sBAAA;AAAA;AAAA,KAGC,cAAA,GAAiB,sBAAA,GAAyB,mBAAA;;cAGzC,6BAAA,EAA+B,IAAA,CAC1C,cAAA,eACe,2BAAA;AAAA,iBAmBD,0BAAA,CACd,OAAA,WACC,IAAA,CACD,mBAAA,QACM,UAAA,QAAkB,wBAAA;AAAA,KAQd,yBAAA,GAA4B,IAAA,CACtC,sBAAA,eACa,6BAAA,IAEb,OAAA,QAAe,6BAAA,IACf,IAAA,CAAK,mBAAA,QAA2B,OAAA,CAAQ,UAAA,QAAkB,0BAAA,MAC1D,OAAA,CAAQ,OAAA,CAAQ,UAAA,QAAkB,0BAAA"}
|
package/dist/middle_layer/ops.js
CHANGED
|
@@ -31,14 +31,20 @@ const DefaultDriverKitOpsSettings = {
|
|
|
31
31
|
pollingInterval: 1e3,
|
|
32
32
|
stopPollingDelay: 1e3
|
|
33
33
|
},
|
|
34
|
-
pFrameDriverOps: PFrameDriverOpsDefaults
|
|
34
|
+
pFrameDriverOps: PFrameDriverOpsDefaults,
|
|
35
|
+
parquetCacheOps: {
|
|
36
|
+
maxSizeBytes: 8 * 1024 * 1024 * 1024,
|
|
37
|
+
admissionFraction: .2,
|
|
38
|
+
maxFilesTracked: 5e4
|
|
39
|
+
}
|
|
35
40
|
};
|
|
36
41
|
function DefaultDriverKitOpsPaths(workDir) {
|
|
37
42
|
return {
|
|
38
43
|
blobDownloadPath: path.join(workDir, "download"),
|
|
39
44
|
blobDownloadRangesCachePath: path.join(workDir, "downloadRangesCache"),
|
|
40
45
|
downloadBlobToURLPath: path.join(workDir, "downloadToURL"),
|
|
41
|
-
pframesSpillPath: path.join(workDir, "pframes")
|
|
46
|
+
pframesSpillPath: path.join(workDir, "pframes"),
|
|
47
|
+
parquetCachePath: path.join(workDir, "parquetCache")
|
|
42
48
|
};
|
|
43
49
|
}
|
|
44
50
|
/** Some defaults fot MiddleLayerOps. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ops.js","names":[],"sources":["../../src/middle_layer/ops.ts"],"sourcesContent":["import type { TemporalSynchronizedTreeOps } from \"./types\";\nimport type {\n DownloadBlobToURLDriverOps,\n DownloadDriverOps,\n DownloadUrlDriverOps,\n OpenFileDialogCallback,\n VirtualLocalStorageSpec,\n} from \"@milaboratories/pl-drivers\";\nimport type { UploadDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { LogsStreamDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConsoleLoggerAdapter } from \"@milaboratories/ts-helpers\";\nimport type { LocalStorageProjection } from \"@milaboratories/pl-drivers\";\nimport path from \"node:path\";\nimport { PFrameDriverOpsDefaults, type PFrameDriverOps } from \"../pool\";\n\n/** Paths part of {@link DriverKitOps}. */\nexport type DriverKitOpsPaths = {\n /** Common root where to put downloaded blobs / downloaded blob cache */\n readonly blobDownloadPath: string;\n\n /** Common root for a cache for range queries. */\n readonly blobDownloadRangesCachePath: string;\n\n /** Common root where to put downloaded blobs with */\n readonly downloadBlobToURLPath: string;\n\n /**\n * List of pl storages that have projections in local file system.\n *\n * This option affect two drivers:\n *\n * (1) LS driver generates \"index\" handles instead of \"upload\" for paths inside those locations\n *\n * (2) Download driver directly serves content retrieval requests for blobs from listed storages,\n * and don't apply any caching for such blobs (i.e. preventing duplication of files for Downloaded\n * type handles, making OnDemand and Downloaded handles equivalent)\n *\n * */\n readonly localProjections: LocalStorageProjection[];\n\n /**\n * List of virtual storages that will allow homogeneous access to local FSs through LS API.\n * If undefined, default list will be created.\n * */\n readonly virtualLocalStoragesOverride?: VirtualLocalStorageSpec[];\n\n /** Path to the directory where pframes will spill temporary files and store materialized views */\n readonly pframesSpillPath: string;\n};\n\n/** Options required to initialize full set of middle layer driver kit */\nexport type DriverKitOpsSettings = {\n //\n // Common\n //\n\n readonly logger: MiLogger;\n\n //\n // Signer\n //\n\n /**\n * Local secret, that is used to sign and verify different pieces of information\n * that can be used to access local data, like local paths for ongoing uploads.\n *\n * Use {@link MiddleLayer.generateLocalSecret} to generate sufficiently random string.\n * */\n readonly localSecret: string;\n\n //\n // Blob Driver\n //\n\n /**\n * Settings related to the download driver making operations with blobs. This driver is also used\n * to download logs when source process terminates and log terns into a blob\n */\n readonly blobDriverOps: DownloadDriverOps;\n\n //\n // Frontend Driver\n //\n\n /** Settings related to the frontend driver that downloads frontends. */\n readonly frontendDownloadDriverOps: DownloadUrlDriverOps;\n\n //\n // Blob To URL Driver\n //\n\n readonly downloadBlobToURLDriverOps: DownloadBlobToURLDriverOps;\n\n //\n // Upload Driver\n //\n\n /**\n * Settings related to the upload driver that actually performs upload and helps render upload\n * and indexing progresses from related pl resources.\n * */\n readonly uploadDriverOps: UploadDriverOps;\n\n //\n // Log streaming ops\n // (static logs are served via the blob driver)\n //\n\n /** Settings related to the streaming log driver */\n readonly logStreamDriverOps: LogsStreamDriverOps;\n\n //\n // LS Driver\n //\n\n /**\n * Callback to access system file open dialog, must be provided by the environment,\n * to allow for {@link showOpenSingleFileDialog} / {@link showOpenMultipleFilesDialog}\n * calls from the UI.\n */\n readonly openFileDialogCallback: OpenFileDialogCallback;\n\n //\n // PFrame Driver\n //\n\n /** Settings related to the PFrame driver */\n readonly pFrameDriverOps: PFrameDriverOps;\n};\n\nexport type DriverKitOps = DriverKitOpsPaths & DriverKitOpsSettings;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultDriverKitOpsSettings: Pick<\n DriverKitOpsSettings,\n | \"logger\"\n | \"blobDriverOps\"\n | \"frontendDownloadDriverOps\"\n | \"downloadBlobToURLDriverOps\"\n | \"uploadDriverOps\"\n | \"logStreamDriverOps\"\n | \"pFrameDriverOps\"\n> = {\n logger: new ConsoleLoggerAdapter(),\n blobDriverOps: {\n cacheSoftSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n rangesCacheMaxSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n nConcurrentDownloads: 10,\n },\n frontendDownloadDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n withGunzip: true,\n nConcurrentDownloads: 50,\n },\n downloadBlobToURLDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n nConcurrentDownloads: 10,\n },\n uploadDriverOps: {\n nConcurrentPartUploads: 10,\n nConcurrentGetProgresses: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n logStreamDriverOps: {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n pFrameDriverOps: PFrameDriverOpsDefaults,\n};\n\nexport function DefaultDriverKitOpsPaths(\n workDir: string,\n): Pick<\n DriverKitOpsPaths,\n \"blobDownloadPath\" | \"blobDownloadRangesCachePath\" | \"downloadBlobToURLPath\" | \"pframesSpillPath\"\n> {\n return {\n blobDownloadPath: path.join(workDir, \"download\"),\n blobDownloadRangesCachePath: path.join(workDir, \"downloadRangesCache\"),\n downloadBlobToURLPath: path.join(workDir, \"downloadToURL\"),\n pframesSpillPath: path.join(workDir, \"pframes\"),\n };\n}\n\n/** Fields with default values are marked as optional here. */\nexport type DriverKitOpsConstructor = Omit<\n DriverKitOpsSettings,\n keyof typeof DefaultDriverKitOpsSettings\n> &\n Partial<typeof DefaultDriverKitOpsSettings> &\n Omit<DriverKitOpsPaths, keyof ReturnType<typeof DefaultDriverKitOpsPaths>> &\n Partial<ReturnType<typeof DefaultDriverKitOpsPaths>>;\n\nexport type MiddleLayerOpsPaths = DriverKitOpsPaths & {\n /** Common root where to put frontend code. */\n readonly frontendDownloadPath: string;\n};\n\n/** Debug options for middle layer. */\nexport type MiddleLayerDebugOptions = {\n /** If true, will dump initial tree state to the file with root resource id as name. */\n dumpInitialTreeState: boolean;\n};\n\n/** Configuration controlling different aspects of middle layer behaviour. */\nexport type MiddleLayerOpsSettings = DriverKitOpsSettings & {\n /** Debug options. */\n readonly debugOps: MiddleLayerDebugOptions;\n\n /** Contain temporal options controlling how often should pl trees be\n * synchronized with the pl server. */\n readonly defaultTreeOptions: TemporalSynchronizedTreeOps;\n\n /** Defines interval in milliseconds for running periodic project maintenance job.\n * Project maintenance includes background staging rendering and cached outputs cleanup. */\n readonly projectRefreshInterval: number;\n\n /** How often to check for dev block updates */\n readonly devBlockUpdateRecheckInterval: number;\n\n /** Prioritize this channel if update is available in this block */\n readonly preferredUpdateChannel?: string;\n};\n\nexport type MiddleLayerOps = MiddleLayerOpsSettings & MiddleLayerOpsPaths;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultMiddleLayerOpsSettings: Pick<\n MiddleLayerOps,\n | keyof typeof DefaultDriverKitOpsSettings\n | \"defaultTreeOptions\"\n | \"projectRefreshInterval\"\n | \"devBlockUpdateRecheckInterval\"\n | \"debugOps\"\n> = {\n ...DefaultDriverKitOpsSettings,\n defaultTreeOptions: {\n pollingInterval: 200,\n stopPollingDelay: 2500,\n initialTreeLoadingTimeout: 100 * 60 * 60 * 1000, // disable timeout for loading project tree (100 hours)\n },\n debugOps: {\n dumpInitialTreeState: false,\n },\n devBlockUpdateRecheckInterval: 1000,\n projectRefreshInterval: 2000,\n};\n\nexport function DefaultMiddleLayerOpsPaths(\n workDir: string,\n): Pick<\n MiddleLayerOpsPaths,\n keyof ReturnType<typeof DefaultDriverKitOpsPaths> | \"frontendDownloadPath\"\n> {\n return {\n ...DefaultDriverKitOpsPaths(workDir),\n frontendDownloadPath: path.join(workDir, \"frontend\"),\n };\n}\n\nexport type MiddleLayerOpsConstructor = Omit<\n MiddleLayerOpsSettings,\n keyof typeof DefaultMiddleLayerOpsSettings\n> &\n Partial<typeof DefaultMiddleLayerOpsSettings> &\n Omit<MiddleLayerOpsPaths, keyof Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>> &\n Partial<Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>>;\n"],"mappings":";;;;;;AAsIA,MAAa,8BAST;CACF,QAAQ,IAAI,sBAAsB;CAClC,eAAe;EACb,oBAAoB,IAAI,OAAO,OAAO;EACtC,yBAAyB,IAAI,OAAO,OAAO;EAC3C,sBAAsB;EACvB;CACD,2BAA2B;EACzB,oBAAoB,IAAI,OAAO,OAAO;EACtC,YAAY;EACZ,sBAAsB;EACvB;CACD,4BAA4B;EAC1B,oBAAoB,IAAI,OAAO,OAAO;EACtC,sBAAsB;EACvB;CACD,iBAAiB;EACf,wBAAwB;EACxB,0BAA0B;EAC1B,iBAAiB;EACjB,kBAAkB;EACnB;CACD,oBAAoB;EAClB,oBAAoB;EACpB,iBAAiB;EACjB,kBAAkB;EACnB;CACD,iBAAiB;CAClB;AAED,SAAgB,yBACd,SAIA;AACA,QAAO;EACL,kBAAkB,KAAK,KAAK,SAAS,WAAW;EAChD,6BAA6B,KAAK,KAAK,SAAS,sBAAsB;EACtE,uBAAuB,KAAK,KAAK,SAAS,gBAAgB;EAC1D,kBAAkB,KAAK,KAAK,SAAS,UAAU;EAChD;;;AA8CH,MAAa,gCAOT;CACF,GAAG;CACH,oBAAoB;EAClB,iBAAiB;EACjB,kBAAkB;EAClB,2BAA2B,MAAW,KAAK;EAC5C;CACD,UAAU,EACR,sBAAsB,OACvB;CACD,+BAA+B;CAC/B,wBAAwB;CACzB;AAED,SAAgB,2BACd,SAIA;AACA,QAAO;EACL,GAAG,yBAAyB,QAAQ;EACpC,sBAAsB,KAAK,KAAK,SAAS,WAAW;EACrD"}
|
|
1
|
+
{"version":3,"file":"ops.js","names":[],"sources":["../../src/middle_layer/ops.ts"],"sourcesContent":["import type { TemporalSynchronizedTreeOps } from \"./types\";\nimport type {\n DownloadBlobToURLDriverOps,\n DownloadDriverOps,\n DownloadUrlDriverOps,\n OpenFileDialogCallback,\n VirtualLocalStorageSpec,\n} from \"@milaboratories/pl-drivers\";\nimport type { UploadDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { LogsStreamDriverOps } from \"@milaboratories/pl-drivers\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\nimport { ConsoleLoggerAdapter } from \"@milaboratories/ts-helpers\";\nimport type { LocalStorageProjection } from \"@milaboratories/pl-drivers\";\nimport path from \"node:path\";\nimport { PFrameDriverOpsDefaults, type PFrameDriverOps, type ParquetCacheOps } from \"../pool\";\n\n/** Paths part of {@link DriverKitOps}. */\nexport type DriverKitOpsPaths = {\n /** Common root where to put downloaded blobs / downloaded blob cache */\n readonly blobDownloadPath: string;\n\n /** Common root for a cache for range queries. */\n readonly blobDownloadRangesCachePath: string;\n\n /** Common root where to put downloaded blobs with */\n readonly downloadBlobToURLPath: string;\n\n /**\n * List of pl storages that have projections in local file system.\n *\n * This option affect two drivers:\n *\n * (1) LS driver generates \"index\" handles instead of \"upload\" for paths inside those locations\n *\n * (2) Download driver directly serves content retrieval requests for blobs from listed storages,\n * and don't apply any caching for such blobs (i.e. preventing duplication of files for Downloaded\n * type handles, making OnDemand and Downloaded handles equivalent)\n *\n * */\n readonly localProjections: LocalStorageProjection[];\n\n /**\n * List of virtual storages that will allow homogeneous access to local FSs through LS API.\n * If undefined, default list will be created.\n * */\n readonly virtualLocalStoragesOverride?: VirtualLocalStorageSpec[];\n\n /** Path to the directory where pframes will spill temporary files and store materialized views */\n readonly pframesSpillPath: string;\n\n /**\n * Path to the directory backing the persistent parquet blob cache. Unlike\n * {@link pframesSpillPath} this directory is NOT emptied on startup - the cache\n * (and its lifetime counters) is meant to survive restarts.\n */\n readonly parquetCachePath: string;\n};\n\n/** Options required to initialize full set of middle layer driver kit */\nexport type DriverKitOpsSettings = {\n //\n // Common\n //\n\n readonly logger: MiLogger;\n\n //\n // Signer\n //\n\n /**\n * Local secret, that is used to sign and verify different pieces of information\n * that can be used to access local data, like local paths for ongoing uploads.\n *\n * Use {@link MiddleLayer.generateLocalSecret} to generate sufficiently random string.\n * */\n readonly localSecret: string;\n\n //\n // Blob Driver\n //\n\n /**\n * Settings related to the download driver making operations with blobs. This driver is also used\n * to download logs when source process terminates and log terns into a blob\n */\n readonly blobDriverOps: DownloadDriverOps;\n\n //\n // Frontend Driver\n //\n\n /** Settings related to the frontend driver that downloads frontends. */\n readonly frontendDownloadDriverOps: DownloadUrlDriverOps;\n\n //\n // Blob To URL Driver\n //\n\n readonly downloadBlobToURLDriverOps: DownloadBlobToURLDriverOps;\n\n //\n // Upload Driver\n //\n\n /**\n * Settings related to the upload driver that actually performs upload and helps render upload\n * and indexing progresses from related pl resources.\n * */\n readonly uploadDriverOps: UploadDriverOps;\n\n //\n // Log streaming ops\n // (static logs are served via the blob driver)\n //\n\n /** Settings related to the streaming log driver */\n readonly logStreamDriverOps: LogsStreamDriverOps;\n\n //\n // LS Driver\n //\n\n /**\n * Callback to access system file open dialog, must be provided by the environment,\n * to allow for {@link showOpenSingleFileDialog} / {@link showOpenMultipleFilesDialog}\n * calls from the UI.\n */\n readonly openFileDialogCallback: OpenFileDialogCallback;\n\n //\n // PFrame Driver\n //\n\n /** Settings related to the PFrame driver */\n readonly pFrameDriverOps: PFrameDriverOps;\n\n /**\n * Tuning for the persistent parquet blob cache. Its directory is\n * {@link DriverKitOpsPaths.parquetCachePath}; this carries only the\n * size/eviction knobs.\n */\n readonly parquetCacheOps: ParquetCacheOps;\n};\n\nexport type DriverKitOps = DriverKitOpsPaths & DriverKitOpsSettings;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultDriverKitOpsSettings: Pick<\n DriverKitOpsSettings,\n | \"logger\"\n | \"blobDriverOps\"\n | \"frontendDownloadDriverOps\"\n | \"downloadBlobToURLDriverOps\"\n | \"uploadDriverOps\"\n | \"logStreamDriverOps\"\n | \"pFrameDriverOps\"\n | \"parquetCacheOps\"\n> = {\n logger: new ConsoleLoggerAdapter(),\n blobDriverOps: {\n cacheSoftSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n rangesCacheMaxSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n nConcurrentDownloads: 10,\n },\n frontendDownloadDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n withGunzip: true,\n nConcurrentDownloads: 50,\n },\n downloadBlobToURLDriverOps: {\n cacheSoftSizeBytes: 1 * 1024 * 1024 * 1024, // 1 GB\n nConcurrentDownloads: 10,\n },\n uploadDriverOps: {\n nConcurrentPartUploads: 10,\n nConcurrentGetProgresses: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n logStreamDriverOps: {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n pFrameDriverOps: PFrameDriverOpsDefaults,\n parquetCacheOps: {\n maxSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB\n admissionFraction: 0.2, // a single file may occupy at most 20% of the budget\n maxFilesTracked: 50_000, // ghost (previously-evicted) files remembered to guide readmission\n },\n};\n\nexport function DefaultDriverKitOpsPaths(\n workDir: string,\n): Pick<\n DriverKitOpsPaths,\n | \"blobDownloadPath\"\n | \"blobDownloadRangesCachePath\"\n | \"downloadBlobToURLPath\"\n | \"pframesSpillPath\"\n | \"parquetCachePath\"\n> {\n return {\n blobDownloadPath: path.join(workDir, \"download\"),\n blobDownloadRangesCachePath: path.join(workDir, \"downloadRangesCache\"),\n downloadBlobToURLPath: path.join(workDir, \"downloadToURL\"),\n pframesSpillPath: path.join(workDir, \"pframes\"),\n parquetCachePath: path.join(workDir, \"parquetCache\"),\n };\n}\n\n/** Fields with default values are marked as optional here. */\nexport type DriverKitOpsConstructor = Omit<\n DriverKitOpsSettings,\n keyof typeof DefaultDriverKitOpsSettings\n> &\n Partial<typeof DefaultDriverKitOpsSettings> &\n Omit<DriverKitOpsPaths, keyof ReturnType<typeof DefaultDriverKitOpsPaths>> &\n Partial<ReturnType<typeof DefaultDriverKitOpsPaths>>;\n\nexport type MiddleLayerOpsPaths = DriverKitOpsPaths & {\n /** Common root where to put frontend code. */\n readonly frontendDownloadPath: string;\n};\n\n/** Debug options for middle layer. */\nexport type MiddleLayerDebugOptions = {\n /** If true, will dump initial tree state to the file with root resource id as name. */\n dumpInitialTreeState: boolean;\n};\n\n/** Configuration controlling different aspects of middle layer behaviour. */\nexport type MiddleLayerOpsSettings = DriverKitOpsSettings & {\n /** Debug options. */\n readonly debugOps: MiddleLayerDebugOptions;\n\n /** Contain temporal options controlling how often should pl trees be\n * synchronized with the pl server. */\n readonly defaultTreeOptions: TemporalSynchronizedTreeOps;\n\n /** Defines interval in milliseconds for running periodic project maintenance job.\n * Project maintenance includes background staging rendering and cached outputs cleanup. */\n readonly projectRefreshInterval: number;\n\n /** How often to check for dev block updates */\n readonly devBlockUpdateRecheckInterval: number;\n\n /** Prioritize this channel if update is available in this block */\n readonly preferredUpdateChannel?: string;\n};\n\nexport type MiddleLayerOps = MiddleLayerOpsSettings & MiddleLayerOpsPaths;\n\n/** Some defaults fot MiddleLayerOps. */\nexport const DefaultMiddleLayerOpsSettings: Pick<\n MiddleLayerOps,\n | keyof typeof DefaultDriverKitOpsSettings\n | \"defaultTreeOptions\"\n | \"projectRefreshInterval\"\n | \"devBlockUpdateRecheckInterval\"\n | \"debugOps\"\n> = {\n ...DefaultDriverKitOpsSettings,\n defaultTreeOptions: {\n pollingInterval: 200,\n stopPollingDelay: 2500,\n initialTreeLoadingTimeout: 100 * 60 * 60 * 1000, // disable timeout for loading project tree (100 hours)\n },\n debugOps: {\n dumpInitialTreeState: false,\n },\n devBlockUpdateRecheckInterval: 1000,\n projectRefreshInterval: 2000,\n};\n\nexport function DefaultMiddleLayerOpsPaths(\n workDir: string,\n): Pick<\n MiddleLayerOpsPaths,\n keyof ReturnType<typeof DefaultDriverKitOpsPaths> | \"frontendDownloadPath\"\n> {\n return {\n ...DefaultDriverKitOpsPaths(workDir),\n frontendDownloadPath: path.join(workDir, \"frontend\"),\n };\n}\n\nexport type MiddleLayerOpsConstructor = Omit<\n MiddleLayerOpsSettings,\n keyof typeof DefaultMiddleLayerOpsSettings\n> &\n Partial<typeof DefaultMiddleLayerOpsSettings> &\n Omit<MiddleLayerOpsPaths, keyof Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>> &\n Partial<Awaited<ReturnType<typeof DefaultMiddleLayerOpsPaths>>>;\n"],"mappings":";;;;;;AAoJA,MAAa,8BAUT;CACF,QAAQ,IAAI,sBAAsB;CAClC,eAAe;EACb,oBAAoB,IAAI,OAAO,OAAO;EACtC,yBAAyB,IAAI,OAAO,OAAO;EAC3C,sBAAsB;EACvB;CACD,2BAA2B;EACzB,oBAAoB,IAAI,OAAO,OAAO;EACtC,YAAY;EACZ,sBAAsB;EACvB;CACD,4BAA4B;EAC1B,oBAAoB,IAAI,OAAO,OAAO;EACtC,sBAAsB;EACvB;CACD,iBAAiB;EACf,wBAAwB;EACxB,0BAA0B;EAC1B,iBAAiB;EACjB,kBAAkB;EACnB;CACD,oBAAoB;EAClB,oBAAoB;EACpB,iBAAiB;EACjB,kBAAkB;EACnB;CACD,iBAAiB;CACjB,iBAAiB;EACf,cAAc,IAAI,OAAO,OAAO;EAChC,mBAAmB;EACnB,iBAAiB;EAClB;CACF;AAED,SAAgB,yBACd,SAQA;AACA,QAAO;EACL,kBAAkB,KAAK,KAAK,SAAS,WAAW;EAChD,6BAA6B,KAAK,KAAK,SAAS,sBAAsB;EACtE,uBAAuB,KAAK,KAAK,SAAS,gBAAgB;EAC1D,kBAAkB,KAAK,KAAK,SAAS,UAAU;EAC/C,kBAAkB,KAAK,KAAK,SAAS,eAAe;EACrD;;;AA8CH,MAAa,gCAOT;CACF,GAAG;CACH,oBAAoB;EAClB,iBAAiB;EACjB,kBAAkB;EAClB,2BAA2B,MAAW,KAAK;EAC5C;CACD,UAAU,EACR,sBAAsB,OACvB;CACD,+BAA+B;CAC/B,wBAAwB;CACzB;AAED,SAAgB,2BACd,SAIA;AACA,QAAO;EACL,GAAG,yBAAyB,QAAQ;EACpC,sBAAsB,KAAK,KAAK,SAAS,WAAW;EACrD"}
|
package/dist/pool/driver.cjs
CHANGED
|
@@ -45,7 +45,7 @@ var LocalBlobProviderImpl = class extends _milaboratories_helpers.RefCountPoolBa
|
|
|
45
45
|
},
|
|
46
46
|
resolveBlobContent: async (blobId) => {
|
|
47
47
|
const blob = await this.getByKey(blobId).awaitStableValue(signal);
|
|
48
|
-
return await this.blobDriver.
|
|
48
|
+
return await this.blobDriver.getContentDirect(blob.handle, { signal });
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
}
|
|
@@ -136,23 +136,29 @@ var BlobStore = class extends _milaboratories_pl_model_middle_layer.PFrameIntern
|
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
138
|
var RemoteBlobProviderImpl = class RemoteBlobProviderImpl {
|
|
139
|
-
constructor(pool, server) {
|
|
139
|
+
constructor(pool, server, cache) {
|
|
140
140
|
this.pool = pool;
|
|
141
141
|
this.server = server;
|
|
142
|
+
this.cache = cache;
|
|
142
143
|
}
|
|
143
|
-
static async init(blobDriver, logger, serverOptions) {
|
|
144
|
+
static async init(blobDriver, logger, serverOptions, cacheConfig) {
|
|
144
145
|
const pool = new RemoteBlobPool(blobDriver, logger);
|
|
145
146
|
const store = new BlobStore({
|
|
146
147
|
remoteBlobProvider: pool,
|
|
147
148
|
logger
|
|
148
149
|
});
|
|
149
|
-
const
|
|
150
|
+
const cachingStore = await _milaboratories_pframes_rs_node.HttpHelpers.createCachingObjectStore({
|
|
151
|
+
upstream: store,
|
|
152
|
+
config: cacheConfig,
|
|
153
|
+
logger
|
|
154
|
+
});
|
|
155
|
+
const handler = _milaboratories_pframes_rs_node.HttpHelpers.createRequestHandler({ store: cachingStore });
|
|
150
156
|
const server = await _milaboratories_pframes_rs_node.HttpHelpers.createHttpServer({
|
|
151
157
|
...serverOptions,
|
|
152
158
|
handler
|
|
153
159
|
});
|
|
154
160
|
logger("info", `PFrames HTTP server started on ${server.info.url}`);
|
|
155
|
-
return new RemoteBlobProviderImpl(pool, server);
|
|
161
|
+
return new RemoteBlobProviderImpl(pool, server, cachingStore);
|
|
156
162
|
}
|
|
157
163
|
acquire(params) {
|
|
158
164
|
return this.pool.acquire(params);
|
|
@@ -161,11 +167,14 @@ var RemoteBlobProviderImpl = class RemoteBlobProviderImpl {
|
|
|
161
167
|
return this.server.info;
|
|
162
168
|
}
|
|
163
169
|
async getCacheMetrics() {
|
|
164
|
-
return
|
|
170
|
+
return this.cache.getMetrics();
|
|
171
|
+
}
|
|
172
|
+
async resetCache() {
|
|
173
|
+
await this.cache.reset();
|
|
165
174
|
}
|
|
166
|
-
async resetCache() {}
|
|
167
175
|
async [Symbol.asyncDispose]() {
|
|
168
176
|
await this.server.stop();
|
|
177
|
+
await this.cache[Symbol.asyncDispose]();
|
|
169
178
|
await this.pool[Symbol.asyncDispose]();
|
|
170
179
|
}
|
|
171
180
|
};
|
|
@@ -178,7 +187,10 @@ async function createPFrameDriver(params) {
|
|
|
178
187
|
await (0, _milaboratories_ts_helpers.emptyDir)(resolvedSpillPath);
|
|
179
188
|
const logger = (level, message) => params.logger[level](message);
|
|
180
189
|
const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);
|
|
181
|
-
const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, { port: params.options.parquetServerPort }
|
|
190
|
+
const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, { port: params.options.parquetServerPort }, {
|
|
191
|
+
cachePath: node_path.default.resolve(params.cachePath),
|
|
192
|
+
...params.cacheOps
|
|
193
|
+
});
|
|
182
194
|
const resolveDataInfo = (spec, data) => {
|
|
183
195
|
if ((0, _milaboratories_pl_tree.isPlTreeNodeAccessor)(data)) return require_data.parseDataInfoResource(data) ?? (0, _milaboratories_pf_driver.makeJsonDataInfo)(spec, []);
|
|
184
196
|
return (0, _platforma_sdk_model.isDataInfo)(data) ? data.type === "ParquetPartitioned" ? (0, _platforma_sdk_model.mapDataInfo)(data, (a) => require_data.traverseParquetChunkResource(a)) : (0, _platforma_sdk_model.mapDataInfo)(data, (a) => require_data.makeLocalBlobRef(a)) : (0, _milaboratories_pf_driver.makeJsonDataInfo)(spec, data);
|
package/dist/pool/driver.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.cjs","names":["RefCountPoolBase","PFrameDriverError","PFrameInternal","Readable","HttpHelpers","AbstractPFrameDriverOpsDefaults","path","parseDataInfoResource","traverseParquetChunkResource","makeLocalBlobRef","AbstractPFrameDriver"],"sources":["../../src/pool/driver.ts"],"sourcesContent":["import {\n mapDataInfo,\n isDataInfo,\n ensureError,\n PFrameDriverError,\n isAbortError,\n type LocalBlobHandleAndSize,\n type RemoteBlobHandleAndSize,\n type RemoteBlobHandle,\n type ContentHandler,\n type PColumnSpec,\n type PColumnDataUniversal,\n} from \"@platforma-sdk/model\";\nimport { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { emptyDir } from \"@milaboratories/ts-helpers\";\nimport { RefCountPoolBase, type PoolEntry, type MiLogger } from \"@milaboratories/helpers\";\nimport type { DownloadDriver } from \"@milaboratories/pl-drivers\";\nimport { isPlTreeNodeAccessor, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport type { Computable, ComputableStableDefined } from \"@milaboratories/computable\";\nimport {\n makeJsonDataInfo,\n AbstractPFrameDriver,\n AbstractPFrameDriverOpsDefaults,\n type AbstractInternalPFrameDriver,\n type AbstractPFrameDriverOps,\n type LocalBlobProvider,\n type RemoteBlobProvider,\n} from \"@milaboratories/pf-driver\";\nimport { HttpHelpers } from \"@milaboratories/pframes-rs-node\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport {\n BlobResourceRef,\n makeLocalBlobRef,\n parseDataInfoResource,\n traverseParquetChunkResource,\n} from \"./data\";\nimport { isDownloadNetworkError400 } from \"@milaboratories/pl-drivers\";\nimport { parseSignedResourceId } from \"@milaboratories/pl-client\";\n\nfunction makeBlobId(res: BlobResourceRef): PFrameInternal.PFrameBlobId {\n const { globalId } = parseSignedResourceId(res.resourceInfo.id);\n return String(globalId) as PFrameInternal.PFrameBlobId;\n}\n\ntype LocalBlob = ComputableStableDefined<LocalBlobHandleAndSize>;\nclass LocalBlobProviderImpl\n extends RefCountPoolBase<BlobResourceRef, PFrameInternal.PFrameBlobId, LocalBlob>\n implements LocalBlobProvider<BlobResourceRef>\n{\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): LocalBlob {\n return this.blobDriver.getDownloadedBlob(params.resourceInfo);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): LocalBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Local blob with id ${blobId} not found.`);\n return resource;\n }\n\n public makeDataSource(\n signal: AbortSignal,\n ): Omit<PFrameInternal.PFrameDataSourceV2, \"parquetServer\"> {\n return {\n preloadBlob: async (blobIds: PFrameInternal.PFrameBlobId[]) => {\n try {\n await Promise.all(\n blobIds.map((blobId) => this.getByKey(blobId).awaitStableFullValue(signal)),\n );\n } catch (err: unknown) {\n if (!isAbortError(err)) throw err;\n }\n },\n resolveBlobContent: async (blobId: PFrameInternal.PFrameBlobId) => {\n const computable = this.getByKey(blobId);\n const blob = await computable.awaitStableValue(signal);\n return await this.blobDriver.getContent(blob.handle, { signal });\n },\n };\n }\n}\n\ntype RemoteBlob = Computable<RemoteBlobHandleAndSize>;\nclass RemoteBlobPool extends RefCountPoolBase<\n BlobResourceRef,\n PFrameInternal.PFrameBlobId,\n RemoteBlob\n> {\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): RemoteBlob {\n if (params.onDemandSnapshot === undefined) {\n throw new PFrameDriverError(\n `BlobResourceRef for rid ${params.toJSON()} is missing the on-demand snapshot; ` +\n `remote (parquet) blobs must be captured via makeRemoteBlobRef.`,\n );\n }\n return this.blobDriver.getOnDemandBlob(params.onDemandSnapshot);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): RemoteBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Remote blob with id ${blobId} not found.`);\n return resource;\n }\n\n public async withContent<T>(\n handle: RemoteBlobHandle,\n options: {\n range: PFrameInternal.FileRange;\n signal: AbortSignal;\n handler: ContentHandler<T>;\n },\n ): Promise<T> {\n return await this.blobDriver.withContent(handle, {\n range: {\n from: options.range.start,\n to: options.range.end + 1,\n },\n signal: options.signal,\n handler: options.handler,\n });\n }\n}\n\ninterface BlobStoreOptions extends PFrameInternal.ObjectStoreOptions {\n remoteBlobProvider: RemoteBlobPool;\n}\n\nclass BlobStore extends PFrameInternal.BaseObjectStore {\n private readonly remoteBlobProvider: RemoteBlobPool;\n\n constructor(options: BlobStoreOptions) {\n super(options);\n this.remoteBlobProvider = options.remoteBlobProvider;\n }\n\n public override async request(\n filename: PFrameInternal.ParquetFileName,\n params: {\n method: PFrameInternal.HttpMethod;\n range?: PFrameInternal.HttpRange;\n signal: AbortSignal;\n callback: (response: PFrameInternal.ObjectStoreResponse) => Promise<void>;\n },\n ): Promise<void> {\n const blobId = filename.slice(\n 0,\n -PFrameInternal.ParquetExtension.length,\n ) as PFrameInternal.PFrameBlobId;\n const respond = async (response: PFrameInternal.ObjectStoreResponse): Promise<void> => {\n try {\n await params.callback(response);\n } catch (error: unknown) {\n this.logger(\n \"warn\",\n `PFrames blob store received unhandled rejection from HTTP handler: ${ensureError(error)}`,\n );\n }\n };\n\n try {\n const computable = this.remoteBlobProvider.tryGetByKey(blobId);\n if (!computable) return await respond({ type: \"NotFound\" });\n\n let blob: RemoteBlobHandleAndSize;\n try {\n blob = await computable.getValue();\n } catch (error: unknown) {\n this.logger(\n \"error\",\n `PFrames blob store failed to get blob from computable: ${ensureError(error)}`,\n );\n return await respond({ type: \"InternalError\" });\n }\n params.signal.throwIfAborted();\n\n const translatedRange = this.translate(blob.size, params.range);\n if (!translatedRange) {\n return await respond({\n type: \"RangeNotSatisfiable\",\n size: blob.size,\n });\n }\n\n if (params.method === \"HEAD\") {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n });\n }\n\n this.logger(\n \"info\",\n `PFrames blob store requesting content for ${blobId}, ` +\n `range [${translatedRange.start}..=${translatedRange.end}]`,\n );\n return await this.remoteBlobProvider.withContent(blob.handle, {\n range: translatedRange,\n signal: params.signal,\n handler: async (data) => {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n data: Readable.fromWeb(data),\n });\n },\n });\n } catch (error: unknown) {\n if (!isAbortError(error)) {\n if (isDownloadNetworkError400(error) && error.statusCode === 404) {\n this.logger(\"info\", `PFrames blob store known race error: ${ensureError(error)}`);\n } else {\n this.logger(\"warn\", `PFrames blob store unhandled error: ${ensureError(error)}`);\n }\n }\n return await respond({ type: \"InternalError\" });\n }\n }\n}\n\nclass RemoteBlobProviderImpl implements RemoteBlobProvider<BlobResourceRef> {\n constructor(\n private readonly pool: RemoteBlobPool,\n private readonly server: PFrameInternal.HttpServer,\n // TODO: private readonly cache: PFrameInternal.CachingObjectStore,\n ) {}\n\n public static async init(\n blobDriver: DownloadDriver,\n logger: PFrameInternal.Logger,\n serverOptions: Omit<PFrameInternal.HttpServerOptions, \"handler\">,\n ): Promise<RemoteBlobProviderImpl> {\n const pool = new RemoteBlobPool(blobDriver, logger);\n const store = new BlobStore({ remoteBlobProvider: pool, logger });\n // TODO: const cachingStore = HttpHelpers.createCachingObjectStore({ ... });\n\n const handler = HttpHelpers.createRequestHandler({ store });\n const server = await HttpHelpers.createHttpServer({ ...serverOptions, handler });\n logger(\"info\", `PFrames HTTP server started on ${server.info.url}`);\n\n return new RemoteBlobProviderImpl(pool, server);\n }\n\n public acquire(params: BlobResourceRef): PoolEntry<PFrameInternal.PFrameBlobId> {\n return this.pool.acquire(params);\n }\n\n public httpServerInfo(): PFrameInternal.HttpServerInfo {\n return this.server.info;\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return null; // TODO: this.cache.getMetrics()\n }\n\n public async resetCache(): Promise<void> {\n // TODO: this.cache.reset()\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\n // TODO: await this.cache[Symbol.asyncDispose]();\n await this.pool[Symbol.asyncDispose]();\n }\n}\n\nexport interface InternalPFrameDriver extends AbstractInternalPFrameDriver<\n PColumnDataUniversal<PlTreeNodeAccessor>\n> {}\n\nexport type PFrameDriverOps = AbstractPFrameDriverOps & {\n /** Port to run parquet HTTP server on. */\n parquetServerPort: number;\n};\n\nexport const PFrameDriverOpsDefaults: PFrameDriverOps = {\n ...AbstractPFrameDriverOpsDefaults,\n parquetServerPort: 0, // 0 means that some unused port will be assigned by the OS\n};\n\nexport async function createPFrameDriver(params: {\n blobDriver: DownloadDriver;\n logger: MiLogger;\n spillPath: string;\n options: PFrameDriverOps;\n}): Promise<InternalPFrameDriver> {\n const resolvedSpillPath = path.resolve(params.spillPath);\n await emptyDir(resolvedSpillPath);\n\n const logger: PFrameInternal.Logger = (level, message) => params.logger[level](message);\n const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);\n const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, {\n port: params.options.parquetServerPort,\n });\n\n const resolveDataInfo = (spec: PColumnSpec, data: PColumnDataUniversal<PlTreeNodeAccessor>) => {\n if (isPlTreeNodeAccessor(data)) {\n return parseDataInfoResource(data) ?? makeJsonDataInfo(spec, []);\n }\n\n return isDataInfo(data)\n ? data.type === \"ParquetPartitioned\"\n ? mapDataInfo(data, (a) => traverseParquetChunkResource(a))\n : mapDataInfo(data, (a) => makeLocalBlobRef(a))\n : makeJsonDataInfo(spec, data);\n };\n\n return new AbstractPFrameDriver({\n logger,\n localBlobProvider,\n remoteBlobProvider,\n spillPath: resolvedSpillPath,\n options: params.options,\n resolveDataInfo,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"driver.cjs","names":["RefCountPoolBase","PFrameDriverError","PFrameInternal","Readable","HttpHelpers","AbstractPFrameDriverOpsDefaults","path","parseDataInfoResource","traverseParquetChunkResource","makeLocalBlobRef","AbstractPFrameDriver"],"sources":["../../src/pool/driver.ts"],"sourcesContent":["import {\n mapDataInfo,\n isDataInfo,\n ensureError,\n PFrameDriverError,\n isAbortError,\n type LocalBlobHandleAndSize,\n type RemoteBlobHandleAndSize,\n type RemoteBlobHandle,\n type ContentHandler,\n type PColumnSpec,\n type PColumnDataUniversal,\n} from \"@platforma-sdk/model\";\nimport { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { emptyDir } from \"@milaboratories/ts-helpers\";\nimport { RefCountPoolBase, type PoolEntry, type MiLogger } from \"@milaboratories/helpers\";\nimport type { DownloadDriver } from \"@milaboratories/pl-drivers\";\nimport { isPlTreeNodeAccessor, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport type { Computable, ComputableStableDefined } from \"@milaboratories/computable\";\nimport {\n makeJsonDataInfo,\n AbstractPFrameDriver,\n AbstractPFrameDriverOpsDefaults,\n type AbstractInternalPFrameDriver,\n type AbstractPFrameDriverOps,\n type LocalBlobProvider,\n type RemoteBlobProvider,\n} from \"@milaboratories/pf-driver\";\nimport { HttpHelpers } from \"@milaboratories/pframes-rs-node\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport {\n BlobResourceRef,\n makeLocalBlobRef,\n parseDataInfoResource,\n traverseParquetChunkResource,\n} from \"./data\";\nimport { isDownloadNetworkError400 } from \"@milaboratories/pl-drivers\";\nimport { parseSignedResourceId } from \"@milaboratories/pl-client\";\n\nfunction makeBlobId(res: BlobResourceRef): PFrameInternal.PFrameBlobId {\n const { globalId } = parseSignedResourceId(res.resourceInfo.id);\n return String(globalId) as PFrameInternal.PFrameBlobId;\n}\n\ntype LocalBlob = ComputableStableDefined<LocalBlobHandleAndSize>;\nclass LocalBlobProviderImpl\n extends RefCountPoolBase<BlobResourceRef, PFrameInternal.PFrameBlobId, LocalBlob>\n implements LocalBlobProvider<BlobResourceRef>\n{\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): LocalBlob {\n return this.blobDriver.getDownloadedBlob(params.resourceInfo);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): LocalBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Local blob with id ${blobId} not found.`);\n return resource;\n }\n\n public makeDataSource(\n signal: AbortSignal,\n ): Omit<PFrameInternal.PFrameDataSourceV2, \"parquetServer\"> {\n return {\n preloadBlob: async (blobIds: PFrameInternal.PFrameBlobId[]) => {\n try {\n await Promise.all(\n blobIds.map((blobId) => this.getByKey(blobId).awaitStableFullValue(signal)),\n );\n } catch (err: unknown) {\n if (!isAbortError(err)) throw err;\n }\n },\n resolveBlobContent: async (blobId: PFrameInternal.PFrameBlobId) => {\n const computable = this.getByKey(blobId);\n const blob = await computable.awaitStableValue(signal);\n return await this.blobDriver.getContentDirect(blob.handle, { signal });\n },\n };\n }\n}\n\ntype RemoteBlob = Computable<RemoteBlobHandleAndSize>;\nclass RemoteBlobPool extends RefCountPoolBase<\n BlobResourceRef,\n PFrameInternal.PFrameBlobId,\n RemoteBlob\n> {\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): RemoteBlob {\n if (params.onDemandSnapshot === undefined) {\n throw new PFrameDriverError(\n `BlobResourceRef for rid ${params.toJSON()} is missing the on-demand snapshot; ` +\n `remote (parquet) blobs must be captured via makeRemoteBlobRef.`,\n );\n }\n return this.blobDriver.getOnDemandBlob(params.onDemandSnapshot);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): RemoteBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Remote blob with id ${blobId} not found.`);\n return resource;\n }\n\n public async withContent<T>(\n handle: RemoteBlobHandle,\n options: {\n range: PFrameInternal.FileRange;\n signal: AbortSignal;\n handler: ContentHandler<T>;\n },\n ): Promise<T> {\n return await this.blobDriver.withContent(handle, {\n range: {\n from: options.range.start,\n to: options.range.end + 1,\n },\n signal: options.signal,\n handler: options.handler,\n });\n }\n}\n\ninterface BlobStoreOptions extends PFrameInternal.ObjectStoreOptions {\n remoteBlobProvider: RemoteBlobPool;\n}\n\nclass BlobStore extends PFrameInternal.BaseObjectStore {\n private readonly remoteBlobProvider: RemoteBlobPool;\n\n constructor(options: BlobStoreOptions) {\n super(options);\n this.remoteBlobProvider = options.remoteBlobProvider;\n }\n\n public override async request(\n filename: PFrameInternal.ParquetFileName,\n params: {\n method: PFrameInternal.HttpMethod;\n range?: PFrameInternal.HttpRange;\n signal: AbortSignal;\n callback: (response: PFrameInternal.ObjectStoreResponse) => Promise<void>;\n },\n ): Promise<void> {\n const blobId = filename.slice(\n 0,\n -PFrameInternal.ParquetExtension.length,\n ) as PFrameInternal.PFrameBlobId;\n const respond = async (response: PFrameInternal.ObjectStoreResponse): Promise<void> => {\n try {\n await params.callback(response);\n } catch (error: unknown) {\n this.logger(\n \"warn\",\n `PFrames blob store received unhandled rejection from HTTP handler: ${ensureError(error)}`,\n );\n }\n };\n\n try {\n const computable = this.remoteBlobProvider.tryGetByKey(blobId);\n if (!computable) return await respond({ type: \"NotFound\" });\n\n let blob: RemoteBlobHandleAndSize;\n try {\n blob = await computable.getValue();\n } catch (error: unknown) {\n this.logger(\n \"error\",\n `PFrames blob store failed to get blob from computable: ${ensureError(error)}`,\n );\n return await respond({ type: \"InternalError\" });\n }\n params.signal.throwIfAborted();\n\n const translatedRange = this.translate(blob.size, params.range);\n if (!translatedRange) {\n return await respond({\n type: \"RangeNotSatisfiable\",\n size: blob.size,\n });\n }\n\n if (params.method === \"HEAD\") {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n });\n }\n\n this.logger(\n \"info\",\n `PFrames blob store requesting content for ${blobId}, ` +\n `range [${translatedRange.start}..=${translatedRange.end}]`,\n );\n return await this.remoteBlobProvider.withContent(blob.handle, {\n range: translatedRange,\n signal: params.signal,\n handler: async (data) => {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n data: Readable.fromWeb(data),\n });\n },\n });\n } catch (error: unknown) {\n if (!isAbortError(error)) {\n if (isDownloadNetworkError400(error) && error.statusCode === 404) {\n this.logger(\"info\", `PFrames blob store known race error: ${ensureError(error)}`);\n } else {\n this.logger(\"warn\", `PFrames blob store unhandled error: ${ensureError(error)}`);\n }\n }\n return await respond({ type: \"InternalError\" });\n }\n }\n}\n\nclass RemoteBlobProviderImpl implements RemoteBlobProvider<BlobResourceRef> {\n constructor(\n private readonly pool: RemoteBlobPool,\n private readonly server: PFrameInternal.HttpServer,\n private readonly cache: PFrameInternal.CachingObjectStore,\n ) {}\n\n public static async init(\n blobDriver: DownloadDriver,\n logger: PFrameInternal.Logger,\n serverOptions: Omit<PFrameInternal.HttpServerOptions, \"handler\">,\n cacheConfig: PFrameInternal.CacheConfig,\n ): Promise<RemoteBlobProviderImpl> {\n const pool = new RemoteBlobPool(blobDriver, logger);\n const store = new BlobStore({ remoteBlobProvider: pool, logger });\n const cachingStore = await HttpHelpers.createCachingObjectStore({\n upstream: store,\n config: cacheConfig,\n logger,\n });\n\n const handler = HttpHelpers.createRequestHandler({ store: cachingStore });\n const server = await HttpHelpers.createHttpServer({ ...serverOptions, handler });\n logger(\"info\", `PFrames HTTP server started on ${server.info.url}`);\n\n return new RemoteBlobProviderImpl(pool, server, cachingStore);\n }\n\n public acquire(params: BlobResourceRef): PoolEntry<PFrameInternal.PFrameBlobId> {\n return this.pool.acquire(params);\n }\n\n public httpServerInfo(): PFrameInternal.HttpServerInfo {\n return this.server.info;\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return this.cache.getMetrics();\n }\n\n public async resetCache(): Promise<void> {\n await this.cache.reset();\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\n await this.cache[Symbol.asyncDispose]();\n await this.pool[Symbol.asyncDispose]();\n }\n}\n\nexport interface InternalPFrameDriver extends AbstractInternalPFrameDriver<\n PColumnDataUniversal<PlTreeNodeAccessor>\n> {}\n\nexport type PFrameDriverOps = AbstractPFrameDriverOps & {\n /** Port to run parquet HTTP server on. */\n parquetServerPort: number;\n};\n\nexport const PFrameDriverOpsDefaults: PFrameDriverOps = {\n ...AbstractPFrameDriverOpsDefaults,\n parquetServerPort: 0, // 0 means that some unused port will be assigned by the OS\n};\n\n/**\n * Tuning for the persistent parquet blob cache, minus its filesystem path (which\n * is supplied separately - see {@link createPFrameDriver}'s `cachePath`). Carries\n * only the size/eviction knobs of {@link PFrameInternal.CacheConfig}.\n */\nexport type ParquetCacheOps = Omit<PFrameInternal.CacheConfig, \"cachePath\">;\n\nexport async function createPFrameDriver(params: {\n blobDriver: DownloadDriver;\n logger: MiLogger;\n spillPath: string;\n cachePath: string;\n options: PFrameDriverOps;\n cacheOps: ParquetCacheOps;\n}): Promise<InternalPFrameDriver> {\n const resolvedSpillPath = path.resolve(params.spillPath);\n await emptyDir(resolvedSpillPath);\n\n const logger: PFrameInternal.Logger = (level, message) => params.logger[level](message);\n const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);\n const remoteBlobProvider = await RemoteBlobProviderImpl.init(\n params.blobDriver,\n logger,\n { port: params.options.parquetServerPort },\n { cachePath: path.resolve(params.cachePath), ...params.cacheOps },\n );\n\n const resolveDataInfo = (spec: PColumnSpec, data: PColumnDataUniversal<PlTreeNodeAccessor>) => {\n if (isPlTreeNodeAccessor(data)) {\n return parseDataInfoResource(data) ?? makeJsonDataInfo(spec, []);\n }\n\n return isDataInfo(data)\n ? data.type === \"ParquetPartitioned\"\n ? mapDataInfo(data, (a) => traverseParquetChunkResource(a))\n : mapDataInfo(data, (a) => makeLocalBlobRef(a))\n : makeJsonDataInfo(spec, data);\n };\n\n return new AbstractPFrameDriver({\n logger,\n localBlobProvider,\n remoteBlobProvider,\n spillPath: resolvedSpillPath,\n options: params.options,\n resolveDataInfo,\n });\n}\n"],"mappings":"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"}
|
package/dist/pool/driver.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PColumnDataUniversal } from "@platforma-sdk/model";
|
|
2
|
+
import { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
2
3
|
import { PlTreeNodeAccessor } from "@milaboratories/pl-tree";
|
|
3
4
|
import { DownloadDriver } from "@milaboratories/pl-drivers";
|
|
4
5
|
import { AbstractInternalPFrameDriver, AbstractPFrameDriverOps } from "@milaboratories/pf-driver";
|
|
@@ -8,6 +9,12 @@ interface InternalPFrameDriver extends AbstractInternalPFrameDriver<PColumnDataU
|
|
|
8
9
|
type PFrameDriverOps = AbstractPFrameDriverOps & {
|
|
9
10
|
/** Port to run parquet HTTP server on. */parquetServerPort: number;
|
|
10
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Tuning for the persistent parquet blob cache, minus its filesystem path (which
|
|
14
|
+
* is supplied separately - see {@link createPFrameDriver}'s `cachePath`). Carries
|
|
15
|
+
* only the size/eviction knobs of {@link PFrameInternal.CacheConfig}.
|
|
16
|
+
*/
|
|
17
|
+
type ParquetCacheOps = Omit<PFrameInternal.CacheConfig, "cachePath">;
|
|
11
18
|
//#endregion
|
|
12
|
-
export { InternalPFrameDriver, PFrameDriverOps };
|
|
19
|
+
export { InternalPFrameDriver, PFrameDriverOps, ParquetCacheOps };
|
|
13
20
|
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.d.ts","names":[],"sources":["../../src/pool/driver.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"driver.d.ts","names":[],"sources":["../../src/pool/driver.ts"],"mappings":";;;;;;;UA4SiB,oBAAA,SAA6B,4BAAA,CAC5C,oBAAA,CAAqB,kBAAA;AAAA,KAGX,eAAA,GAAkB,uBAAA;EAJQ,0CAMpC,iBAAA;AAAA;;;;;;KAaU,eAAA,GAAkB,IAAA,CAAK,cAAA,CAAe,WAAA"}
|
package/dist/pool/driver.js
CHANGED
|
@@ -43,7 +43,7 @@ var LocalBlobProviderImpl = class extends RefCountPoolBase {
|
|
|
43
43
|
},
|
|
44
44
|
resolveBlobContent: async (blobId) => {
|
|
45
45
|
const blob = await this.getByKey(blobId).awaitStableValue(signal);
|
|
46
|
-
return await this.blobDriver.
|
|
46
|
+
return await this.blobDriver.getContentDirect(blob.handle, { signal });
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
}
|
|
@@ -134,23 +134,29 @@ var BlobStore = class extends PFrameInternal.BaseObjectStore {
|
|
|
134
134
|
}
|
|
135
135
|
};
|
|
136
136
|
var RemoteBlobProviderImpl = class RemoteBlobProviderImpl {
|
|
137
|
-
constructor(pool, server) {
|
|
137
|
+
constructor(pool, server, cache) {
|
|
138
138
|
this.pool = pool;
|
|
139
139
|
this.server = server;
|
|
140
|
+
this.cache = cache;
|
|
140
141
|
}
|
|
141
|
-
static async init(blobDriver, logger, serverOptions) {
|
|
142
|
+
static async init(blobDriver, logger, serverOptions, cacheConfig) {
|
|
142
143
|
const pool = new RemoteBlobPool(blobDriver, logger);
|
|
143
144
|
const store = new BlobStore({
|
|
144
145
|
remoteBlobProvider: pool,
|
|
145
146
|
logger
|
|
146
147
|
});
|
|
147
|
-
const
|
|
148
|
+
const cachingStore = await HttpHelpers.createCachingObjectStore({
|
|
149
|
+
upstream: store,
|
|
150
|
+
config: cacheConfig,
|
|
151
|
+
logger
|
|
152
|
+
});
|
|
153
|
+
const handler = HttpHelpers.createRequestHandler({ store: cachingStore });
|
|
148
154
|
const server = await HttpHelpers.createHttpServer({
|
|
149
155
|
...serverOptions,
|
|
150
156
|
handler
|
|
151
157
|
});
|
|
152
158
|
logger("info", `PFrames HTTP server started on ${server.info.url}`);
|
|
153
|
-
return new RemoteBlobProviderImpl(pool, server);
|
|
159
|
+
return new RemoteBlobProviderImpl(pool, server, cachingStore);
|
|
154
160
|
}
|
|
155
161
|
acquire(params) {
|
|
156
162
|
return this.pool.acquire(params);
|
|
@@ -159,11 +165,14 @@ var RemoteBlobProviderImpl = class RemoteBlobProviderImpl {
|
|
|
159
165
|
return this.server.info;
|
|
160
166
|
}
|
|
161
167
|
async getCacheMetrics() {
|
|
162
|
-
return
|
|
168
|
+
return this.cache.getMetrics();
|
|
169
|
+
}
|
|
170
|
+
async resetCache() {
|
|
171
|
+
await this.cache.reset();
|
|
163
172
|
}
|
|
164
|
-
async resetCache() {}
|
|
165
173
|
async [Symbol.asyncDispose]() {
|
|
166
174
|
await this.server.stop();
|
|
175
|
+
await this.cache[Symbol.asyncDispose]();
|
|
167
176
|
await this.pool[Symbol.asyncDispose]();
|
|
168
177
|
}
|
|
169
178
|
};
|
|
@@ -176,7 +185,10 @@ async function createPFrameDriver(params) {
|
|
|
176
185
|
await emptyDir(resolvedSpillPath);
|
|
177
186
|
const logger = (level, message) => params.logger[level](message);
|
|
178
187
|
const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);
|
|
179
|
-
const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, { port: params.options.parquetServerPort }
|
|
188
|
+
const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, { port: params.options.parquetServerPort }, {
|
|
189
|
+
cachePath: path.resolve(params.cachePath),
|
|
190
|
+
...params.cacheOps
|
|
191
|
+
});
|
|
180
192
|
const resolveDataInfo = (spec, data) => {
|
|
181
193
|
if (isPlTreeNodeAccessor(data)) return parseDataInfoResource(data) ?? makeJsonDataInfo(spec, []);
|
|
182
194
|
return isDataInfo(data) ? data.type === "ParquetPartitioned" ? mapDataInfo(data, (a) => traverseParquetChunkResource(a)) : mapDataInfo(data, (a) => makeLocalBlobRef(a)) : makeJsonDataInfo(spec, data);
|
package/dist/pool/driver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.js","names":[],"sources":["../../src/pool/driver.ts"],"sourcesContent":["import {\n mapDataInfo,\n isDataInfo,\n ensureError,\n PFrameDriverError,\n isAbortError,\n type LocalBlobHandleAndSize,\n type RemoteBlobHandleAndSize,\n type RemoteBlobHandle,\n type ContentHandler,\n type PColumnSpec,\n type PColumnDataUniversal,\n} from \"@platforma-sdk/model\";\nimport { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { emptyDir } from \"@milaboratories/ts-helpers\";\nimport { RefCountPoolBase, type PoolEntry, type MiLogger } from \"@milaboratories/helpers\";\nimport type { DownloadDriver } from \"@milaboratories/pl-drivers\";\nimport { isPlTreeNodeAccessor, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport type { Computable, ComputableStableDefined } from \"@milaboratories/computable\";\nimport {\n makeJsonDataInfo,\n AbstractPFrameDriver,\n AbstractPFrameDriverOpsDefaults,\n type AbstractInternalPFrameDriver,\n type AbstractPFrameDriverOps,\n type LocalBlobProvider,\n type RemoteBlobProvider,\n} from \"@milaboratories/pf-driver\";\nimport { HttpHelpers } from \"@milaboratories/pframes-rs-node\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport {\n BlobResourceRef,\n makeLocalBlobRef,\n parseDataInfoResource,\n traverseParquetChunkResource,\n} from \"./data\";\nimport { isDownloadNetworkError400 } from \"@milaboratories/pl-drivers\";\nimport { parseSignedResourceId } from \"@milaboratories/pl-client\";\n\nfunction makeBlobId(res: BlobResourceRef): PFrameInternal.PFrameBlobId {\n const { globalId } = parseSignedResourceId(res.resourceInfo.id);\n return String(globalId) as PFrameInternal.PFrameBlobId;\n}\n\ntype LocalBlob = ComputableStableDefined<LocalBlobHandleAndSize>;\nclass LocalBlobProviderImpl\n extends RefCountPoolBase<BlobResourceRef, PFrameInternal.PFrameBlobId, LocalBlob>\n implements LocalBlobProvider<BlobResourceRef>\n{\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): LocalBlob {\n return this.blobDriver.getDownloadedBlob(params.resourceInfo);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): LocalBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Local blob with id ${blobId} not found.`);\n return resource;\n }\n\n public makeDataSource(\n signal: AbortSignal,\n ): Omit<PFrameInternal.PFrameDataSourceV2, \"parquetServer\"> {\n return {\n preloadBlob: async (blobIds: PFrameInternal.PFrameBlobId[]) => {\n try {\n await Promise.all(\n blobIds.map((blobId) => this.getByKey(blobId).awaitStableFullValue(signal)),\n );\n } catch (err: unknown) {\n if (!isAbortError(err)) throw err;\n }\n },\n resolveBlobContent: async (blobId: PFrameInternal.PFrameBlobId) => {\n const computable = this.getByKey(blobId);\n const blob = await computable.awaitStableValue(signal);\n return await this.blobDriver.getContent(blob.handle, { signal });\n },\n };\n }\n}\n\ntype RemoteBlob = Computable<RemoteBlobHandleAndSize>;\nclass RemoteBlobPool extends RefCountPoolBase<\n BlobResourceRef,\n PFrameInternal.PFrameBlobId,\n RemoteBlob\n> {\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): RemoteBlob {\n if (params.onDemandSnapshot === undefined) {\n throw new PFrameDriverError(\n `BlobResourceRef for rid ${params.toJSON()} is missing the on-demand snapshot; ` +\n `remote (parquet) blobs must be captured via makeRemoteBlobRef.`,\n );\n }\n return this.blobDriver.getOnDemandBlob(params.onDemandSnapshot);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): RemoteBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Remote blob with id ${blobId} not found.`);\n return resource;\n }\n\n public async withContent<T>(\n handle: RemoteBlobHandle,\n options: {\n range: PFrameInternal.FileRange;\n signal: AbortSignal;\n handler: ContentHandler<T>;\n },\n ): Promise<T> {\n return await this.blobDriver.withContent(handle, {\n range: {\n from: options.range.start,\n to: options.range.end + 1,\n },\n signal: options.signal,\n handler: options.handler,\n });\n }\n}\n\ninterface BlobStoreOptions extends PFrameInternal.ObjectStoreOptions {\n remoteBlobProvider: RemoteBlobPool;\n}\n\nclass BlobStore extends PFrameInternal.BaseObjectStore {\n private readonly remoteBlobProvider: RemoteBlobPool;\n\n constructor(options: BlobStoreOptions) {\n super(options);\n this.remoteBlobProvider = options.remoteBlobProvider;\n }\n\n public override async request(\n filename: PFrameInternal.ParquetFileName,\n params: {\n method: PFrameInternal.HttpMethod;\n range?: PFrameInternal.HttpRange;\n signal: AbortSignal;\n callback: (response: PFrameInternal.ObjectStoreResponse) => Promise<void>;\n },\n ): Promise<void> {\n const blobId = filename.slice(\n 0,\n -PFrameInternal.ParquetExtension.length,\n ) as PFrameInternal.PFrameBlobId;\n const respond = async (response: PFrameInternal.ObjectStoreResponse): Promise<void> => {\n try {\n await params.callback(response);\n } catch (error: unknown) {\n this.logger(\n \"warn\",\n `PFrames blob store received unhandled rejection from HTTP handler: ${ensureError(error)}`,\n );\n }\n };\n\n try {\n const computable = this.remoteBlobProvider.tryGetByKey(blobId);\n if (!computable) return await respond({ type: \"NotFound\" });\n\n let blob: RemoteBlobHandleAndSize;\n try {\n blob = await computable.getValue();\n } catch (error: unknown) {\n this.logger(\n \"error\",\n `PFrames blob store failed to get blob from computable: ${ensureError(error)}`,\n );\n return await respond({ type: \"InternalError\" });\n }\n params.signal.throwIfAborted();\n\n const translatedRange = this.translate(blob.size, params.range);\n if (!translatedRange) {\n return await respond({\n type: \"RangeNotSatisfiable\",\n size: blob.size,\n });\n }\n\n if (params.method === \"HEAD\") {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n });\n }\n\n this.logger(\n \"info\",\n `PFrames blob store requesting content for ${blobId}, ` +\n `range [${translatedRange.start}..=${translatedRange.end}]`,\n );\n return await this.remoteBlobProvider.withContent(blob.handle, {\n range: translatedRange,\n signal: params.signal,\n handler: async (data) => {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n data: Readable.fromWeb(data),\n });\n },\n });\n } catch (error: unknown) {\n if (!isAbortError(error)) {\n if (isDownloadNetworkError400(error) && error.statusCode === 404) {\n this.logger(\"info\", `PFrames blob store known race error: ${ensureError(error)}`);\n } else {\n this.logger(\"warn\", `PFrames blob store unhandled error: ${ensureError(error)}`);\n }\n }\n return await respond({ type: \"InternalError\" });\n }\n }\n}\n\nclass RemoteBlobProviderImpl implements RemoteBlobProvider<BlobResourceRef> {\n constructor(\n private readonly pool: RemoteBlobPool,\n private readonly server: PFrameInternal.HttpServer,\n // TODO: private readonly cache: PFrameInternal.CachingObjectStore,\n ) {}\n\n public static async init(\n blobDriver: DownloadDriver,\n logger: PFrameInternal.Logger,\n serverOptions: Omit<PFrameInternal.HttpServerOptions, \"handler\">,\n ): Promise<RemoteBlobProviderImpl> {\n const pool = new RemoteBlobPool(blobDriver, logger);\n const store = new BlobStore({ remoteBlobProvider: pool, logger });\n // TODO: const cachingStore = HttpHelpers.createCachingObjectStore({ ... });\n\n const handler = HttpHelpers.createRequestHandler({ store });\n const server = await HttpHelpers.createHttpServer({ ...serverOptions, handler });\n logger(\"info\", `PFrames HTTP server started on ${server.info.url}`);\n\n return new RemoteBlobProviderImpl(pool, server);\n }\n\n public acquire(params: BlobResourceRef): PoolEntry<PFrameInternal.PFrameBlobId> {\n return this.pool.acquire(params);\n }\n\n public httpServerInfo(): PFrameInternal.HttpServerInfo {\n return this.server.info;\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return null; // TODO: this.cache.getMetrics()\n }\n\n public async resetCache(): Promise<void> {\n // TODO: this.cache.reset()\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\n // TODO: await this.cache[Symbol.asyncDispose]();\n await this.pool[Symbol.asyncDispose]();\n }\n}\n\nexport interface InternalPFrameDriver extends AbstractInternalPFrameDriver<\n PColumnDataUniversal<PlTreeNodeAccessor>\n> {}\n\nexport type PFrameDriverOps = AbstractPFrameDriverOps & {\n /** Port to run parquet HTTP server on. */\n parquetServerPort: number;\n};\n\nexport const PFrameDriverOpsDefaults: PFrameDriverOps = {\n ...AbstractPFrameDriverOpsDefaults,\n parquetServerPort: 0, // 0 means that some unused port will be assigned by the OS\n};\n\nexport async function createPFrameDriver(params: {\n blobDriver: DownloadDriver;\n logger: MiLogger;\n spillPath: string;\n options: PFrameDriverOps;\n}): Promise<InternalPFrameDriver> {\n const resolvedSpillPath = path.resolve(params.spillPath);\n await emptyDir(resolvedSpillPath);\n\n const logger: PFrameInternal.Logger = (level, message) => params.logger[level](message);\n const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);\n const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, {\n port: params.options.parquetServerPort,\n });\n\n const resolveDataInfo = (spec: PColumnSpec, data: PColumnDataUniversal<PlTreeNodeAccessor>) => {\n if (isPlTreeNodeAccessor(data)) {\n return parseDataInfoResource(data) ?? makeJsonDataInfo(spec, []);\n }\n\n return isDataInfo(data)\n ? data.type === \"ParquetPartitioned\"\n ? mapDataInfo(data, (a) => traverseParquetChunkResource(a))\n : mapDataInfo(data, (a) => makeLocalBlobRef(a))\n : makeJsonDataInfo(spec, data);\n };\n\n return new AbstractPFrameDriver({\n logger,\n localBlobProvider,\n remoteBlobProvider,\n spillPath: resolvedSpillPath,\n options: params.options,\n resolveDataInfo,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"driver.js","names":[],"sources":["../../src/pool/driver.ts"],"sourcesContent":["import {\n mapDataInfo,\n isDataInfo,\n ensureError,\n PFrameDriverError,\n isAbortError,\n type LocalBlobHandleAndSize,\n type RemoteBlobHandleAndSize,\n type RemoteBlobHandle,\n type ContentHandler,\n type PColumnSpec,\n type PColumnDataUniversal,\n} from \"@platforma-sdk/model\";\nimport { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { emptyDir } from \"@milaboratories/ts-helpers\";\nimport { RefCountPoolBase, type PoolEntry, type MiLogger } from \"@milaboratories/helpers\";\nimport type { DownloadDriver } from \"@milaboratories/pl-drivers\";\nimport { isPlTreeNodeAccessor, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport type { Computable, ComputableStableDefined } from \"@milaboratories/computable\";\nimport {\n makeJsonDataInfo,\n AbstractPFrameDriver,\n AbstractPFrameDriverOpsDefaults,\n type AbstractInternalPFrameDriver,\n type AbstractPFrameDriverOps,\n type LocalBlobProvider,\n type RemoteBlobProvider,\n} from \"@milaboratories/pf-driver\";\nimport { HttpHelpers } from \"@milaboratories/pframes-rs-node\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport {\n BlobResourceRef,\n makeLocalBlobRef,\n parseDataInfoResource,\n traverseParquetChunkResource,\n} from \"./data\";\nimport { isDownloadNetworkError400 } from \"@milaboratories/pl-drivers\";\nimport { parseSignedResourceId } from \"@milaboratories/pl-client\";\n\nfunction makeBlobId(res: BlobResourceRef): PFrameInternal.PFrameBlobId {\n const { globalId } = parseSignedResourceId(res.resourceInfo.id);\n return String(globalId) as PFrameInternal.PFrameBlobId;\n}\n\ntype LocalBlob = ComputableStableDefined<LocalBlobHandleAndSize>;\nclass LocalBlobProviderImpl\n extends RefCountPoolBase<BlobResourceRef, PFrameInternal.PFrameBlobId, LocalBlob>\n implements LocalBlobProvider<BlobResourceRef>\n{\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): LocalBlob {\n return this.blobDriver.getDownloadedBlob(params.resourceInfo);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): LocalBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Local blob with id ${blobId} not found.`);\n return resource;\n }\n\n public makeDataSource(\n signal: AbortSignal,\n ): Omit<PFrameInternal.PFrameDataSourceV2, \"parquetServer\"> {\n return {\n preloadBlob: async (blobIds: PFrameInternal.PFrameBlobId[]) => {\n try {\n await Promise.all(\n blobIds.map((blobId) => this.getByKey(blobId).awaitStableFullValue(signal)),\n );\n } catch (err: unknown) {\n if (!isAbortError(err)) throw err;\n }\n },\n resolveBlobContent: async (blobId: PFrameInternal.PFrameBlobId) => {\n const computable = this.getByKey(blobId);\n const blob = await computable.awaitStableValue(signal);\n return await this.blobDriver.getContentDirect(blob.handle, { signal });\n },\n };\n }\n}\n\ntype RemoteBlob = Computable<RemoteBlobHandleAndSize>;\nclass RemoteBlobPool extends RefCountPoolBase<\n BlobResourceRef,\n PFrameInternal.PFrameBlobId,\n RemoteBlob\n> {\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(\n params: BlobResourceRef,\n _key: PFrameInternal.PFrameBlobId,\n ): RemoteBlob {\n if (params.onDemandSnapshot === undefined) {\n throw new PFrameDriverError(\n `BlobResourceRef for rid ${params.toJSON()} is missing the on-demand snapshot; ` +\n `remote (parquet) blobs must be captured via makeRemoteBlobRef.`,\n );\n }\n return this.blobDriver.getOnDemandBlob(params.onDemandSnapshot);\n }\n\n public getByKey(blobId: PFrameInternal.PFrameBlobId): RemoteBlob {\n const resource = super.tryGetByKey(blobId);\n if (!resource) throw new PFrameDriverError(`Remote blob with id ${blobId} not found.`);\n return resource;\n }\n\n public async withContent<T>(\n handle: RemoteBlobHandle,\n options: {\n range: PFrameInternal.FileRange;\n signal: AbortSignal;\n handler: ContentHandler<T>;\n },\n ): Promise<T> {\n return await this.blobDriver.withContent(handle, {\n range: {\n from: options.range.start,\n to: options.range.end + 1,\n },\n signal: options.signal,\n handler: options.handler,\n });\n }\n}\n\ninterface BlobStoreOptions extends PFrameInternal.ObjectStoreOptions {\n remoteBlobProvider: RemoteBlobPool;\n}\n\nclass BlobStore extends PFrameInternal.BaseObjectStore {\n private readonly remoteBlobProvider: RemoteBlobPool;\n\n constructor(options: BlobStoreOptions) {\n super(options);\n this.remoteBlobProvider = options.remoteBlobProvider;\n }\n\n public override async request(\n filename: PFrameInternal.ParquetFileName,\n params: {\n method: PFrameInternal.HttpMethod;\n range?: PFrameInternal.HttpRange;\n signal: AbortSignal;\n callback: (response: PFrameInternal.ObjectStoreResponse) => Promise<void>;\n },\n ): Promise<void> {\n const blobId = filename.slice(\n 0,\n -PFrameInternal.ParquetExtension.length,\n ) as PFrameInternal.PFrameBlobId;\n const respond = async (response: PFrameInternal.ObjectStoreResponse): Promise<void> => {\n try {\n await params.callback(response);\n } catch (error: unknown) {\n this.logger(\n \"warn\",\n `PFrames blob store received unhandled rejection from HTTP handler: ${ensureError(error)}`,\n );\n }\n };\n\n try {\n const computable = this.remoteBlobProvider.tryGetByKey(blobId);\n if (!computable) return await respond({ type: \"NotFound\" });\n\n let blob: RemoteBlobHandleAndSize;\n try {\n blob = await computable.getValue();\n } catch (error: unknown) {\n this.logger(\n \"error\",\n `PFrames blob store failed to get blob from computable: ${ensureError(error)}`,\n );\n return await respond({ type: \"InternalError\" });\n }\n params.signal.throwIfAborted();\n\n const translatedRange = this.translate(blob.size, params.range);\n if (!translatedRange) {\n return await respond({\n type: \"RangeNotSatisfiable\",\n size: blob.size,\n });\n }\n\n if (params.method === \"HEAD\") {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n });\n }\n\n this.logger(\n \"info\",\n `PFrames blob store requesting content for ${blobId}, ` +\n `range [${translatedRange.start}..=${translatedRange.end}]`,\n );\n return await this.remoteBlobProvider.withContent(blob.handle, {\n range: translatedRange,\n signal: params.signal,\n handler: async (data) => {\n return await respond({\n type: \"Ok\",\n size: blob.size,\n range: translatedRange,\n data: Readable.fromWeb(data),\n });\n },\n });\n } catch (error: unknown) {\n if (!isAbortError(error)) {\n if (isDownloadNetworkError400(error) && error.statusCode === 404) {\n this.logger(\"info\", `PFrames blob store known race error: ${ensureError(error)}`);\n } else {\n this.logger(\"warn\", `PFrames blob store unhandled error: ${ensureError(error)}`);\n }\n }\n return await respond({ type: \"InternalError\" });\n }\n }\n}\n\nclass RemoteBlobProviderImpl implements RemoteBlobProvider<BlobResourceRef> {\n constructor(\n private readonly pool: RemoteBlobPool,\n private readonly server: PFrameInternal.HttpServer,\n private readonly cache: PFrameInternal.CachingObjectStore,\n ) {}\n\n public static async init(\n blobDriver: DownloadDriver,\n logger: PFrameInternal.Logger,\n serverOptions: Omit<PFrameInternal.HttpServerOptions, \"handler\">,\n cacheConfig: PFrameInternal.CacheConfig,\n ): Promise<RemoteBlobProviderImpl> {\n const pool = new RemoteBlobPool(blobDriver, logger);\n const store = new BlobStore({ remoteBlobProvider: pool, logger });\n const cachingStore = await HttpHelpers.createCachingObjectStore({\n upstream: store,\n config: cacheConfig,\n logger,\n });\n\n const handler = HttpHelpers.createRequestHandler({ store: cachingStore });\n const server = await HttpHelpers.createHttpServer({ ...serverOptions, handler });\n logger(\"info\", `PFrames HTTP server started on ${server.info.url}`);\n\n return new RemoteBlobProviderImpl(pool, server, cachingStore);\n }\n\n public acquire(params: BlobResourceRef): PoolEntry<PFrameInternal.PFrameBlobId> {\n return this.pool.acquire(params);\n }\n\n public httpServerInfo(): PFrameInternal.HttpServerInfo {\n return this.server.info;\n }\n\n public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {\n return this.cache.getMetrics();\n }\n\n public async resetCache(): Promise<void> {\n await this.cache.reset();\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\n await this.cache[Symbol.asyncDispose]();\n await this.pool[Symbol.asyncDispose]();\n }\n}\n\nexport interface InternalPFrameDriver extends AbstractInternalPFrameDriver<\n PColumnDataUniversal<PlTreeNodeAccessor>\n> {}\n\nexport type PFrameDriverOps = AbstractPFrameDriverOps & {\n /** Port to run parquet HTTP server on. */\n parquetServerPort: number;\n};\n\nexport const PFrameDriverOpsDefaults: PFrameDriverOps = {\n ...AbstractPFrameDriverOpsDefaults,\n parquetServerPort: 0, // 0 means that some unused port will be assigned by the OS\n};\n\n/**\n * Tuning for the persistent parquet blob cache, minus its filesystem path (which\n * is supplied separately - see {@link createPFrameDriver}'s `cachePath`). Carries\n * only the size/eviction knobs of {@link PFrameInternal.CacheConfig}.\n */\nexport type ParquetCacheOps = Omit<PFrameInternal.CacheConfig, \"cachePath\">;\n\nexport async function createPFrameDriver(params: {\n blobDriver: DownloadDriver;\n logger: MiLogger;\n spillPath: string;\n cachePath: string;\n options: PFrameDriverOps;\n cacheOps: ParquetCacheOps;\n}): Promise<InternalPFrameDriver> {\n const resolvedSpillPath = path.resolve(params.spillPath);\n await emptyDir(resolvedSpillPath);\n\n const logger: PFrameInternal.Logger = (level, message) => params.logger[level](message);\n const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);\n const remoteBlobProvider = await RemoteBlobProviderImpl.init(\n params.blobDriver,\n logger,\n { port: params.options.parquetServerPort },\n { cachePath: path.resolve(params.cachePath), ...params.cacheOps },\n );\n\n const resolveDataInfo = (spec: PColumnSpec, data: PColumnDataUniversal<PlTreeNodeAccessor>) => {\n if (isPlTreeNodeAccessor(data)) {\n return parseDataInfoResource(data) ?? makeJsonDataInfo(spec, []);\n }\n\n return isDataInfo(data)\n ? data.type === \"ParquetPartitioned\"\n ? mapDataInfo(data, (a) => traverseParquetChunkResource(a))\n : mapDataInfo(data, (a) => makeLocalBlobRef(a))\n : makeJsonDataInfo(spec, data);\n };\n\n return new AbstractPFrameDriver({\n logger,\n localBlobProvider,\n remoteBlobProvider,\n spillPath: resolvedSpillPath,\n options: params.options,\n resolveDataInfo,\n });\n}\n"],"mappings":"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"}
|
package/dist/pool/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import { InternalPFrameDriver, PFrameDriverOps } from "./driver.js";
|
|
1
|
+
import { InternalPFrameDriver, PFrameDriverOps, ParquetCacheOps } from "./driver.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-middle-layer",
|
|
3
|
-
"version": "1.64.
|
|
3
|
+
"version": "1.64.29",
|
|
4
4
|
"description": "Pl Middle Layer",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@milaboratories/pframes-rs-node": "1.1.
|
|
23
|
-
"@milaboratories/pframes-rs-wasm": "1.1.
|
|
22
|
+
"@milaboratories/pframes-rs-node": "1.1.50",
|
|
23
|
+
"@milaboratories/pframes-rs-wasm": "1.1.50",
|
|
24
24
|
"canonicalize": "~2.1.0",
|
|
25
25
|
"denque": "^2.1.0",
|
|
26
26
|
"es-toolkit": "^1.39.10",
|
|
@@ -32,22 +32,22 @@
|
|
|
32
32
|
"yaml": "^2.8.0",
|
|
33
33
|
"zod": "~3.25.76",
|
|
34
34
|
"@milaboratories/computable": "2.9.5",
|
|
35
|
+
"@milaboratories/pf-spec-driver": "1.4.13",
|
|
35
36
|
"@milaboratories/helpers": "1.14.2",
|
|
37
|
+
"@milaboratories/pf-driver": "1.7.11",
|
|
36
38
|
"@milaboratories/pl-client": "3.11.4",
|
|
37
|
-
"@milaboratories/pf-spec-driver": "1.4.12",
|
|
38
|
-
"@milaboratories/pf-driver": "1.7.10",
|
|
39
|
-
"@milaboratories/pl-drivers": "1.15.6",
|
|
40
|
-
"@milaboratories/pl-http": "1.2.4",
|
|
41
|
-
"@milaboratories/pl-errors": "1.4.22",
|
|
42
39
|
"@milaboratories/pl-deployments": "3.0.7",
|
|
43
|
-
"@milaboratories/pl-
|
|
44
|
-
"@milaboratories/
|
|
40
|
+
"@milaboratories/pl-drivers": "1.16.0",
|
|
41
|
+
"@milaboratories/pl-errors": "1.4.22",
|
|
45
42
|
"@milaboratories/pl-model-common": "1.46.1",
|
|
43
|
+
"@milaboratories/pl-http": "1.2.4",
|
|
46
44
|
"@milaboratories/pl-model-middle-layer": "1.30.6",
|
|
45
|
+
"@milaboratories/pl-model-backend": "1.4.7",
|
|
47
46
|
"@milaboratories/pl-tree": "1.12.12",
|
|
47
|
+
"@milaboratories/ts-helpers": "1.8.3",
|
|
48
48
|
"@milaboratories/resolve-helper": "1.1.3",
|
|
49
49
|
"@platforma-sdk/block-tools": "2.10.19",
|
|
50
|
-
"@platforma-sdk/workflow-tengo": "6.6.
|
|
50
|
+
"@platforma-sdk/workflow-tengo": "6.6.2",
|
|
51
51
|
"@platforma-sdk/model": "1.79.6"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"typescript": "~5.9.3",
|
|
58
58
|
"vitest": "^4.1.3",
|
|
59
59
|
"@milaboratories/build-configs": "2.0.0",
|
|
60
|
-
"@milaboratories/ts-
|
|
61
|
-
"@milaboratories/ts-
|
|
60
|
+
"@milaboratories/ts-configs": "1.2.3",
|
|
61
|
+
"@milaboratories/ts-builder": "1.5.2"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=22.19.0"
|
|
@@ -118,7 +118,9 @@ export async function initDriverKit(
|
|
|
118
118
|
blobDriver,
|
|
119
119
|
logger: ops.logger,
|
|
120
120
|
spillPath: ops.pframesSpillPath,
|
|
121
|
+
cachePath: ops.parquetCachePath,
|
|
121
122
|
options: ops.pFrameDriverOps,
|
|
123
|
+
cacheOps: ops.parquetCacheOps,
|
|
122
124
|
});
|
|
123
125
|
|
|
124
126
|
const frontendDownloadDriver = new DownloadUrlDriver(
|
package/src/middle_layer/ops.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type { MiLogger } from "@milaboratories/ts-helpers";
|
|
|
12
12
|
import { ConsoleLoggerAdapter } from "@milaboratories/ts-helpers";
|
|
13
13
|
import type { LocalStorageProjection } from "@milaboratories/pl-drivers";
|
|
14
14
|
import path from "node:path";
|
|
15
|
-
import { PFrameDriverOpsDefaults, type PFrameDriverOps } from "../pool";
|
|
15
|
+
import { PFrameDriverOpsDefaults, type PFrameDriverOps, type ParquetCacheOps } from "../pool";
|
|
16
16
|
|
|
17
17
|
/** Paths part of {@link DriverKitOps}. */
|
|
18
18
|
export type DriverKitOpsPaths = {
|
|
@@ -47,6 +47,13 @@ export type DriverKitOpsPaths = {
|
|
|
47
47
|
|
|
48
48
|
/** Path to the directory where pframes will spill temporary files and store materialized views */
|
|
49
49
|
readonly pframesSpillPath: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Path to the directory backing the persistent parquet blob cache. Unlike
|
|
53
|
+
* {@link pframesSpillPath} this directory is NOT emptied on startup - the cache
|
|
54
|
+
* (and its lifetime counters) is meant to survive restarts.
|
|
55
|
+
*/
|
|
56
|
+
readonly parquetCachePath: string;
|
|
50
57
|
};
|
|
51
58
|
|
|
52
59
|
/** Options required to initialize full set of middle layer driver kit */
|
|
@@ -127,6 +134,13 @@ export type DriverKitOpsSettings = {
|
|
|
127
134
|
|
|
128
135
|
/** Settings related to the PFrame driver */
|
|
129
136
|
readonly pFrameDriverOps: PFrameDriverOps;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Tuning for the persistent parquet blob cache. Its directory is
|
|
140
|
+
* {@link DriverKitOpsPaths.parquetCachePath}; this carries only the
|
|
141
|
+
* size/eviction knobs.
|
|
142
|
+
*/
|
|
143
|
+
readonly parquetCacheOps: ParquetCacheOps;
|
|
130
144
|
};
|
|
131
145
|
|
|
132
146
|
export type DriverKitOps = DriverKitOpsPaths & DriverKitOpsSettings;
|
|
@@ -141,6 +155,7 @@ export const DefaultDriverKitOpsSettings: Pick<
|
|
|
141
155
|
| "uploadDriverOps"
|
|
142
156
|
| "logStreamDriverOps"
|
|
143
157
|
| "pFrameDriverOps"
|
|
158
|
+
| "parquetCacheOps"
|
|
144
159
|
> = {
|
|
145
160
|
logger: new ConsoleLoggerAdapter(),
|
|
146
161
|
blobDriverOps: {
|
|
@@ -169,19 +184,29 @@ export const DefaultDriverKitOpsSettings: Pick<
|
|
|
169
184
|
stopPollingDelay: 1000,
|
|
170
185
|
},
|
|
171
186
|
pFrameDriverOps: PFrameDriverOpsDefaults,
|
|
187
|
+
parquetCacheOps: {
|
|
188
|
+
maxSizeBytes: 8 * 1024 * 1024 * 1024, // 8 GB
|
|
189
|
+
admissionFraction: 0.2, // a single file may occupy at most 20% of the budget
|
|
190
|
+
maxFilesTracked: 50_000, // ghost (previously-evicted) files remembered to guide readmission
|
|
191
|
+
},
|
|
172
192
|
};
|
|
173
193
|
|
|
174
194
|
export function DefaultDriverKitOpsPaths(
|
|
175
195
|
workDir: string,
|
|
176
196
|
): Pick<
|
|
177
197
|
DriverKitOpsPaths,
|
|
178
|
-
|
|
198
|
+
| "blobDownloadPath"
|
|
199
|
+
| "blobDownloadRangesCachePath"
|
|
200
|
+
| "downloadBlobToURLPath"
|
|
201
|
+
| "pframesSpillPath"
|
|
202
|
+
| "parquetCachePath"
|
|
179
203
|
> {
|
|
180
204
|
return {
|
|
181
205
|
blobDownloadPath: path.join(workDir, "download"),
|
|
182
206
|
blobDownloadRangesCachePath: path.join(workDir, "downloadRangesCache"),
|
|
183
207
|
downloadBlobToURLPath: path.join(workDir, "downloadToURL"),
|
|
184
208
|
pframesSpillPath: path.join(workDir, "pframes"),
|
|
209
|
+
parquetCachePath: path.join(workDir, "parquetCache"),
|
|
185
210
|
};
|
|
186
211
|
}
|
|
187
212
|
|
package/src/pool/driver.ts
CHANGED
|
@@ -88,7 +88,7 @@ class LocalBlobProviderImpl
|
|
|
88
88
|
resolveBlobContent: async (blobId: PFrameInternal.PFrameBlobId) => {
|
|
89
89
|
const computable = this.getByKey(blobId);
|
|
90
90
|
const blob = await computable.awaitStableValue(signal);
|
|
91
|
-
return await this.blobDriver.
|
|
91
|
+
return await this.blobDriver.getContentDirect(blob.handle, { signal });
|
|
92
92
|
},
|
|
93
93
|
};
|
|
94
94
|
}
|
|
@@ -251,23 +251,28 @@ class RemoteBlobProviderImpl implements RemoteBlobProvider<BlobResourceRef> {
|
|
|
251
251
|
constructor(
|
|
252
252
|
private readonly pool: RemoteBlobPool,
|
|
253
253
|
private readonly server: PFrameInternal.HttpServer,
|
|
254
|
-
|
|
254
|
+
private readonly cache: PFrameInternal.CachingObjectStore,
|
|
255
255
|
) {}
|
|
256
256
|
|
|
257
257
|
public static async init(
|
|
258
258
|
blobDriver: DownloadDriver,
|
|
259
259
|
logger: PFrameInternal.Logger,
|
|
260
260
|
serverOptions: Omit<PFrameInternal.HttpServerOptions, "handler">,
|
|
261
|
+
cacheConfig: PFrameInternal.CacheConfig,
|
|
261
262
|
): Promise<RemoteBlobProviderImpl> {
|
|
262
263
|
const pool = new RemoteBlobPool(blobDriver, logger);
|
|
263
264
|
const store = new BlobStore({ remoteBlobProvider: pool, logger });
|
|
264
|
-
|
|
265
|
+
const cachingStore = await HttpHelpers.createCachingObjectStore({
|
|
266
|
+
upstream: store,
|
|
267
|
+
config: cacheConfig,
|
|
268
|
+
logger,
|
|
269
|
+
});
|
|
265
270
|
|
|
266
|
-
const handler = HttpHelpers.createRequestHandler({ store });
|
|
271
|
+
const handler = HttpHelpers.createRequestHandler({ store: cachingStore });
|
|
267
272
|
const server = await HttpHelpers.createHttpServer({ ...serverOptions, handler });
|
|
268
273
|
logger("info", `PFrames HTTP server started on ${server.info.url}`);
|
|
269
274
|
|
|
270
|
-
return new RemoteBlobProviderImpl(pool, server);
|
|
275
|
+
return new RemoteBlobProviderImpl(pool, server, cachingStore);
|
|
271
276
|
}
|
|
272
277
|
|
|
273
278
|
public acquire(params: BlobResourceRef): PoolEntry<PFrameInternal.PFrameBlobId> {
|
|
@@ -279,16 +284,16 @@ class RemoteBlobProviderImpl implements RemoteBlobProvider<BlobResourceRef> {
|
|
|
279
284
|
}
|
|
280
285
|
|
|
281
286
|
public async getCacheMetrics(): Promise<PFrameInternal.CacheMetrics | null> {
|
|
282
|
-
return
|
|
287
|
+
return this.cache.getMetrics();
|
|
283
288
|
}
|
|
284
289
|
|
|
285
290
|
public async resetCache(): Promise<void> {
|
|
286
|
-
|
|
291
|
+
await this.cache.reset();
|
|
287
292
|
}
|
|
288
293
|
|
|
289
294
|
async [Symbol.asyncDispose](): Promise<void> {
|
|
290
295
|
await this.server.stop();
|
|
291
|
-
|
|
296
|
+
await this.cache[Symbol.asyncDispose]();
|
|
292
297
|
await this.pool[Symbol.asyncDispose]();
|
|
293
298
|
}
|
|
294
299
|
}
|
|
@@ -307,20 +312,32 @@ export const PFrameDriverOpsDefaults: PFrameDriverOps = {
|
|
|
307
312
|
parquetServerPort: 0, // 0 means that some unused port will be assigned by the OS
|
|
308
313
|
};
|
|
309
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Tuning for the persistent parquet blob cache, minus its filesystem path (which
|
|
317
|
+
* is supplied separately - see {@link createPFrameDriver}'s `cachePath`). Carries
|
|
318
|
+
* only the size/eviction knobs of {@link PFrameInternal.CacheConfig}.
|
|
319
|
+
*/
|
|
320
|
+
export type ParquetCacheOps = Omit<PFrameInternal.CacheConfig, "cachePath">;
|
|
321
|
+
|
|
310
322
|
export async function createPFrameDriver(params: {
|
|
311
323
|
blobDriver: DownloadDriver;
|
|
312
324
|
logger: MiLogger;
|
|
313
325
|
spillPath: string;
|
|
326
|
+
cachePath: string;
|
|
314
327
|
options: PFrameDriverOps;
|
|
328
|
+
cacheOps: ParquetCacheOps;
|
|
315
329
|
}): Promise<InternalPFrameDriver> {
|
|
316
330
|
const resolvedSpillPath = path.resolve(params.spillPath);
|
|
317
331
|
await emptyDir(resolvedSpillPath);
|
|
318
332
|
|
|
319
333
|
const logger: PFrameInternal.Logger = (level, message) => params.logger[level](message);
|
|
320
334
|
const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);
|
|
321
|
-
const remoteBlobProvider = await RemoteBlobProviderImpl.init(
|
|
322
|
-
|
|
323
|
-
|
|
335
|
+
const remoteBlobProvider = await RemoteBlobProviderImpl.init(
|
|
336
|
+
params.blobDriver,
|
|
337
|
+
logger,
|
|
338
|
+
{ port: params.options.parquetServerPort },
|
|
339
|
+
{ cachePath: path.resolve(params.cachePath), ...params.cacheOps },
|
|
340
|
+
);
|
|
324
341
|
|
|
325
342
|
const resolveDataInfo = (spec: PColumnSpec, data: PColumnDataUniversal<PlTreeNodeAccessor>) => {
|
|
326
343
|
if (isPlTreeNodeAccessor(data)) {
|