@gscdump/engine-duckdb-wasm 0.26.6 → 0.26.7
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/index.d.mts +18 -0
- package/dist/index.mjs +8 -8
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -136,6 +136,24 @@ interface AttachOpfsTablesOptions {
|
|
|
136
136
|
version?: string;
|
|
137
137
|
/** Ticks once per file as it lands in OPFS + registers. UI progress. */
|
|
138
138
|
onFileProgress?: (info: OpfsFileProgress) => void;
|
|
139
|
+
/**
|
|
140
|
+
* Serializer for the operations that mutate the DuckDB-WASM virtual
|
|
141
|
+
* filesystem / catalog (`registerFileHandle`, `dropFile`, `CREATE`/`DROP
|
|
142
|
+
* VIEW`) — those are not concurrency-safe across consumers sharing one
|
|
143
|
+
* `AsyncDuckDB`. Callers with a shared DB pass their global attach mutex
|
|
144
|
+
* here so ONLY these mutations serialize; the parquet downloads (network +
|
|
145
|
+
* OPFS writes, no DB interaction) run outside the lock and overlap across
|
|
146
|
+
* concurrent attaches. Wrapping the whole `attachOpfsParquetTables` call in
|
|
147
|
+
* the mutex instead serializes every table's downloads end-to-end — the
|
|
148
|
+
* dominant cold-load cost.
|
|
149
|
+
*
|
|
150
|
+
* The returned handle's `detach()` is NOT routed through this — callers
|
|
151
|
+
* that pass a lock typically already hold it around teardown, and the lock
|
|
152
|
+
* is not reentrant.
|
|
153
|
+
*
|
|
154
|
+
* Default: run inline (caller owns the DB exclusively).
|
|
155
|
+
*/
|
|
156
|
+
withDb?: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
139
157
|
}
|
|
140
158
|
interface OpfsFileProgress {
|
|
141
159
|
table: string;
|
package/dist/index.mjs
CHANGED
|
@@ -702,7 +702,7 @@ async function runWithConcurrency$1(items, concurrency, fn) {
|
|
|
702
702
|
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker));
|
|
703
703
|
}
|
|
704
704
|
async function attachOpfsParquetTables(options) {
|
|
705
|
-
const { db, conn, tables, schema = "main", fetch: fetchImpl = globalThis.fetch.bind(globalThis), fetchInit, fetchConcurrency = DEFAULT_CONCURRENCY, signal, version, onFileProgress } = options;
|
|
705
|
+
const { db, conn, tables, schema = "main", fetch: fetchImpl = globalThis.fetch.bind(globalThis), fetchInit, fetchConcurrency = DEFAULT_CONCURRENCY, signal, version, onFileProgress, withDb = (fn) => fn() } = options;
|
|
706
706
|
await requestPersistentStorage();
|
|
707
707
|
const root = await getOpfsRoot();
|
|
708
708
|
const flat = [];
|
|
@@ -746,7 +746,7 @@ async function attachOpfsParquetTables(options) {
|
|
|
746
746
|
const releaseTable = async (table) => {
|
|
747
747
|
const names = (tableFiles.get(table) ?? []).map((f) => f.name);
|
|
748
748
|
for (const n of names) acquiredNames.delete(n);
|
|
749
|
-
await registry.release(names);
|
|
749
|
+
await withDb(() => registry.release(names));
|
|
750
750
|
};
|
|
751
751
|
const runDownloads = () => runWithConcurrency$1(flat, Math.max(1, fetchConcurrency), async (item, index) => {
|
|
752
752
|
if (degraded.has(item.table)) return;
|
|
@@ -764,7 +764,7 @@ async function attachOpfsParquetTables(options) {
|
|
|
764
764
|
throw err;
|
|
765
765
|
}
|
|
766
766
|
try {
|
|
767
|
-
await registry.acquire(name, () => result.handle);
|
|
767
|
+
await withDb(() => registry.acquire(name, () => result.handle));
|
|
768
768
|
acquiredNames.add(name);
|
|
769
769
|
} catch (err) {
|
|
770
770
|
if (isAbortError$1(err)) throw err;
|
|
@@ -794,7 +794,7 @@ async function attachOpfsParquetTables(options) {
|
|
|
794
794
|
try {
|
|
795
795
|
await runDownloads();
|
|
796
796
|
} catch (err) {
|
|
797
|
-
await registry.release([...acquiredNames]).catch(() => {});
|
|
797
|
+
await withDb(() => registry.release([...acquiredNames])).catch(() => {});
|
|
798
798
|
throw err;
|
|
799
799
|
}
|
|
800
800
|
const attached = [];
|
|
@@ -814,19 +814,19 @@ async function attachOpfsParquetTables(options) {
|
|
|
814
814
|
const lakeNames = overlayName ? files.map((f) => f.name).filter((n) => n !== overlayName) : files.map((f) => f.name);
|
|
815
815
|
try {
|
|
816
816
|
signal?.throwIfAborted();
|
|
817
|
-
await conn.query(overlayName ? readParquetViewWithOverlaySql(schema, t.table, lakeNames, overlayName) : readParquetViewSql$1(schema, t.table, lakeNames));
|
|
817
|
+
await withDb(() => conn.query(overlayName ? readParquetViewWithOverlaySql(schema, t.table, lakeNames, overlayName) : readParquetViewSql$1(schema, t.table, lakeNames)));
|
|
818
818
|
} catch (err) {
|
|
819
819
|
if (isAbortError$1(err)) {
|
|
820
|
-
await detachOpfs(registry, conn, schema, attached, [...acquiredNames]).catch(() => {});
|
|
820
|
+
await withDb(() => detachOpfs(registry, conn, schema, attached, [...acquiredNames])).catch(() => {});
|
|
821
821
|
throw err;
|
|
822
822
|
}
|
|
823
823
|
if (isOpfsAccessHandleConflict(err)) {
|
|
824
|
-
if (registry.viewRefs(`${schema}.${t.table}`) === 0) await conn.query(`DROP VIEW IF EXISTS ${schema}.${t.table}`).catch(() => {});
|
|
824
|
+
if (registry.viewRefs(`${schema}.${t.table}`) === 0) await withDb(() => conn.query(`DROP VIEW IF EXISTS ${schema}.${t.table}`)).catch(() => {});
|
|
825
825
|
degraded.add(t.table);
|
|
826
826
|
await releaseTable(t.table);
|
|
827
827
|
continue;
|
|
828
828
|
}
|
|
829
|
-
await detachOpfs(registry, conn, schema, attached, [...acquiredNames]).catch(() => {});
|
|
829
|
+
await withDb(() => detachOpfs(registry, conn, schema, attached, [...acquiredNames])).catch(() => {});
|
|
830
830
|
throw err;
|
|
831
831
|
}
|
|
832
832
|
attached.push(t.table);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/engine-duckdb-wasm",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.26.
|
|
4
|
+
"version": "0.26.7",
|
|
5
5
|
"description": "DuckDB-WASM engine adapter for @gscdump/analysis — typed browser analytics against parquet via R2.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"drizzle-orm": "1.0.0-rc.3",
|
|
48
|
-
"@gscdump/engine": "0.26.
|
|
49
|
-
"gscdump": "0.26.
|
|
50
|
-
"
|
|
48
|
+
"@gscdump/engine": "0.26.7",
|
|
49
|
+
"@gscdump/sdk": "0.26.7",
|
|
50
|
+
"gscdump": "0.26.7"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@duckdb/duckdb-wasm": "^1.32.0",
|