Skip to content

Commit cb2767b

Browse files
author
Marcus Pousette
committed
tests(pglite): add message context leak repro and changeset\n\nDepends on submodule PR: electric-sql/postgres-pglite#47
1 parent 96d4e62 commit cb2767b

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changesets
2+
3+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4+
with multi-package repos, or single-package repos to help you version and publish your code. You can
5+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6+
7+
We have a quick list of common questions to get you started engaging with this project in
8+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@electric-sql/pglite': minor
3+
---
4+
5+
Ensure MessageContext and its children are actually cleared between queries
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@3.0.3/schema.json",
3+
"changelog": "@changesets/cli/changelog",
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "restricted",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": []
11+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { describe, it, expect, beforeEach } from 'vitest'
2+
import { testDTC } from './test-utils.js'
3+
import { PGlite } from '../dist/index.js'
4+
5+
// This test isolates the MessageContext leak reported in
6+
// https://github.com/electric-sql/pglite/issues/779
7+
// It inserts many rows with large JSON literals and then inspects
8+
// pg_backend_memory_contexts to ensure MessageContext has been reset
9+
// between queries and does not accumulate unbounded allocations.
10+
11+
const KB = 1024
12+
13+
function makeJsonBlob(size: number): string {
14+
// Keep the SQL literal simple (mostly "x" payload) to simulate
15+
// large messages while avoiding excessive parsing overhead.
16+
return JSON.stringify({ padding: 'x'.repeat(size) })
17+
}
18+
19+
testDTC(async (defaultDataTransferContainer) => {
20+
describe('MessageContext reset between queries', () => {
21+
let db: PGlite
22+
23+
beforeEach(async () => {
24+
db = new PGlite({ defaultDataTransferContainer })
25+
await db.exec(`
26+
CREATE TABLE IF NOT EXISTS leak_test (
27+
id SERIAL PRIMARY KEY,
28+
blob jsonb NOT NULL
29+
);
30+
`)
31+
})
32+
33+
it('does not accumulate allocations in MessageContext', async () => {
34+
// Choose sizes to expose the leak without taking too long.
35+
const blobSize = 100 * KB // ~100KB per row
36+
const rows = 300 // ~30MB of total SQL literal payload
37+
38+
const blob = makeJsonBlob(blobSize)
39+
40+
for (let i = 0; i < rows; i++) {
41+
await db.exec(`INSERT INTO leak_test (blob) VALUES ('${blob}')`)
42+
}
43+
44+
// After the loop, the next query should see a freshly reset
45+
// MessageContext (reset happens at the start of command read),
46+
// so used_bytes should remain small (well below the total data inserted).
47+
const mem = await db.query<{ used_bytes: number }>(`
48+
SELECT used_bytes
49+
FROM pg_backend_memory_contexts
50+
WHERE name = 'MessageContext'
51+
ORDER BY level
52+
LIMIT 1
53+
`)
54+
55+
expect(mem.rows).toHaveLength(1)
56+
const used = Number(mem.rows[0].used_bytes)
57+
58+
// On a correctly resetting build, MessageContext should typically be in the
59+
// low kilobytes to a few megabytes range. Set an upper bound that will fail
60+
// if allocations accumulated across the INSERTs (~30MB of literal payload).
61+
// Using 5MB as a generous ceiling for transient allocations of this SELECT.
62+
expect(used).toBeLessThan(5 * 1024 * 1024)
63+
})
64+
})
65+
})
66+

0 commit comments

Comments
 (0)