@milaboratories/pl-middle-layer 1.58.0 → 1.58.2
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 +1 -1
- package/dist/middle_layer/driver_kit.d.ts +1 -1
- package/dist/middle_layer/driver_kit.js +1 -1
- package/dist/middle_layer/middle_layer.d.ts +1 -1
- package/dist/pool/data.cjs +45 -14
- package/dist/pool/data.cjs.map +1 -1
- package/dist/pool/data.d.ts +2 -0
- package/dist/pool/data.d.ts.map +1 -1
- package/dist/pool/data.js +46 -16
- package/dist/pool/data.js.map +1 -1
- package/dist/pool/driver.cjs +6 -5
- package/dist/pool/driver.cjs.map +1 -1
- package/dist/pool/driver.d.ts +1 -1
- package/dist/pool/driver.d.ts.map +1 -1
- package/dist/pool/driver.js +7 -6
- package/dist/pool/driver.js.map +1 -1
- package/package.json +11 -11
- package/src/pool/data.ts +68 -29
- package/src/pool/driver.ts +33 -20
|
@@ -3,8 +3,8 @@ const require_driver = require("../pool/driver.cjs");
|
|
|
3
3
|
require("../pool/index.cjs");
|
|
4
4
|
const require_ops = require("./ops.cjs");
|
|
5
5
|
let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
|
|
6
|
-
let _milaboratories_helpers = require("@milaboratories/helpers");
|
|
7
6
|
let _milaboratories_pl_drivers = require("@milaboratories/pl-drivers");
|
|
7
|
+
let _milaboratories_helpers = require("@milaboratories/helpers");
|
|
8
8
|
//#region src/middle_layer/driver_kit.ts
|
|
9
9
|
async function initDriverKit(pl, workdir, frontendDownloadPath, _ops) {
|
|
10
10
|
const ops = {
|
|
@@ -2,8 +2,8 @@ import { InternalPFrameDriver } from "../pool/driver.js";
|
|
|
2
2
|
import { DriverKitOpsConstructor } from "./ops.js";
|
|
3
3
|
import { Signer } from "@milaboratories/ts-helpers";
|
|
4
4
|
import { PlClient } from "@milaboratories/pl-client";
|
|
5
|
-
import * as Sdk from "@milaboratories/pl-model-common";
|
|
6
5
|
import { DownloadBlobToURLDriver, DownloadDriver, DownloadUrlDriver, InternalLsDriver, LogsDriver, UploadDriver } from "@milaboratories/pl-drivers";
|
|
6
|
+
import * as Sdk from "@milaboratories/pl-model-common";
|
|
7
7
|
|
|
8
8
|
//#region src/middle_layer/driver_kit.d.ts
|
|
9
9
|
/**
|
|
@@ -2,8 +2,8 @@ import { createPFrameDriver } from "../pool/driver.js";
|
|
|
2
2
|
import "../pool/index.js";
|
|
3
3
|
import { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings } from "./ops.js";
|
|
4
4
|
import { HmacSha256Signer } from "@milaboratories/ts-helpers";
|
|
5
|
-
import { isAsyncDisposable } from "@milaboratories/helpers";
|
|
6
5
|
import { DownloadBlobToURLDriver, DownloadDriver, DownloadUrlDriver, LogsDriver, LogsStreamDriver, LsDriver, UploadDriver, createDownloadClient, createLogsClient, createUploadBlobClient, createUploadProgressClient } from "@milaboratories/pl-drivers";
|
|
6
|
+
import { isAsyncDisposable } from "@milaboratories/helpers";
|
|
7
7
|
//#region src/middle_layer/driver_kit.ts
|
|
8
8
|
async function initDriverKit(pl, workdir, frontendDownloadPath, _ops) {
|
|
9
9
|
const ops = {
|
|
@@ -12,9 +12,9 @@ import { Dispatcher } from "undici";
|
|
|
12
12
|
import { BlockEventDispatcher, MiLogger, Signer } from "@milaboratories/ts-helpers";
|
|
13
13
|
import { PlClient, ResourceId } from "@milaboratories/pl-client";
|
|
14
14
|
import { ComputableStableDefined } from "@milaboratories/computable";
|
|
15
|
+
import { DownloadUrlDriver } from "@milaboratories/pl-drivers";
|
|
15
16
|
import { QuickJSWASMModule } from "quickjs-emscripten";
|
|
16
17
|
import { ModelServiceRegistry } from "@milaboratories/pl-model-common";
|
|
17
|
-
import { DownloadUrlDriver } from "@milaboratories/pl-drivers";
|
|
18
18
|
|
|
19
19
|
//#region src/middle_layer/middle_layer.d.ts
|
|
20
20
|
interface MiddleLayerEnvironment {
|
package/dist/pool/data.cjs
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
let _platforma_sdk_model = require("@platforma-sdk/model");
|
|
3
3
|
let _milaboratories_pl_client = require("@milaboratories/pl-client");
|
|
4
|
+
let _milaboratories_pl_tree = require("@milaboratories/pl-tree");
|
|
4
5
|
let node_crypto = require("node:crypto");
|
|
5
6
|
let canonicalize = require("canonicalize");
|
|
6
7
|
canonicalize = require_runtime.__toESM(canonicalize);
|
|
8
|
+
let _milaboratories_pl_drivers = require("@milaboratories/pl-drivers");
|
|
7
9
|
//#region src/pool/data.ts
|
|
10
|
+
/**
|
|
11
|
+
* Tree-independent reference to a blob resource used by the PFrame data flow.
|
|
12
|
+
*
|
|
13
|
+
* The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;
|
|
14
|
+
* resolution then went back through the originating tree, so when that tree dropped
|
|
15
|
+
* the resource (e.g., a project recalculated with new settings), shared pool entries
|
|
16
|
+
* — held alive by other projects — would start failing with "resource not found in
|
|
17
|
+
* the tree" even though the underlying blob was still valid backend-side.
|
|
18
|
+
*
|
|
19
|
+
* BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed
|
|
20
|
+
* to resolve. The pools then key by rid (`resourceInfo.id`) and call into the
|
|
21
|
+
* download driver with the snapshot directly — independent of any specific tree.
|
|
22
|
+
*/
|
|
23
|
+
var BlobResourceRef = class {
|
|
24
|
+
constructor(resourceInfo, onDemandSnapshot) {
|
|
25
|
+
this.resourceInfo = resourceInfo;
|
|
26
|
+
this.onDemandSnapshot = onDemandSnapshot;
|
|
27
|
+
}
|
|
28
|
+
toJSON() {
|
|
29
|
+
return (0, _milaboratories_pl_client.resourceIdToString)(this.resourceInfo.id);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function makeLocalBlobRef(accessor) {
|
|
33
|
+
return new BlobResourceRef(accessor.resourceInfo, void 0);
|
|
34
|
+
}
|
|
35
|
+
function makeRemoteBlobRef(accessor) {
|
|
36
|
+
return new BlobResourceRef(accessor.resourceInfo, (0, _milaboratories_pl_tree.makeResourceSnapshot)(accessor, _milaboratories_pl_drivers.OnDemandBlobResourceSnapshot));
|
|
37
|
+
}
|
|
8
38
|
const PColumnDataJsonPartitioned = (0, _milaboratories_pl_client.resourceType)("PColumnData/JsonPartitioned", "1");
|
|
9
39
|
const PColumnDataJsonSuperPartitioned = (0, _milaboratories_pl_client.resourceType)("PColumnData/Partitioned/JsonPartitioned", "1");
|
|
10
40
|
const PColumnDataBinaryPartitioned = (0, _milaboratories_pl_client.resourceType)("PColumnData/BinaryPartitioned", "1");
|
|
@@ -28,10 +58,10 @@ function parseDataInfoResource(data) {
|
|
|
28
58
|
};
|
|
29
59
|
} else if ((0, _milaboratories_pl_client.resourceTypesEqual)(data.resourceType, PColumnDataJsonPartitioned)) {
|
|
30
60
|
const meta = resourceData;
|
|
31
|
-
const parts = Object.fromEntries(data.listInputFields().map((field) => [field, data.traverse({
|
|
61
|
+
const parts = Object.fromEntries(data.listInputFields().map((field) => [field, makeLocalBlobRef(data.traverse({
|
|
32
62
|
field,
|
|
33
63
|
errorIfFieldNotSet: true
|
|
34
|
-
})
|
|
64
|
+
}))]));
|
|
35
65
|
return {
|
|
36
66
|
type: "JsonPartitioned",
|
|
37
67
|
partitionKeyLength: meta.partitionKeyLength,
|
|
@@ -49,10 +79,10 @@ function parseDataInfoResource(data) {
|
|
|
49
79
|
if (keys === void 0) throw new _platforma_sdk_model.PFrameDriverError(`no partition keys for super key ${superKey}`);
|
|
50
80
|
for (const key of keys) {
|
|
51
81
|
const partKey = JSON.stringify([...JSON.parse(superKey), ...JSON.parse(key)]);
|
|
52
|
-
parts[partKey] = superPart.traverse({
|
|
82
|
+
parts[partKey] = makeLocalBlobRef(superPart.traverse({
|
|
53
83
|
field: key,
|
|
54
84
|
errorIfFieldNotSet: true
|
|
55
|
-
})
|
|
85
|
+
}));
|
|
56
86
|
}
|
|
57
87
|
}
|
|
58
88
|
return {
|
|
@@ -70,10 +100,10 @@ function parseDataInfoResource(data) {
|
|
|
70
100
|
part = {};
|
|
71
101
|
parts[partKey] = part;
|
|
72
102
|
}
|
|
73
|
-
part.index = data.traverse({
|
|
103
|
+
part.index = makeLocalBlobRef(data.traverse({
|
|
74
104
|
field,
|
|
75
105
|
errorIfFieldNotSet: true
|
|
76
|
-
})
|
|
106
|
+
}));
|
|
77
107
|
} else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {
|
|
78
108
|
const partKey = field.slice(0, -7);
|
|
79
109
|
let part = parts[partKey];
|
|
@@ -81,10 +111,10 @@ function parseDataInfoResource(data) {
|
|
|
81
111
|
part = {};
|
|
82
112
|
parts[partKey] = part;
|
|
83
113
|
}
|
|
84
|
-
part.values = data.traverse({
|
|
114
|
+
part.values = makeLocalBlobRef(data.traverse({
|
|
85
115
|
field,
|
|
86
116
|
errorIfFieldNotSet: true
|
|
87
|
-
})
|
|
117
|
+
}));
|
|
88
118
|
} else throw new _platforma_sdk_model.PFrameDriverError(`unrecognized part field name: ${field}`);
|
|
89
119
|
for (const [key, part] of Object.entries(parts)) {
|
|
90
120
|
if (part.index === void 0) throw new _platforma_sdk_model.PFrameDriverError(`no index for part ${key}`);
|
|
@@ -113,10 +143,10 @@ function parseDataInfoResource(data) {
|
|
|
113
143
|
part = {};
|
|
114
144
|
parts[partKey] = part;
|
|
115
145
|
}
|
|
116
|
-
parts[partKey].index = superData.traverse({
|
|
146
|
+
parts[partKey].index = makeLocalBlobRef(superData.traverse({
|
|
117
147
|
field,
|
|
118
148
|
errorIfFieldNotSet: true
|
|
119
|
-
})
|
|
149
|
+
}));
|
|
120
150
|
} else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {
|
|
121
151
|
const key = field.slice(0, -7);
|
|
122
152
|
const partKey = JSON.stringify([...JSON.parse(superKey), ...JSON.parse(key)]);
|
|
@@ -125,10 +155,10 @@ function parseDataInfoResource(data) {
|
|
|
125
155
|
part = {};
|
|
126
156
|
parts[partKey] = part;
|
|
127
157
|
}
|
|
128
|
-
parts[partKey].values = superData.traverse({
|
|
158
|
+
parts[partKey].values = makeLocalBlobRef(superData.traverse({
|
|
129
159
|
field,
|
|
130
160
|
errorIfFieldNotSet: true
|
|
131
|
-
})
|
|
161
|
+
}));
|
|
132
162
|
} else throw new _platforma_sdk_model.PFrameDriverError(`unrecognized part field name: ${field}`);
|
|
133
163
|
}
|
|
134
164
|
return {
|
|
@@ -177,11 +207,11 @@ function parseDataInfoResource(data) {
|
|
|
177
207
|
}
|
|
178
208
|
function traverseParquetChunkResource(resource) {
|
|
179
209
|
if (!(0, _milaboratories_pl_client.resourceTypesEqual)(resource.resourceType, ParquetChunkResourceType)) throw new _platforma_sdk_model.PFrameDriverError(`unknown resource type: ${(0, _milaboratories_pl_client.resourceTypeToString)(resource.resourceType)}, expected: ${(0, _milaboratories_pl_client.resourceTypeToString)(ParquetChunkResourceType)}`);
|
|
180
|
-
const blob = resource.traverse({
|
|
210
|
+
const blob = makeRemoteBlobRef(resource.traverse({
|
|
181
211
|
field: "blob",
|
|
182
212
|
assertFieldType: "Service",
|
|
183
213
|
errorIfFieldNotSet: true
|
|
184
|
-
})
|
|
214
|
+
}));
|
|
185
215
|
const partInfo = resource.getDataAsJson();
|
|
186
216
|
const mapping = resource.traverse({
|
|
187
217
|
field: "mapping",
|
|
@@ -217,6 +247,7 @@ function deriveLocalPObjectId(resolvePath, outputName) {
|
|
|
217
247
|
exports.deriveGlobalPObjectId = deriveGlobalPObjectId;
|
|
218
248
|
exports.deriveLegacyPObjectId = deriveLegacyPObjectId;
|
|
219
249
|
exports.deriveLocalPObjectId = deriveLocalPObjectId;
|
|
250
|
+
exports.makeLocalBlobRef = makeLocalBlobRef;
|
|
220
251
|
exports.parseDataInfoResource = parseDataInfoResource;
|
|
221
252
|
exports.traverseParquetChunkResource = traverseParquetChunkResource;
|
|
222
253
|
|
package/dist/pool/data.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data.cjs","names":["PFrameDriverError"],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport type { PlTreeEntry, PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n isNullResourceId,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): PFrameInternal.DataInfo<PlTreeEntry> {\n if (!data.getIsReadyOrError()) throw new PFrameDriverError(\"Data not ready.\");\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [field, data.traverse({ field, errorIfFieldNotSet: true }).persist()]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, PlTreeEntry> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = superPart.traverse({ field: key, errorIfFieldNotSet: true }).persist();\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<PlTreeEntry>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = data.traverse({ field, errorIfFieldNotSet: true }).persist();\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = data.traverse({ field, errorIfFieldNotSet: true }).persist();\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<PlTreeEntry>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<PlTreeEntry>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = superData\n .traverse({\n field,\n errorIfFieldNotSet: true,\n })\n .persist();\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = superData\n .traverse({\n field,\n errorIfFieldNotSet: true,\n })\n .persist();\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<PlTreeEntry>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<PlTreeEntry>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<PlTreeEntry>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<PlTreeEntry> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = resource\n .traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .persist();\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n hash.update(String(!isNullResourceId(data.originalId) ? data.originalId : data.id));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data.cjs","names":["OnDemandBlobResourceSnapshot","PFrameDriverError"],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport { makeResourceSnapshot, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n isNullResourceId,\n resourceIdToString,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n type ResourceId,\n type ResourceType,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { OnDemandBlobResourceSnapshot } from \"@milaboratories/pl-drivers\";\n\n/**\n * Tree-independent reference to a blob resource used by the PFrame data flow.\n *\n * The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;\n * resolution then went back through the originating tree, so when that tree dropped\n * the resource (e.g., a project recalculated with new settings), shared pool entries\n * — held alive by other projects — would start failing with \"resource not found in\n * the tree\" even though the underlying blob was still valid backend-side.\n *\n * BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed\n * to resolve. The pools then key by rid (`resourceInfo.id`) and call into the\n * download driver with the snapshot directly — independent of any specific tree.\n */\nexport class BlobResourceRef {\n constructor(\n public readonly resourceInfo: { readonly id: ResourceId; readonly type: ResourceType },\n /** Present only for on-demand (remote) blobs; needed for size and signed handle. */\n public readonly onDemandSnapshot: OnDemandBlobResourceSnapshot | undefined,\n ) {}\n\n toJSON(): string {\n return resourceIdToString(this.resourceInfo.id);\n }\n}\n\nexport function makeLocalBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(accessor.resourceInfo, undefined);\n}\n\nfunction makeRemoteBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(\n accessor.resourceInfo,\n makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot),\n );\n}\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) throw new PFrameDriverError(\"Data not ready.\");\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [\n field,\n makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true })),\n ]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, BlobResourceRef> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = makeLocalBlobRef(\n superPart.traverse({ field: key, errorIfFieldNotSet: true }),\n );\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<BlobResourceRef> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = makeRemoteBlobRef(\n resource.traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true }),\n );\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n hash.update(String(!isNullResourceId(data.originalId) ? data.originalId : data.id));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":"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"}
|
package/dist/pool/data.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { PObjectId } from "@platforma-sdk/model";
|
|
2
2
|
import { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
3
|
+
import { ResourceId, ResourceType } from "@milaboratories/pl-client";
|
|
3
4
|
import { PlTreeNodeAccessor } from "@milaboratories/pl-tree";
|
|
5
|
+
import { OnDemandBlobResourceSnapshot } from "@milaboratories/pl-drivers";
|
|
4
6
|
|
|
5
7
|
//#region src/pool/data.d.ts
|
|
6
8
|
declare function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId;
|
package/dist/pool/data.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data.d.ts","names":[],"sources":["../../src/pool/data.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"data.d.ts","names":[],"sources":["../../src/pool/data.ts"],"mappings":";;;;;;;iBA0UgB,qBAAA,CAAsB,OAAA,UAAiB,UAAA,WAAqB,SAAA;AAAA,iBAI5D,oBAAA,CAAqB,WAAA,YAAuB,UAAA,WAAqB,SAAA"}
|
package/dist/pool/data.js
CHANGED
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
import { PFrameDriverError } from "@platforma-sdk/model";
|
|
2
|
-
import { isNullResourceId, resourceType, resourceTypeToString, resourceTypesEqual } from "@milaboratories/pl-client";
|
|
2
|
+
import { isNullResourceId, resourceIdToString, resourceType, resourceTypeToString, resourceTypesEqual } from "@milaboratories/pl-client";
|
|
3
|
+
import { makeResourceSnapshot } from "@milaboratories/pl-tree";
|
|
3
4
|
import { createHash } from "node:crypto";
|
|
4
5
|
import canonicalize from "canonicalize";
|
|
6
|
+
import { OnDemandBlobResourceSnapshot } from "@milaboratories/pl-drivers";
|
|
5
7
|
//#region src/pool/data.ts
|
|
8
|
+
/**
|
|
9
|
+
* Tree-independent reference to a blob resource used by the PFrame data flow.
|
|
10
|
+
*
|
|
11
|
+
* The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;
|
|
12
|
+
* resolution then went back through the originating tree, so when that tree dropped
|
|
13
|
+
* the resource (e.g., a project recalculated with new settings), shared pool entries
|
|
14
|
+
* — held alive by other projects — would start failing with "resource not found in
|
|
15
|
+
* the tree" even though the underlying blob was still valid backend-side.
|
|
16
|
+
*
|
|
17
|
+
* BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed
|
|
18
|
+
* to resolve. The pools then key by rid (`resourceInfo.id`) and call into the
|
|
19
|
+
* download driver with the snapshot directly — independent of any specific tree.
|
|
20
|
+
*/
|
|
21
|
+
var BlobResourceRef = class {
|
|
22
|
+
constructor(resourceInfo, onDemandSnapshot) {
|
|
23
|
+
this.resourceInfo = resourceInfo;
|
|
24
|
+
this.onDemandSnapshot = onDemandSnapshot;
|
|
25
|
+
}
|
|
26
|
+
toJSON() {
|
|
27
|
+
return resourceIdToString(this.resourceInfo.id);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
function makeLocalBlobRef(accessor) {
|
|
31
|
+
return new BlobResourceRef(accessor.resourceInfo, void 0);
|
|
32
|
+
}
|
|
33
|
+
function makeRemoteBlobRef(accessor) {
|
|
34
|
+
return new BlobResourceRef(accessor.resourceInfo, makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot));
|
|
35
|
+
}
|
|
6
36
|
const PColumnDataJsonPartitioned = resourceType("PColumnData/JsonPartitioned", "1");
|
|
7
37
|
const PColumnDataJsonSuperPartitioned = resourceType("PColumnData/Partitioned/JsonPartitioned", "1");
|
|
8
38
|
const PColumnDataBinaryPartitioned = resourceType("PColumnData/BinaryPartitioned", "1");
|
|
@@ -26,10 +56,10 @@ function parseDataInfoResource(data) {
|
|
|
26
56
|
};
|
|
27
57
|
} else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {
|
|
28
58
|
const meta = resourceData;
|
|
29
|
-
const parts = Object.fromEntries(data.listInputFields().map((field) => [field, data.traverse({
|
|
59
|
+
const parts = Object.fromEntries(data.listInputFields().map((field) => [field, makeLocalBlobRef(data.traverse({
|
|
30
60
|
field,
|
|
31
61
|
errorIfFieldNotSet: true
|
|
32
|
-
})
|
|
62
|
+
}))]));
|
|
33
63
|
return {
|
|
34
64
|
type: "JsonPartitioned",
|
|
35
65
|
partitionKeyLength: meta.partitionKeyLength,
|
|
@@ -47,10 +77,10 @@ function parseDataInfoResource(data) {
|
|
|
47
77
|
if (keys === void 0) throw new PFrameDriverError(`no partition keys for super key ${superKey}`);
|
|
48
78
|
for (const key of keys) {
|
|
49
79
|
const partKey = JSON.stringify([...JSON.parse(superKey), ...JSON.parse(key)]);
|
|
50
|
-
parts[partKey] = superPart.traverse({
|
|
80
|
+
parts[partKey] = makeLocalBlobRef(superPart.traverse({
|
|
51
81
|
field: key,
|
|
52
82
|
errorIfFieldNotSet: true
|
|
53
|
-
})
|
|
83
|
+
}));
|
|
54
84
|
}
|
|
55
85
|
}
|
|
56
86
|
return {
|
|
@@ -68,10 +98,10 @@ function parseDataInfoResource(data) {
|
|
|
68
98
|
part = {};
|
|
69
99
|
parts[partKey] = part;
|
|
70
100
|
}
|
|
71
|
-
part.index = data.traverse({
|
|
101
|
+
part.index = makeLocalBlobRef(data.traverse({
|
|
72
102
|
field,
|
|
73
103
|
errorIfFieldNotSet: true
|
|
74
|
-
})
|
|
104
|
+
}));
|
|
75
105
|
} else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {
|
|
76
106
|
const partKey = field.slice(0, -7);
|
|
77
107
|
let part = parts[partKey];
|
|
@@ -79,10 +109,10 @@ function parseDataInfoResource(data) {
|
|
|
79
109
|
part = {};
|
|
80
110
|
parts[partKey] = part;
|
|
81
111
|
}
|
|
82
|
-
part.values = data.traverse({
|
|
112
|
+
part.values = makeLocalBlobRef(data.traverse({
|
|
83
113
|
field,
|
|
84
114
|
errorIfFieldNotSet: true
|
|
85
|
-
})
|
|
115
|
+
}));
|
|
86
116
|
} else throw new PFrameDriverError(`unrecognized part field name: ${field}`);
|
|
87
117
|
for (const [key, part] of Object.entries(parts)) {
|
|
88
118
|
if (part.index === void 0) throw new PFrameDriverError(`no index for part ${key}`);
|
|
@@ -111,10 +141,10 @@ function parseDataInfoResource(data) {
|
|
|
111
141
|
part = {};
|
|
112
142
|
parts[partKey] = part;
|
|
113
143
|
}
|
|
114
|
-
parts[partKey].index = superData.traverse({
|
|
144
|
+
parts[partKey].index = makeLocalBlobRef(superData.traverse({
|
|
115
145
|
field,
|
|
116
146
|
errorIfFieldNotSet: true
|
|
117
|
-
})
|
|
147
|
+
}));
|
|
118
148
|
} else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {
|
|
119
149
|
const key = field.slice(0, -7);
|
|
120
150
|
const partKey = JSON.stringify([...JSON.parse(superKey), ...JSON.parse(key)]);
|
|
@@ -123,10 +153,10 @@ function parseDataInfoResource(data) {
|
|
|
123
153
|
part = {};
|
|
124
154
|
parts[partKey] = part;
|
|
125
155
|
}
|
|
126
|
-
parts[partKey].values = superData.traverse({
|
|
156
|
+
parts[partKey].values = makeLocalBlobRef(superData.traverse({
|
|
127
157
|
field,
|
|
128
158
|
errorIfFieldNotSet: true
|
|
129
|
-
})
|
|
159
|
+
}));
|
|
130
160
|
} else throw new PFrameDriverError(`unrecognized part field name: ${field}`);
|
|
131
161
|
}
|
|
132
162
|
return {
|
|
@@ -175,11 +205,11 @@ function parseDataInfoResource(data) {
|
|
|
175
205
|
}
|
|
176
206
|
function traverseParquetChunkResource(resource) {
|
|
177
207
|
if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) throw new PFrameDriverError(`unknown resource type: ${resourceTypeToString(resource.resourceType)}, expected: ${resourceTypeToString(ParquetChunkResourceType)}`);
|
|
178
|
-
const blob = resource.traverse({
|
|
208
|
+
const blob = makeRemoteBlobRef(resource.traverse({
|
|
179
209
|
field: "blob",
|
|
180
210
|
assertFieldType: "Service",
|
|
181
211
|
errorIfFieldNotSet: true
|
|
182
|
-
})
|
|
212
|
+
}));
|
|
183
213
|
const partInfo = resource.getDataAsJson();
|
|
184
214
|
const mapping = resource.traverse({
|
|
185
215
|
field: "mapping",
|
|
@@ -212,6 +242,6 @@ function deriveLocalPObjectId(resolvePath, outputName) {
|
|
|
212
242
|
});
|
|
213
243
|
}
|
|
214
244
|
//#endregion
|
|
215
|
-
export { deriveGlobalPObjectId, deriveLegacyPObjectId, deriveLocalPObjectId, parseDataInfoResource, traverseParquetChunkResource };
|
|
245
|
+
export { deriveGlobalPObjectId, deriveLegacyPObjectId, deriveLocalPObjectId, makeLocalBlobRef, parseDataInfoResource, traverseParquetChunkResource };
|
|
216
246
|
|
|
217
247
|
//# sourceMappingURL=data.js.map
|
package/dist/pool/data.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data.js","names":[],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport type { PlTreeEntry, PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n isNullResourceId,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): PFrameInternal.DataInfo<PlTreeEntry> {\n if (!data.getIsReadyOrError()) throw new PFrameDriverError(\"Data not ready.\");\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [field, data.traverse({ field, errorIfFieldNotSet: true }).persist()]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, PlTreeEntry> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = superPart.traverse({ field: key, errorIfFieldNotSet: true }).persist();\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<PlTreeEntry>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = data.traverse({ field, errorIfFieldNotSet: true }).persist();\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = data.traverse({ field, errorIfFieldNotSet: true }).persist();\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<PlTreeEntry>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<PlTreeEntry>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = superData\n .traverse({\n field,\n errorIfFieldNotSet: true,\n })\n .persist();\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = superData\n .traverse({\n field,\n errorIfFieldNotSet: true,\n })\n .persist();\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<PlTreeEntry>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<PlTreeEntry>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<PlTreeEntry>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<PlTreeEntry> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = resource\n .traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .persist();\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n hash.update(String(!isNullResourceId(data.originalId) ? data.originalId : data.id));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data.js","names":[],"sources":["../../src/pool/data.ts"],"sourcesContent":["import {\n PFrameDriverError,\n type BinaryChunk,\n type ParquetChunk,\n type ParquetChunkMapping,\n type ParquetChunkMetadata,\n type PColumnValue,\n type PlRef,\n type PObjectId,\n type PObjectSpec,\n} from \"@platforma-sdk/model\";\nimport { makeResourceSnapshot, type PlTreeNodeAccessor } from \"@milaboratories/pl-tree\";\nimport canonicalize from \"canonicalize\";\nimport {\n isNullResourceId,\n resourceIdToString,\n resourceType,\n resourceTypeToString,\n resourceTypesEqual,\n type ResourceId,\n type ResourceType,\n} from \"@milaboratories/pl-client\";\nimport type { Writable } from \"utility-types\";\nimport { createHash } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { OnDemandBlobResourceSnapshot } from \"@milaboratories/pl-drivers\";\n\n/**\n * Tree-independent reference to a blob resource used by the PFrame data flow.\n *\n * The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;\n * resolution then went back through the originating tree, so when that tree dropped\n * the resource (e.g., a project recalculated with new settings), shared pool entries\n * — held alive by other projects — would start failing with \"resource not found in\n * the tree\" even though the underlying blob was still valid backend-side.\n *\n * BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed\n * to resolve. The pools then key by rid (`resourceInfo.id`) and call into the\n * download driver with the snapshot directly — independent of any specific tree.\n */\nexport class BlobResourceRef {\n constructor(\n public readonly resourceInfo: { readonly id: ResourceId; readonly type: ResourceType },\n /** Present only for on-demand (remote) blobs; needed for size and signed handle. */\n public readonly onDemandSnapshot: OnDemandBlobResourceSnapshot | undefined,\n ) {}\n\n toJSON(): string {\n return resourceIdToString(this.resourceInfo.id);\n }\n}\n\nexport function makeLocalBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(accessor.resourceInfo, undefined);\n}\n\nfunction makeRemoteBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {\n return new BlobResourceRef(\n accessor.resourceInfo,\n makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot),\n );\n}\n\nexport const PColumnDataJsonPartitioned = resourceType(\"PColumnData/JsonPartitioned\", \"1\");\nexport const PColumnDataJsonSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/JsonPartitioned\",\n \"1\",\n);\nexport const PColumnDataBinaryPartitioned = resourceType(\"PColumnData/BinaryPartitioned\", \"1\");\nexport const PColumnDataBinarySuperPartitioned = resourceType(\n \"PColumnData/Partitioned/BinaryPartitioned\",\n \"1\",\n);\nexport const PColumnDataParquetPartitioned = resourceType(\"PColumnData/ParquetPartitioned\", \"1\");\nexport const PColumnDataParquetSuperPartitioned = resourceType(\n \"PColumnData/Partitioned/ParquetPartitioned\",\n \"1\",\n);\nexport const PColumnDataJson = resourceType(\"PColumnData/Json\", \"1\");\n\nexport const ParquetChunkResourceType = resourceType(\"ParquetChunk\", \"1\");\n\nexport type PColumnDataJsonResourceValue = {\n keyLength: number;\n data: Record<string, PColumnValue>;\n};\n\nexport type PColumnDataPartitionedResourceValue = {\n partitionKeyLength: number;\n};\n\nexport type PColumnDataSuperPartitionedResourceValue = {\n superPartitionKeyLength: number;\n partitionKeyLength: number;\n};\n\nconst BinaryPartitionedIndexFieldSuffix = \".index\";\nconst BinaryPartitionedValuesFieldSuffix = \".values\";\n\nexport function parseDataInfoResource(\n data: PlTreeNodeAccessor,\n): PFrameInternal.DataInfo<BlobResourceRef> {\n if (!data.getIsReadyOrError()) throw new PFrameDriverError(\"Data not ready.\");\n\n const resourceData = data.getDataAsJson();\n if (resourceData === undefined)\n throw new PFrameDriverError(\"unexpected data info structure, no resource data\");\n\n if (resourceTypesEqual(data.resourceType, PColumnDataJson)) {\n const dataContent = resourceData as PColumnDataJsonResourceValue;\n\n return {\n type: \"Json\",\n keyLength: dataContent.keyLength,\n data: dataContent.data,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts = Object.fromEntries(\n data\n .listInputFields()\n .map((field) => [\n field,\n makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true })),\n ]),\n );\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, BlobResourceRef> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = makeLocalBlobRef(\n superPart.traverse({ field: key, errorIfFieldNotSet: true }),\n );\n }\n }\n\n return {\n type: \"JsonPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n\n // parsing the structure\n for (const field of data.listInputFields()) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.index = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n part.values = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n\n // structure validation\n for (const [key, part] of Object.entries(parts)) {\n if (part.index === undefined) throw new PFrameDriverError(`no index for part ${key}`);\n if (part.values === undefined) throw new PFrameDriverError(`no values for part ${key}`);\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};\n for (const superKey of data.listInputFields()) {\n const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superData.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const field of keys) {\n if (field.endsWith(BinaryPartitionedIndexFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedIndexFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].index = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {\n const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n let part = parts[partKey];\n if (part === undefined) {\n part = {};\n parts[partKey] = part;\n }\n parts[partKey].values = makeLocalBlobRef(\n superData.traverse({ field, errorIfFieldNotSet: true }),\n );\n } else throw new PFrameDriverError(`unrecognized part field name: ${field}`);\n }\n }\n\n return {\n type: \"BinaryPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {\n const meta = resourceData as PColumnDataPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const key of data.listInputFields()) {\n const resource = data.traverse({\n field: key,\n assertFieldType: \"Input\",\n errorIfFieldNotSet: true,\n });\n\n parts[key] = traverseParquetChunkResource(resource);\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.partitionKeyLength,\n parts,\n };\n } else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {\n const meta = resourceData as PColumnDataSuperPartitionedResourceValue;\n\n const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};\n for (const superKey of data.listInputFields()) {\n const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });\n const keys = superPart.listInputFields();\n if (keys === undefined)\n throw new PFrameDriverError(`no partition keys for super key ${superKey}`);\n\n for (const key of keys) {\n const resource = data.traverse({ field: key, errorIfFieldNotSet: true });\n\n const partKey = JSON.stringify([\n ...(JSON.parse(superKey) as PColumnValue[]),\n ...(JSON.parse(key) as PColumnValue[]),\n ]);\n parts[partKey] = traverseParquetChunkResource(resource);\n }\n }\n\n return {\n type: \"ParquetPartitioned\",\n partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,\n parts,\n };\n }\n\n throw new PFrameDriverError(\n `unsupported resource type: ${resourceTypeToString(data.resourceType)}`,\n );\n}\n\nexport function traverseParquetChunkResource(\n resource: PlTreeNodeAccessor,\n): ParquetChunk<BlobResourceRef> {\n if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {\n throw new PFrameDriverError(\n `unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +\n `expected: ${resourceTypeToString(ParquetChunkResourceType)}`,\n );\n }\n\n const blob = makeRemoteBlobRef(\n resource.traverse({ field: \"blob\", assertFieldType: \"Service\", errorIfFieldNotSet: true }),\n );\n const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;\n const mapping = resource\n .traverse({ field: \"mapping\", assertFieldType: \"Service\", errorIfFieldNotSet: true })\n .getDataAsJson() as ParquetChunkMapping;\n\n return {\n data: blob,\n ...partInfo,\n ...mapping,\n };\n}\n\nexport function deriveLegacyPObjectId(spec: PObjectSpec, data: PlTreeNodeAccessor): PObjectId {\n const hash = createHash(\"sha256\");\n hash.update(canonicalize(spec)!);\n hash.update(String(!isNullResourceId(data.originalId) ? data.originalId : data.id));\n return hash.digest().toString(\"hex\") as PObjectId;\n}\n\nexport function deriveGlobalPObjectId(blockId: string, exportName: string): PObjectId {\n return canonicalize({ __isRef: true, blockId, name: exportName } satisfies PlRef)! as PObjectId;\n}\n\nexport function deriveLocalPObjectId(resolvePath: string[], outputName: string): PObjectId {\n return canonicalize({ resolvePath, name: outputName })! as PObjectId;\n}\n"],"mappings":"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"}
|
package/dist/pool/driver.cjs
CHANGED
|
@@ -6,14 +6,14 @@ let node_path = require("node:path");
|
|
|
6
6
|
node_path = require_runtime.__toESM(node_path);
|
|
7
7
|
let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
|
|
8
8
|
let _milaboratories_pl_tree = require("@milaboratories/pl-tree");
|
|
9
|
+
let _milaboratories_pl_drivers = require("@milaboratories/pl-drivers");
|
|
9
10
|
let _milaboratories_helpers = require("@milaboratories/helpers");
|
|
10
11
|
let _milaboratories_pf_driver = require("@milaboratories/pf-driver");
|
|
11
12
|
let _milaboratories_pframes_rs_node = require("@milaboratories/pframes-rs-node");
|
|
12
13
|
let node_stream = require("node:stream");
|
|
13
|
-
let _milaboratories_pl_drivers = require("@milaboratories/pl-drivers");
|
|
14
14
|
//#region src/pool/driver.ts
|
|
15
15
|
function makeBlobId(res) {
|
|
16
|
-
return String(res.
|
|
16
|
+
return String(res.resourceInfo.id);
|
|
17
17
|
}
|
|
18
18
|
var LocalBlobProviderImpl = class extends _milaboratories_helpers.RefCountPoolBase {
|
|
19
19
|
constructor(blobDriver, logger) {
|
|
@@ -25,7 +25,7 @@ var LocalBlobProviderImpl = class extends _milaboratories_helpers.RefCountPoolBa
|
|
|
25
25
|
return makeBlobId(params);
|
|
26
26
|
}
|
|
27
27
|
createNewResource(params, _key) {
|
|
28
|
-
return this.blobDriver.getDownloadedBlob(params);
|
|
28
|
+
return this.blobDriver.getDownloadedBlob(params.resourceInfo);
|
|
29
29
|
}
|
|
30
30
|
getByKey(blobId) {
|
|
31
31
|
const resource = super.tryGetByKey(blobId);
|
|
@@ -58,7 +58,8 @@ var RemoteBlobPool = class extends _milaboratories_helpers.RefCountPoolBase {
|
|
|
58
58
|
return makeBlobId(params);
|
|
59
59
|
}
|
|
60
60
|
createNewResource(params, _key) {
|
|
61
|
-
|
|
61
|
+
if (params.onDemandSnapshot === void 0) throw new _platforma_sdk_model.PFrameDriverError(`BlobResourceRef for rid ${params.toJSON()} is missing the on-demand snapshot; remote (parquet) blobs must be captured via makeRemoteBlobRef.`);
|
|
62
|
+
return this.blobDriver.getOnDemandBlob(params.onDemandSnapshot);
|
|
62
63
|
}
|
|
63
64
|
getByKey(blobId) {
|
|
64
65
|
const resource = super.tryGetByKey(blobId);
|
|
@@ -173,7 +174,7 @@ async function createPFrameDriver(params) {
|
|
|
173
174
|
const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);
|
|
174
175
|
const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, { port: params.options.parquetServerPort });
|
|
175
176
|
const resolveDataInfo = (spec, data) => {
|
|
176
|
-
return (0, _milaboratories_pl_tree.isPlTreeNodeAccessor)(data) ? require_data.parseDataInfoResource(data) : (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) =>
|
|
177
|
+
return (0, _milaboratories_pl_tree.isPlTreeNodeAccessor)(data) ? require_data.parseDataInfoResource(data) : (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);
|
|
177
178
|
};
|
|
178
179
|
return new _milaboratories_pf_driver.AbstractPFrameDriver({
|
|
179
180
|
logger,
|
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","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 {\n isPlTreeNodeAccessor,\n type PlTreeEntry,\n type PlTreeNodeAccessor,\n} 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 { parseDataInfoResource, traverseParquetChunkResource } from \"./data\";\nimport { isDownloadNetworkError400 } from \"@milaboratories/pl-drivers\";\n\nfunction makeBlobId(res: PlTreeEntry): PFrameInternal.PFrameBlobId {\n return String(res.rid) as PFrameInternal.PFrameBlobId;\n}\n\ntype LocalBlob = ComputableStableDefined<LocalBlobHandleAndSize>;\nclass LocalBlobProviderImpl\n extends RefCountPoolBase<PlTreeEntry, PFrameInternal.PFrameBlobId, LocalBlob>\n implements LocalBlobProvider<PlTreeEntry>\n{\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: PlTreeEntry): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(params: PlTreeEntry, _key: PFrameInternal.PFrameBlobId): LocalBlob {\n return this.blobDriver.getDownloadedBlob(params);\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 PlTreeEntry,\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: PlTreeEntry): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(params: PlTreeEntry, _key: PFrameInternal.PFrameBlobId): RemoteBlob {\n return this.blobDriver.getOnDemandBlob(params);\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<PlTreeEntry> {\n constructor(\n private readonly pool: RemoteBlobPool,\n private readonly server: PFrameInternal.HttpServer,\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\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: PlTreeEntry): PoolEntry<PFrameInternal.PFrameBlobId> {\n return this.pool.acquire(params);\n }\n\n public httpServerInfo(): PFrameInternal.HttpServerInfo {\n return this.server.info;\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\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 return isPlTreeNodeAccessor(data)\n ? parseDataInfoResource(data)\n : isDataInfo(data)\n ? data.type === \"ParquetPartitioned\"\n ? mapDataInfo(data, (a) => traverseParquetChunkResource(a))\n : mapDataInfo(data, (a) => a.persist())\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\";\n\nfunction makeBlobId(res: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return String(res.resourceInfo.id) 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 ) {}\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\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 async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\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 return isPlTreeNodeAccessor(data)\n ? parseDataInfoResource(data)\n : 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":";;;;;;;;;;;;;;AAuCA,SAAS,WAAW,KAAmD;AACrE,QAAO,OAAO,IAAI,aAAa,GAAG;;AAIpC,IAAM,wBAAN,cACUA,wBAAAA,iBAEV;CACE,YACE,YACA,QACA;AACA,SAAO;AAHU,OAAA,aAAA;AACA,OAAA,SAAA;;CAKnB,mBAA6B,QAAsD;AACjF,SAAO,WAAW,OAAO;;CAG3B,kBACE,QACA,MACW;AACX,SAAO,KAAK,WAAW,kBAAkB,OAAO,aAAa;;CAG/D,SAAgB,QAAgD;EAC9D,MAAM,WAAW,MAAM,YAAY,OAAO;AAC1C,MAAI,CAAC,SAAU,OAAM,IAAIC,qBAAAA,kBAAkB,sBAAsB,OAAO,aAAa;AACrF,SAAO;;CAGT,eACE,QAC0D;AAC1D,SAAO;GACL,aAAa,OAAO,YAA2C;AAC7D,QAAI;AACF,WAAM,QAAQ,IACZ,QAAQ,KAAK,WAAW,KAAK,SAAS,OAAO,CAAC,qBAAqB,OAAO,CAAC,CAC5E;aACM,KAAc;AACrB,SAAI,EAAA,GAAA,qBAAA,cAAc,IAAI,CAAE,OAAM;;;GAGlC,oBAAoB,OAAO,WAAwC;IAEjE,MAAM,OAAO,MADM,KAAK,SAAS,OAAO,CACV,iBAAiB,OAAO;AACtD,WAAO,MAAM,KAAK,WAAW,WAAW,KAAK,QAAQ,EAAE,QAAQ,CAAC;;GAEnE;;;AAKL,IAAM,iBAAN,cAA6BD,wBAAAA,iBAI3B;CACA,YACE,YACA,QACA;AACA,SAAO;AAHU,OAAA,aAAA;AACA,OAAA,SAAA;;CAKnB,mBAA6B,QAAsD;AACjF,SAAO,WAAW,OAAO;;CAG3B,kBACE,QACA,MACY;AACZ,MAAI,OAAO,qBAAqB,KAAA,EAC9B,OAAM,IAAIC,qBAAAA,kBACR,2BAA2B,OAAO,QAAQ,CAAC,oGAE5C;AAEH,SAAO,KAAK,WAAW,gBAAgB,OAAO,iBAAiB;;CAGjE,SAAgB,QAAiD;EAC/D,MAAM,WAAW,MAAM,YAAY,OAAO;AAC1C,MAAI,CAAC,SAAU,OAAM,IAAIA,qBAAAA,kBAAkB,uBAAuB,OAAO,aAAa;AACtF,SAAO;;CAGT,MAAa,YACX,QACA,SAKY;AACZ,SAAO,MAAM,KAAK,WAAW,YAAY,QAAQ;GAC/C,OAAO;IACL,MAAM,QAAQ,MAAM;IACpB,IAAI,QAAQ,MAAM,MAAM;IACzB;GACD,QAAQ,QAAQ;GAChB,SAAS,QAAQ;GAClB,CAAC;;;AAQN,IAAM,YAAN,cAAwBC,sCAAAA,eAAe,gBAAgB;CACrD;CAEA,YAAY,SAA2B;AACrC,QAAM,QAAQ;AACd,OAAK,qBAAqB,QAAQ;;CAGpC,MAAsB,QACpB,UACA,QAMe;EACf,MAAM,SAAS,SAAS,MACtB,GACA,CAACA,sCAAAA,eAAe,iBAAiB,OAClC;EACD,MAAM,UAAU,OAAO,aAAgE;AACrF,OAAI;AACF,UAAM,OAAO,SAAS,SAAS;YACxB,OAAgB;AACvB,SAAK,OACH,QACA,uEAAA,GAAA,qBAAA,aAAkF,MAAM,GACzF;;;AAIL,MAAI;GACF,MAAM,aAAa,KAAK,mBAAmB,YAAY,OAAO;AAC9D,OAAI,CAAC,WAAY,QAAO,MAAM,QAAQ,EAAE,MAAM,YAAY,CAAC;GAE3D,IAAI;AACJ,OAAI;AACF,WAAO,MAAM,WAAW,UAAU;YAC3B,OAAgB;AACvB,SAAK,OACH,SACA,2DAAA,GAAA,qBAAA,aAAsE,MAAM,GAC7E;AACD,WAAO,MAAM,QAAQ,EAAE,MAAM,iBAAiB,CAAC;;AAEjD,UAAO,OAAO,gBAAgB;GAE9B,MAAM,kBAAkB,KAAK,UAAU,KAAK,MAAM,OAAO,MAAM;AAC/D,OAAI,CAAC,gBACH,QAAO,MAAM,QAAQ;IACnB,MAAM;IACN,MAAM,KAAK;IACZ,CAAC;AAGJ,OAAI,OAAO,WAAW,OACpB,QAAO,MAAM,QAAQ;IACnB,MAAM;IACN,MAAM,KAAK;IACX,OAAO;IACR,CAAC;AAGJ,QAAK,OACH,QACA,6CAA6C,OAAO,WACxC,gBAAgB,MAAM,KAAK,gBAAgB,IAAI,GAC5D;AACD,UAAO,MAAM,KAAK,mBAAmB,YAAY,KAAK,QAAQ;IAC5D,OAAO;IACP,QAAQ,OAAO;IACf,SAAS,OAAO,SAAS;AACvB,YAAO,MAAM,QAAQ;MACnB,MAAM;MACN,MAAM,KAAK;MACX,OAAO;MACP,MAAMC,YAAAA,SAAS,QAAQ,KAAK;MAC7B,CAAC;;IAEL,CAAC;WACK,OAAgB;AACvB,OAAI,EAAA,GAAA,qBAAA,cAAc,MAAM,CACtB,MAAA,GAAA,2BAAA,2BAA8B,MAAM,IAAI,MAAM,eAAe,IAC3D,MAAK,OAAO,QAAQ,yCAAA,GAAA,qBAAA,aAAoD,MAAM,GAAG;OAEjF,MAAK,OAAO,QAAQ,wCAAA,GAAA,qBAAA,aAAmD,MAAM,GAAG;AAGpF,UAAO,MAAM,QAAQ,EAAE,MAAM,iBAAiB,CAAC;;;;AAKrD,IAAM,yBAAN,MAAM,uBAAsE;CAC1E,YACE,MACA,QACA;AAFiB,OAAA,OAAA;AACA,OAAA,SAAA;;CAGnB,aAAoB,KAClB,YACA,QACA,eACiC;EACjC,MAAM,OAAO,IAAI,eAAe,YAAY,OAAO;EACnD,MAAM,QAAQ,IAAI,UAAU;GAAE,oBAAoB;GAAM;GAAQ,CAAC;EAEjE,MAAM,UAAUC,gCAAAA,YAAY,qBAAqB,EAAE,OAAO,CAAC;EAC3D,MAAM,SAAS,MAAMA,gCAAAA,YAAY,iBAAiB;GAAE,GAAG;GAAe;GAAS,CAAC;AAChF,SAAO,QAAQ,kCAAkC,OAAO,KAAK,MAAM;AAEnE,SAAO,IAAI,uBAAuB,MAAM,OAAO;;CAGjD,QAAe,QAAiE;AAC9E,SAAO,KAAK,KAAK,QAAQ,OAAO;;CAGlC,iBAAuD;AACrD,SAAO,KAAK,OAAO;;CAGrB,OAAO,OAAO,gBAA+B;AAC3C,QAAM,KAAK,OAAO,MAAM;AACxB,QAAM,KAAK,KAAK,OAAO,eAAe;;;AAa1C,MAAa,0BAA2C;CACtD,GAAGC,0BAAAA;CACH,mBAAmB;CACpB;AAED,eAAsB,mBAAmB,QAKP;CAChC,MAAM,oBAAoBC,UAAAA,QAAK,QAAQ,OAAO,UAAU;AACxD,QAAA,GAAA,2BAAA,UAAe,kBAAkB;CAEjC,MAAM,UAAiC,OAAO,YAAY,OAAO,OAAO,OAAO,QAAQ;CACvF,MAAM,oBAAoB,IAAI,sBAAsB,OAAO,YAAY,OAAO;CAC9E,MAAM,qBAAqB,MAAM,uBAAuB,KAAK,OAAO,YAAY,QAAQ,EACtF,MAAM,OAAO,QAAQ,mBACtB,CAAC;CAEF,MAAM,mBAAmB,MAAmB,SAAmD;AAC7F,UAAA,GAAA,wBAAA,sBAA4B,KAAK,GAC7BC,aAAAA,sBAAsB,KAAK,IAAA,GAAA,qBAAA,YAChB,KAAK,GACd,KAAK,SAAS,wBAAA,GAAA,qBAAA,aACA,OAAO,MAAMC,aAAAA,6BAA6B,EAAE,CAAC,IAAA,GAAA,qBAAA,aAC7C,OAAO,MAAMC,aAAAA,iBAAiB,EAAE,CAAC,IAAA,GAAA,0BAAA,kBAC9B,MAAM,KAAK;;AAGpC,QAAO,IAAIC,0BAAAA,qBAAqB;EAC9B;EACA;EACA;EACA,WAAW;EACX,SAAS,OAAO;EAChB;EACD,CAAC"}
|
package/dist/pool/driver.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PColumnDataUniversal } from "@platforma-sdk/model";
|
|
2
2
|
import { PlTreeNodeAccessor } from "@milaboratories/pl-tree";
|
|
3
|
-
import { AbstractInternalPFrameDriver, AbstractPFrameDriverOps } from "@milaboratories/pf-driver";
|
|
4
3
|
import { DownloadDriver } from "@milaboratories/pl-drivers";
|
|
4
|
+
import { AbstractInternalPFrameDriver, AbstractPFrameDriverOps } from "@milaboratories/pf-driver";
|
|
5
5
|
|
|
6
6
|
//#region src/pool/driver.d.ts
|
|
7
7
|
interface InternalPFrameDriver extends AbstractInternalPFrameDriver<PColumnDataUniversal<PlTreeNodeAccessor>> {}
|
|
@@ -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":";;;;;;UA0RiB,oBAAA,SAA6B,4BAAA,CAC5C,oBAAA,CAAqB,kBAAA;AAAA,KAGX,eAAA,GAAkB,uBAAA;EAJQ,0CAMpC,iBAAA;AAAA"}
|
package/dist/pool/driver.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { parseDataInfoResource, traverseParquetChunkResource } from "./data.js";
|
|
1
|
+
import { makeLocalBlobRef, parseDataInfoResource, traverseParquetChunkResource } from "./data.js";
|
|
2
2
|
import { PFrameDriverError, ensureError, isAbortError, isDataInfo, mapDataInfo } from "@platforma-sdk/model";
|
|
3
3
|
import { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { emptyDir } from "@milaboratories/ts-helpers";
|
|
6
6
|
import { isPlTreeNodeAccessor } from "@milaboratories/pl-tree";
|
|
7
|
+
import { isDownloadNetworkError400 } from "@milaboratories/pl-drivers";
|
|
7
8
|
import { RefCountPoolBase } from "@milaboratories/helpers";
|
|
8
9
|
import { AbstractPFrameDriver, AbstractPFrameDriverOpsDefaults, makeJsonDataInfo } from "@milaboratories/pf-driver";
|
|
9
10
|
import { HttpHelpers } from "@milaboratories/pframes-rs-node";
|
|
10
11
|
import { Readable } from "node:stream";
|
|
11
|
-
import { isDownloadNetworkError400 } from "@milaboratories/pl-drivers";
|
|
12
12
|
//#region src/pool/driver.ts
|
|
13
13
|
function makeBlobId(res) {
|
|
14
|
-
return String(res.
|
|
14
|
+
return String(res.resourceInfo.id);
|
|
15
15
|
}
|
|
16
16
|
var LocalBlobProviderImpl = class extends RefCountPoolBase {
|
|
17
17
|
constructor(blobDriver, logger) {
|
|
@@ -23,7 +23,7 @@ var LocalBlobProviderImpl = class extends RefCountPoolBase {
|
|
|
23
23
|
return makeBlobId(params);
|
|
24
24
|
}
|
|
25
25
|
createNewResource(params, _key) {
|
|
26
|
-
return this.blobDriver.getDownloadedBlob(params);
|
|
26
|
+
return this.blobDriver.getDownloadedBlob(params.resourceInfo);
|
|
27
27
|
}
|
|
28
28
|
getByKey(blobId) {
|
|
29
29
|
const resource = super.tryGetByKey(blobId);
|
|
@@ -56,7 +56,8 @@ var RemoteBlobPool = class extends RefCountPoolBase {
|
|
|
56
56
|
return makeBlobId(params);
|
|
57
57
|
}
|
|
58
58
|
createNewResource(params, _key) {
|
|
59
|
-
|
|
59
|
+
if (params.onDemandSnapshot === void 0) throw new PFrameDriverError(`BlobResourceRef for rid ${params.toJSON()} is missing the on-demand snapshot; remote (parquet) blobs must be captured via makeRemoteBlobRef.`);
|
|
60
|
+
return this.blobDriver.getOnDemandBlob(params.onDemandSnapshot);
|
|
60
61
|
}
|
|
61
62
|
getByKey(blobId) {
|
|
62
63
|
const resource = super.tryGetByKey(blobId);
|
|
@@ -171,7 +172,7 @@ async function createPFrameDriver(params) {
|
|
|
171
172
|
const localBlobProvider = new LocalBlobProviderImpl(params.blobDriver, logger);
|
|
172
173
|
const remoteBlobProvider = await RemoteBlobProviderImpl.init(params.blobDriver, logger, { port: params.options.parquetServerPort });
|
|
173
174
|
const resolveDataInfo = (spec, data) => {
|
|
174
|
-
return isPlTreeNodeAccessor(data) ? parseDataInfoResource(data) : isDataInfo(data) ? data.type === "ParquetPartitioned" ? mapDataInfo(data, (a) => traverseParquetChunkResource(a)) : mapDataInfo(data, (a) => a
|
|
175
|
+
return isPlTreeNodeAccessor(data) ? parseDataInfoResource(data) : isDataInfo(data) ? data.type === "ParquetPartitioned" ? mapDataInfo(data, (a) => traverseParquetChunkResource(a)) : mapDataInfo(data, (a) => makeLocalBlobRef(a)) : makeJsonDataInfo(spec, data);
|
|
175
176
|
};
|
|
176
177
|
return new AbstractPFrameDriver({
|
|
177
178
|
logger,
|
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 {\n isPlTreeNodeAccessor,\n type PlTreeEntry,\n type PlTreeNodeAccessor,\n} 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 { parseDataInfoResource, traverseParquetChunkResource } from \"./data\";\nimport { isDownloadNetworkError400 } from \"@milaboratories/pl-drivers\";\n\nfunction makeBlobId(res: PlTreeEntry): PFrameInternal.PFrameBlobId {\n return String(res.rid) as PFrameInternal.PFrameBlobId;\n}\n\ntype LocalBlob = ComputableStableDefined<LocalBlobHandleAndSize>;\nclass LocalBlobProviderImpl\n extends RefCountPoolBase<PlTreeEntry, PFrameInternal.PFrameBlobId, LocalBlob>\n implements LocalBlobProvider<PlTreeEntry>\n{\n constructor(\n private readonly blobDriver: DownloadDriver,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: PlTreeEntry): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(params: PlTreeEntry, _key: PFrameInternal.PFrameBlobId): LocalBlob {\n return this.blobDriver.getDownloadedBlob(params);\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 PlTreeEntry,\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: PlTreeEntry): PFrameInternal.PFrameBlobId {\n return makeBlobId(params);\n }\n\n protected createNewResource(params: PlTreeEntry, _key: PFrameInternal.PFrameBlobId): RemoteBlob {\n return this.blobDriver.getOnDemandBlob(params);\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<PlTreeEntry> {\n constructor(\n private readonly pool: RemoteBlobPool,\n private readonly server: PFrameInternal.HttpServer,\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\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: PlTreeEntry): PoolEntry<PFrameInternal.PFrameBlobId> {\n return this.pool.acquire(params);\n }\n\n public httpServerInfo(): PFrameInternal.HttpServerInfo {\n return this.server.info;\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\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 return isPlTreeNodeAccessor(data)\n ? parseDataInfoResource(data)\n : isDataInfo(data)\n ? data.type === \"ParquetPartitioned\"\n ? mapDataInfo(data, (a) => traverseParquetChunkResource(a))\n : mapDataInfo(data, (a) => a.persist())\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\";\n\nfunction makeBlobId(res: BlobResourceRef): PFrameInternal.PFrameBlobId {\n return String(res.resourceInfo.id) 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 ) {}\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\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 async [Symbol.asyncDispose](): Promise<void> {\n await this.server.stop();\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 return isPlTreeNodeAccessor(data)\n ? parseDataInfoResource(data)\n : 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-middle-layer",
|
|
3
|
-
"version": "1.58.
|
|
3
|
+
"version": "1.58.2",
|
|
4
4
|
"description": "Pl Middle Layer",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -31,23 +31,23 @@
|
|
|
31
31
|
"yaml": "^2.8.0",
|
|
32
32
|
"zod": "~3.25.76",
|
|
33
33
|
"@milaboratories/computable": "2.9.3",
|
|
34
|
+
"@milaboratories/pf-spec-driver": "1.3.9",
|
|
34
35
|
"@milaboratories/helpers": "1.14.1",
|
|
35
36
|
"@milaboratories/pf-driver": "1.4.5",
|
|
36
|
-
"@milaboratories/pf-spec-driver": "1.3.9",
|
|
37
|
-
"@milaboratories/pl-client": "3.2.5",
|
|
38
37
|
"@milaboratories/pl-deployments": "2.17.12",
|
|
39
38
|
"@milaboratories/pl-drivers": "1.13.1",
|
|
40
|
-
"@milaboratories/pl-errors": "1.3.13",
|
|
41
|
-
"@milaboratories/pl-model-backend": "1.2.21",
|
|
42
39
|
"@milaboratories/pl-http": "1.2.4",
|
|
43
|
-
"@milaboratories/pl-
|
|
44
|
-
"@milaboratories/pl-
|
|
40
|
+
"@milaboratories/pl-client": "3.2.5",
|
|
41
|
+
"@milaboratories/pl-model-backend": "1.2.21",
|
|
45
42
|
"@milaboratories/pl-model-common": "1.39.0",
|
|
43
|
+
"@milaboratories/pl-errors": "1.3.13",
|
|
44
|
+
"@milaboratories/pl-model-middle-layer": "1.18.10",
|
|
46
45
|
"@milaboratories/resolve-helper": "1.1.3",
|
|
46
|
+
"@milaboratories/pl-tree": "1.9.23",
|
|
47
47
|
"@milaboratories/ts-helpers": "1.8.1",
|
|
48
|
-
"@platforma-sdk/model": "1.
|
|
49
|
-
"@platforma-sdk/
|
|
50
|
-
"@platforma-sdk/
|
|
48
|
+
"@platforma-sdk/model": "1.73.0",
|
|
49
|
+
"@platforma-sdk/block-tools": "2.7.19",
|
|
50
|
+
"@platforma-sdk/workflow-tengo": "5.20.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "~24.5.2",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"semver": "^7.7.2",
|
|
57
57
|
"typescript": "~5.9.3",
|
|
58
58
|
"vitest": "^4.1.3",
|
|
59
|
-
"@milaboratories/build-configs": "2.0.0",
|
|
60
59
|
"@milaboratories/ts-builder": "1.3.2",
|
|
60
|
+
"@milaboratories/build-configs": "2.0.0",
|
|
61
61
|
"@milaboratories/ts-configs": "1.2.3"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
package/src/pool/data.ts
CHANGED
|
@@ -9,17 +9,57 @@ import {
|
|
|
9
9
|
type PObjectId,
|
|
10
10
|
type PObjectSpec,
|
|
11
11
|
} from "@platforma-sdk/model";
|
|
12
|
-
import
|
|
12
|
+
import { makeResourceSnapshot, type PlTreeNodeAccessor } from "@milaboratories/pl-tree";
|
|
13
13
|
import canonicalize from "canonicalize";
|
|
14
14
|
import {
|
|
15
15
|
isNullResourceId,
|
|
16
|
+
resourceIdToString,
|
|
16
17
|
resourceType,
|
|
17
18
|
resourceTypeToString,
|
|
18
19
|
resourceTypesEqual,
|
|
20
|
+
type ResourceId,
|
|
21
|
+
type ResourceType,
|
|
19
22
|
} from "@milaboratories/pl-client";
|
|
20
23
|
import type { Writable } from "utility-types";
|
|
21
24
|
import { createHash } from "node:crypto";
|
|
22
25
|
import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
26
|
+
import { OnDemandBlobResourceSnapshot } from "@milaboratories/pl-drivers";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Tree-independent reference to a blob resource used by the PFrame data flow.
|
|
30
|
+
*
|
|
31
|
+
* The earlier design carried a {@link PlTreeEntry} all the way into the blob pools;
|
|
32
|
+
* resolution then went back through the originating tree, so when that tree dropped
|
|
33
|
+
* the resource (e.g., a project recalculated with new settings), shared pool entries
|
|
34
|
+
* — held alive by other projects — would start failing with "resource not found in
|
|
35
|
+
* the tree" even though the underlying blob was still valid backend-side.
|
|
36
|
+
*
|
|
37
|
+
* BlobResourceRef captures the snapshot at parse time, where the tree is guaranteed
|
|
38
|
+
* to resolve. The pools then key by rid (`resourceInfo.id`) and call into the
|
|
39
|
+
* download driver with the snapshot directly — independent of any specific tree.
|
|
40
|
+
*/
|
|
41
|
+
export class BlobResourceRef {
|
|
42
|
+
constructor(
|
|
43
|
+
public readonly resourceInfo: { readonly id: ResourceId; readonly type: ResourceType },
|
|
44
|
+
/** Present only for on-demand (remote) blobs; needed for size and signed handle. */
|
|
45
|
+
public readonly onDemandSnapshot: OnDemandBlobResourceSnapshot | undefined,
|
|
46
|
+
) {}
|
|
47
|
+
|
|
48
|
+
toJSON(): string {
|
|
49
|
+
return resourceIdToString(this.resourceInfo.id);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function makeLocalBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {
|
|
54
|
+
return new BlobResourceRef(accessor.resourceInfo, undefined);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function makeRemoteBlobRef(accessor: PlTreeNodeAccessor): BlobResourceRef {
|
|
58
|
+
return new BlobResourceRef(
|
|
59
|
+
accessor.resourceInfo,
|
|
60
|
+
makeResourceSnapshot(accessor, OnDemandBlobResourceSnapshot),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
23
63
|
|
|
24
64
|
export const PColumnDataJsonPartitioned = resourceType("PColumnData/JsonPartitioned", "1");
|
|
25
65
|
export const PColumnDataJsonSuperPartitioned = resourceType(
|
|
@@ -59,7 +99,7 @@ const BinaryPartitionedValuesFieldSuffix = ".values";
|
|
|
59
99
|
|
|
60
100
|
export function parseDataInfoResource(
|
|
61
101
|
data: PlTreeNodeAccessor,
|
|
62
|
-
): PFrameInternal.DataInfo<
|
|
102
|
+
): PFrameInternal.DataInfo<BlobResourceRef> {
|
|
63
103
|
if (!data.getIsReadyOrError()) throw new PFrameDriverError("Data not ready.");
|
|
64
104
|
|
|
65
105
|
const resourceData = data.getDataAsJson();
|
|
@@ -80,7 +120,10 @@ export function parseDataInfoResource(
|
|
|
80
120
|
const parts = Object.fromEntries(
|
|
81
121
|
data
|
|
82
122
|
.listInputFields()
|
|
83
|
-
.map((field) => [
|
|
123
|
+
.map((field) => [
|
|
124
|
+
field,
|
|
125
|
+
makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true })),
|
|
126
|
+
]),
|
|
84
127
|
);
|
|
85
128
|
|
|
86
129
|
return {
|
|
@@ -91,7 +134,7 @@ export function parseDataInfoResource(
|
|
|
91
134
|
} else if (resourceTypesEqual(data.resourceType, PColumnDataJsonSuperPartitioned)) {
|
|
92
135
|
const meta = resourceData as PColumnDataSuperPartitionedResourceValue;
|
|
93
136
|
|
|
94
|
-
const parts: Record<string,
|
|
137
|
+
const parts: Record<string, BlobResourceRef> = {};
|
|
95
138
|
for (const superKey of data.listInputFields()) {
|
|
96
139
|
const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });
|
|
97
140
|
const keys = superPart.listInputFields();
|
|
@@ -103,7 +146,9 @@ export function parseDataInfoResource(
|
|
|
103
146
|
...(JSON.parse(superKey) as PColumnValue[]),
|
|
104
147
|
...(JSON.parse(key) as PColumnValue[]),
|
|
105
148
|
]);
|
|
106
|
-
parts[partKey] =
|
|
149
|
+
parts[partKey] = makeLocalBlobRef(
|
|
150
|
+
superPart.traverse({ field: key, errorIfFieldNotSet: true }),
|
|
151
|
+
);
|
|
107
152
|
}
|
|
108
153
|
}
|
|
109
154
|
|
|
@@ -115,7 +160,7 @@ export function parseDataInfoResource(
|
|
|
115
160
|
} else if (resourceTypesEqual(data.resourceType, PColumnDataBinaryPartitioned)) {
|
|
116
161
|
const meta = resourceData as PColumnDataPartitionedResourceValue;
|
|
117
162
|
|
|
118
|
-
const parts: Record<string, Partial<Writable<BinaryChunk<
|
|
163
|
+
const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};
|
|
119
164
|
|
|
120
165
|
// parsing the structure
|
|
121
166
|
for (const field of data.listInputFields()) {
|
|
@@ -126,7 +171,7 @@ export function parseDataInfoResource(
|
|
|
126
171
|
part = {};
|
|
127
172
|
parts[partKey] = part;
|
|
128
173
|
}
|
|
129
|
-
part.index = data.traverse({ field, errorIfFieldNotSet: true })
|
|
174
|
+
part.index = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));
|
|
130
175
|
} else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {
|
|
131
176
|
const partKey = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);
|
|
132
177
|
let part = parts[partKey];
|
|
@@ -134,7 +179,7 @@ export function parseDataInfoResource(
|
|
|
134
179
|
part = {};
|
|
135
180
|
parts[partKey] = part;
|
|
136
181
|
}
|
|
137
|
-
part.values = data.traverse({ field, errorIfFieldNotSet: true })
|
|
182
|
+
part.values = makeLocalBlobRef(data.traverse({ field, errorIfFieldNotSet: true }));
|
|
138
183
|
} else throw new PFrameDriverError(`unrecognized part field name: ${field}`);
|
|
139
184
|
}
|
|
140
185
|
|
|
@@ -147,12 +192,12 @@ export function parseDataInfoResource(
|
|
|
147
192
|
return {
|
|
148
193
|
type: "BinaryPartitioned",
|
|
149
194
|
partitionKeyLength: meta.partitionKeyLength,
|
|
150
|
-
parts: parts as Record<string, BinaryChunk<
|
|
195
|
+
parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,
|
|
151
196
|
};
|
|
152
197
|
} else if (resourceTypesEqual(data.resourceType, PColumnDataBinarySuperPartitioned)) {
|
|
153
198
|
const meta = resourceData as PColumnDataSuperPartitionedResourceValue;
|
|
154
199
|
|
|
155
|
-
const parts: Record<string, Partial<Writable<BinaryChunk<
|
|
200
|
+
const parts: Record<string, Partial<Writable<BinaryChunk<BlobResourceRef>>>> = {};
|
|
156
201
|
for (const superKey of data.listInputFields()) {
|
|
157
202
|
const superData = data.traverse({ field: superKey, errorIfFieldNotSet: true });
|
|
158
203
|
const keys = superData.listInputFields();
|
|
@@ -172,12 +217,9 @@ export function parseDataInfoResource(
|
|
|
172
217
|
part = {};
|
|
173
218
|
parts[partKey] = part;
|
|
174
219
|
}
|
|
175
|
-
parts[partKey].index =
|
|
176
|
-
.traverse({
|
|
177
|
-
|
|
178
|
-
errorIfFieldNotSet: true,
|
|
179
|
-
})
|
|
180
|
-
.persist();
|
|
220
|
+
parts[partKey].index = makeLocalBlobRef(
|
|
221
|
+
superData.traverse({ field, errorIfFieldNotSet: true }),
|
|
222
|
+
);
|
|
181
223
|
} else if (field.endsWith(BinaryPartitionedValuesFieldSuffix)) {
|
|
182
224
|
const key = field.slice(0, -BinaryPartitionedValuesFieldSuffix.length);
|
|
183
225
|
|
|
@@ -190,12 +232,9 @@ export function parseDataInfoResource(
|
|
|
190
232
|
part = {};
|
|
191
233
|
parts[partKey] = part;
|
|
192
234
|
}
|
|
193
|
-
parts[partKey].values =
|
|
194
|
-
.traverse({
|
|
195
|
-
|
|
196
|
-
errorIfFieldNotSet: true,
|
|
197
|
-
})
|
|
198
|
-
.persist();
|
|
235
|
+
parts[partKey].values = makeLocalBlobRef(
|
|
236
|
+
superData.traverse({ field, errorIfFieldNotSet: true }),
|
|
237
|
+
);
|
|
199
238
|
} else throw new PFrameDriverError(`unrecognized part field name: ${field}`);
|
|
200
239
|
}
|
|
201
240
|
}
|
|
@@ -203,12 +242,12 @@ export function parseDataInfoResource(
|
|
|
203
242
|
return {
|
|
204
243
|
type: "BinaryPartitioned",
|
|
205
244
|
partitionKeyLength: meta.superPartitionKeyLength + meta.partitionKeyLength,
|
|
206
|
-
parts: parts as Record<string, BinaryChunk<
|
|
245
|
+
parts: parts as Record<string, BinaryChunk<BlobResourceRef>>,
|
|
207
246
|
};
|
|
208
247
|
} else if (resourceTypesEqual(data.resourceType, PColumnDataParquetPartitioned)) {
|
|
209
248
|
const meta = resourceData as PColumnDataPartitionedResourceValue;
|
|
210
249
|
|
|
211
|
-
const parts: Record<string, ParquetChunk<
|
|
250
|
+
const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};
|
|
212
251
|
for (const key of data.listInputFields()) {
|
|
213
252
|
const resource = data.traverse({
|
|
214
253
|
field: key,
|
|
@@ -227,7 +266,7 @@ export function parseDataInfoResource(
|
|
|
227
266
|
} else if (resourceTypesEqual(data.resourceType, PColumnDataParquetSuperPartitioned)) {
|
|
228
267
|
const meta = resourceData as PColumnDataSuperPartitionedResourceValue;
|
|
229
268
|
|
|
230
|
-
const parts: Record<string, ParquetChunk<
|
|
269
|
+
const parts: Record<string, ParquetChunk<BlobResourceRef>> = {};
|
|
231
270
|
for (const superKey of data.listInputFields()) {
|
|
232
271
|
const superPart = data.traverse({ field: superKey, errorIfFieldNotSet: true });
|
|
233
272
|
const keys = superPart.listInputFields();
|
|
@@ -259,7 +298,7 @@ export function parseDataInfoResource(
|
|
|
259
298
|
|
|
260
299
|
export function traverseParquetChunkResource(
|
|
261
300
|
resource: PlTreeNodeAccessor,
|
|
262
|
-
): ParquetChunk<
|
|
301
|
+
): ParquetChunk<BlobResourceRef> {
|
|
263
302
|
if (!resourceTypesEqual(resource.resourceType, ParquetChunkResourceType)) {
|
|
264
303
|
throw new PFrameDriverError(
|
|
265
304
|
`unknown resource type: ${resourceTypeToString(resource.resourceType)}, ` +
|
|
@@ -267,9 +306,9 @@ export function traverseParquetChunkResource(
|
|
|
267
306
|
);
|
|
268
307
|
}
|
|
269
308
|
|
|
270
|
-
const blob =
|
|
271
|
-
.traverse({ field: "blob", assertFieldType: "Service", errorIfFieldNotSet: true })
|
|
272
|
-
|
|
309
|
+
const blob = makeRemoteBlobRef(
|
|
310
|
+
resource.traverse({ field: "blob", assertFieldType: "Service", errorIfFieldNotSet: true }),
|
|
311
|
+
);
|
|
273
312
|
const partInfo = resource.getDataAsJson() as ParquetChunkMetadata;
|
|
274
313
|
const mapping = resource
|
|
275
314
|
.traverse({ field: "mapping", assertFieldType: "Service", errorIfFieldNotSet: true })
|
package/src/pool/driver.ts
CHANGED
|
@@ -15,11 +15,7 @@ import { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
|
15
15
|
import { emptyDir } from "@milaboratories/ts-helpers";
|
|
16
16
|
import { RefCountPoolBase, type PoolEntry, type MiLogger } from "@milaboratories/helpers";
|
|
17
17
|
import type { DownloadDriver } from "@milaboratories/pl-drivers";
|
|
18
|
-
import {
|
|
19
|
-
isPlTreeNodeAccessor,
|
|
20
|
-
type PlTreeEntry,
|
|
21
|
-
type PlTreeNodeAccessor,
|
|
22
|
-
} from "@milaboratories/pl-tree";
|
|
18
|
+
import { isPlTreeNodeAccessor, type PlTreeNodeAccessor } from "@milaboratories/pl-tree";
|
|
23
19
|
import type { Computable, ComputableStableDefined } from "@milaboratories/computable";
|
|
24
20
|
import {
|
|
25
21
|
makeJsonDataInfo,
|
|
@@ -33,17 +29,22 @@ import {
|
|
|
33
29
|
import { HttpHelpers } from "@milaboratories/pframes-rs-node";
|
|
34
30
|
import path from "node:path";
|
|
35
31
|
import { Readable } from "node:stream";
|
|
36
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
BlobResourceRef,
|
|
34
|
+
makeLocalBlobRef,
|
|
35
|
+
parseDataInfoResource,
|
|
36
|
+
traverseParquetChunkResource,
|
|
37
|
+
} from "./data";
|
|
37
38
|
import { isDownloadNetworkError400 } from "@milaboratories/pl-drivers";
|
|
38
39
|
|
|
39
|
-
function makeBlobId(res:
|
|
40
|
-
return String(res.
|
|
40
|
+
function makeBlobId(res: BlobResourceRef): PFrameInternal.PFrameBlobId {
|
|
41
|
+
return String(res.resourceInfo.id) as PFrameInternal.PFrameBlobId;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
type LocalBlob = ComputableStableDefined<LocalBlobHandleAndSize>;
|
|
44
45
|
class LocalBlobProviderImpl
|
|
45
|
-
extends RefCountPoolBase<
|
|
46
|
-
implements LocalBlobProvider<
|
|
46
|
+
extends RefCountPoolBase<BlobResourceRef, PFrameInternal.PFrameBlobId, LocalBlob>
|
|
47
|
+
implements LocalBlobProvider<BlobResourceRef>
|
|
47
48
|
{
|
|
48
49
|
constructor(
|
|
49
50
|
private readonly blobDriver: DownloadDriver,
|
|
@@ -52,12 +53,15 @@ class LocalBlobProviderImpl
|
|
|
52
53
|
super();
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
protected calculateParamsKey(params:
|
|
56
|
+
protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {
|
|
56
57
|
return makeBlobId(params);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
protected createNewResource(
|
|
60
|
-
|
|
60
|
+
protected createNewResource(
|
|
61
|
+
params: BlobResourceRef,
|
|
62
|
+
_key: PFrameInternal.PFrameBlobId,
|
|
63
|
+
): LocalBlob {
|
|
64
|
+
return this.blobDriver.getDownloadedBlob(params.resourceInfo);
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
public getByKey(blobId: PFrameInternal.PFrameBlobId): LocalBlob {
|
|
@@ -90,7 +94,7 @@ class LocalBlobProviderImpl
|
|
|
90
94
|
|
|
91
95
|
type RemoteBlob = Computable<RemoteBlobHandleAndSize>;
|
|
92
96
|
class RemoteBlobPool extends RefCountPoolBase<
|
|
93
|
-
|
|
97
|
+
BlobResourceRef,
|
|
94
98
|
PFrameInternal.PFrameBlobId,
|
|
95
99
|
RemoteBlob
|
|
96
100
|
> {
|
|
@@ -101,12 +105,21 @@ class RemoteBlobPool extends RefCountPoolBase<
|
|
|
101
105
|
super();
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
protected calculateParamsKey(params:
|
|
108
|
+
protected calculateParamsKey(params: BlobResourceRef): PFrameInternal.PFrameBlobId {
|
|
105
109
|
return makeBlobId(params);
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
protected createNewResource(
|
|
109
|
-
|
|
112
|
+
protected createNewResource(
|
|
113
|
+
params: BlobResourceRef,
|
|
114
|
+
_key: PFrameInternal.PFrameBlobId,
|
|
115
|
+
): RemoteBlob {
|
|
116
|
+
if (params.onDemandSnapshot === undefined) {
|
|
117
|
+
throw new PFrameDriverError(
|
|
118
|
+
`BlobResourceRef for rid ${params.toJSON()} is missing the on-demand snapshot; ` +
|
|
119
|
+
`remote (parquet) blobs must be captured via makeRemoteBlobRef.`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return this.blobDriver.getOnDemandBlob(params.onDemandSnapshot);
|
|
110
123
|
}
|
|
111
124
|
|
|
112
125
|
public getByKey(blobId: PFrameInternal.PFrameBlobId): RemoteBlob {
|
|
@@ -232,7 +245,7 @@ class BlobStore extends PFrameInternal.BaseObjectStore {
|
|
|
232
245
|
}
|
|
233
246
|
}
|
|
234
247
|
|
|
235
|
-
class RemoteBlobProviderImpl implements RemoteBlobProvider<
|
|
248
|
+
class RemoteBlobProviderImpl implements RemoteBlobProvider<BlobResourceRef> {
|
|
236
249
|
constructor(
|
|
237
250
|
private readonly pool: RemoteBlobPool,
|
|
238
251
|
private readonly server: PFrameInternal.HttpServer,
|
|
@@ -253,7 +266,7 @@ class RemoteBlobProviderImpl implements RemoteBlobProvider<PlTreeEntry> {
|
|
|
253
266
|
return new RemoteBlobProviderImpl(pool, server);
|
|
254
267
|
}
|
|
255
268
|
|
|
256
|
-
public acquire(params:
|
|
269
|
+
public acquire(params: BlobResourceRef): PoolEntry<PFrameInternal.PFrameBlobId> {
|
|
257
270
|
return this.pool.acquire(params);
|
|
258
271
|
}
|
|
259
272
|
|
|
@@ -302,7 +315,7 @@ export async function createPFrameDriver(params: {
|
|
|
302
315
|
: isDataInfo(data)
|
|
303
316
|
? data.type === "ParquetPartitioned"
|
|
304
317
|
? mapDataInfo(data, (a) => traverseParquetChunkResource(a))
|
|
305
|
-
: mapDataInfo(data, (a) => a
|
|
318
|
+
: mapDataInfo(data, (a) => makeLocalBlobRef(a))
|
|
306
319
|
: makeJsonDataInfo(spec, data);
|
|
307
320
|
};
|
|
308
321
|
|