Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 36 additions & 18 deletions packages/pglite/src/extensionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export async function loadExtensions(
}
if (blob) {
const bytes = new Uint8Array(await blob.arrayBuffer())
loadExtension(mod, ext, bytes, log)
// Await all async WASM precompilations so preloadedWasm is populated
// before dlopen is called during postgres startup.
await Promise.all(loadExtension(mod, ext, bytes, log))
} else {
console.error('Could not get binary data for extension:', ext)
}
Expand All @@ -76,28 +78,43 @@ function loadExtension(
_ext: string,
bytes: Uint8Array,
log: (...args: any[]) => void,
) {
): Promise<void>[] {
const soPreloadPromises: Promise<void>[] = []
const data = tinyTar.untar(bytes)
data.forEach((file: any) => {
if (!file.name.startsWith('.')) {
const filePath = mod.WASM_PREFIX + '/' + file.name
if (file.name.endsWith('.so')) {
const extOk = (...args: any[]) => {
log('pgfs:ext OK', filePath, args)
}
const extFail = (...args: any[]) => {
log('pgfs:ext FAIL', filePath, args)
}
mod.FS.createPreloadedFile(
dirname(filePath),
file.name.split('/').pop()!.slice(0, -3),
file.data as any, // There is a type error in Emscripten's FS.createPreloadedFile, this excepts a Uint8Array, but the type is defined as any
true,
true,
extOk,
extFail,
false,
)
const soName = file.name.split('/').pop()! // e.g. 'postgis-3.so'
const dirPath = dirname(filePath)
// Wrap createPreloadedFile in a Promise so loadExtensions can await the
// async WASM compilation done by Emscripten's wasm preload plugin.
// The plugin calls extOk only after preloadedWasm[path] is set, so
// awaiting this ensures dlopen finds the pre-compiled module.
const soPreload = new Promise<void>((resolve, reject) => {
const extOk = (...args: any[]) => {
log('pgfs:ext OK', filePath, args)
resolve()
}
const extFail = (...args: any[]) => {
log('pgfs:ext FAIL', filePath, args)
reject(new Error(`Failed to preload ${filePath}`))
}
// Keep the .so suffix so Emscripten's wasm preload plugin canHandle() matches,
// triggering async WebAssembly.instantiate. The compiled module is stored in
// preloadedWasm under the path with .so.
mod.FS.createPreloadedFile(
dirPath,
soName,
file.data as any, // There is a type error in Emscripten's FS.createPreloadedFile, this excepts a Uint8Array, but the type is defined as any
true,
true,
extOk,
extFail,
false,
)
})
soPreloadPromises.push(soPreload)
} else {
try {
const dirPath = filePath.substring(0, filePath.lastIndexOf('/'))
Expand All @@ -111,6 +128,7 @@ function loadExtension(
}
}
})
return soPreloadPromises
}

function dirname(path: string) {
Expand Down
Loading