fix(pglite): stop leaking every wire message's memory in the wasm module

The PGlite fork stubs MemoryContextResetAndDeleteChildren, which
PostgreSQL 17 removed, as an empty macro, so MessageContext was never
reset and each statement leaked its parse and plan state (about 10 KB).
On a real library the process grew to 15 GB during the first scan and
the host swapped itself to a crawl. The new build maps the macro to
MemoryContextReset (message_context_reset.diff); memory now stays flat
across thousands of statements. Adds PGlite.MemorySize for measuring.
This commit is contained in:
Deluan 2026-09-04 21:38:21 -04:00
commit a528de445d
4 changed files with 18 additions and 0 deletions

View file

@ -11,6 +11,9 @@ electric-sql/postgres-pglite, branch REL_17_5_WASM-pglite). Clone it to /tmp/pgl
- `wasi-c.diff` — makes the forced `-fPIC` in the compiler wrapper overridable (`PGLITE_PIC`). NOTE: the matching
`-fpic` in `postgresql-src/wasm-build/build-pgcore.sh` (cloned at build time) is not covered by a diff here; the
`-fno-pic` experiment did not take effect and is unmeasured.
- `message_context_reset.diff` — goes in `patches/pglite-wasm/`. The fork stubs `MemoryContextResetAndDeleteChildren`
(removed in PostgreSQL 17) as an empty macro, so `MessageContext` is never reset and every wire message leaks its
parse/plan state (~10 KB per statement; a library scan reached 15 GB). The patch maps it to `MemoryContextReset`.
- `clear_error_portals.diff` — goes in `patches/pglite-wasm/`. A PostgreSQL ERROR traps the wasm instance, which skips
every PG_CATCH, so the active portal is never marked failed and the next statement fails with
"cannot drop active portal". Wrapping `AbortCurrentTransaction()` in `clear_error()` with

View file

@ -0,0 +1,12 @@
--- a/pg_main.c
+++ b/pg_main.c
@@ -28,7 +28,8 @@
// globals
-#define MemoryContextResetAndDeleteChildren(...)
+// PG17 dropped this macro; the no-op stub leaked every message's parse/plan state.
+#define MemoryContextResetAndDeleteChildren(ctx) MemoryContextReset(ctx)
// #define SpinLockInit(...)

View file

@ -403,6 +403,9 @@ func (pg *PGlite) startBridge() error {
// DataDir is the host directory holding the cluster.
func (pg *PGlite) DataDir() string { return pg.dataDir }
// MemorySize reports the wasm linear memory size in bytes; it only ever grows.
func (pg *PGlite) MemorySize() uint64 { return uint64(pg.mod.Memory().Size()) }
// Connections reports how many client connections the bridge has accepted.
func (pg *PGlite) Connections() int64 { return pg.connections.Load() }

Binary file not shown.