.
This commit is contained in:
parent
909096969a
commit
f87ad0d786
4 changed files with 50 additions and 14 deletions
|
|
@ -20,7 +20,7 @@
|
|||
"fs-extra": "^11.3.2",
|
||||
"mini-css-extract-plugin": "^2.9.4",
|
||||
"obsidian": "1.11.0",
|
||||
"reconcile-text": "^0.11.0",
|
||||
"reconcile-text": "^0.12.1",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"sass": "^1.96.0",
|
||||
"sass-loader": "^16.0.6",
|
||||
|
|
|
|||
17
frontend/package-lock.json
generated
17
frontend/package-lock.json
generated
|
|
@ -5954,9 +5954,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/reconcile-text": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/reconcile-text/-/reconcile-text-0.8.0.tgz",
|
||||
"integrity": "sha512-evskVha3YgpP2ZelsFxP9t7CuKnwE7TrsH3FdrH2mfKbzjUWiNF7scHXsFbFS921lmFlAOB94DHNAWPvL34Mqg==",
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/reconcile-text/-/reconcile-text-0.12.1.tgz",
|
||||
"integrity": "sha512-UtDykRp8k/hDhMMqcexkeCmGCFy/ScrKFYkIj2lpT7OYEN5eXL6BeUORgf9jPZ+sMf6/z5tZWSOC1Q87jNzhUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
|
@ -7686,7 +7686,7 @@
|
|||
"fs-extra": "^11.3.2",
|
||||
"mini-css-extract-plugin": "^2.9.4",
|
||||
"obsidian": "1.11.0",
|
||||
"reconcile-text": "^0.11.0",
|
||||
"reconcile-text": "^0.12.1",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"sass": "^1.96.0",
|
||||
"sass-loader": "^16.0.6",
|
||||
|
|
@ -7740,13 +7740,6 @@
|
|||
"@codemirror/view": "6.38.6"
|
||||
}
|
||||
},
|
||||
"obsidian-plugin/node_modules/reconcile-text": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/reconcile-text/-/reconcile-text-0.11.0.tgz",
|
||||
"integrity": "sha512-a3sy3obazoc1BMEHx6IQn8ESZKnakVWZuRLi7OSEB56E8evRtrXBMj7yuo10fMoG4JkcZC6tokOfzpwZAKX+PQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"obsidian-plugin/node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
|
|
@ -7775,7 +7768,7 @@
|
|||
"@types/node": "^24.8.1",
|
||||
"byte-base64": "^1.1.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"reconcile-text": "^0.8.0",
|
||||
"reconcile-text": "^0.12.1",
|
||||
"ts-loader": "^9.5.2",
|
||||
"tslib": "2.8.1",
|
||||
"tsx": "^4.20.6",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
"devDependencies": {
|
||||
"byte-base64": "^1.1.0",
|
||||
"minimatch": "^10.0.1",
|
||||
"reconcile-text": "^0.8.0",
|
||||
"reconcile-text": "^0.12.1",
|
||||
"uuid": "^13.0.0",
|
||||
"@types/node": "^24.8.1",
|
||||
"ts-loader": "^9.5.2",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,49 @@ test("content edited after planning is merged with the incoming snapshot", async
|
|||
);
|
||||
});
|
||||
|
||||
test("repeated large text replacements reuse WebAssembly memory", async () => {
|
||||
// The replacement from fuzz-193329 exhausted reconcile-text 0.8.0's
|
||||
// allocator over repeated merges, eventually stalling sync and trapping.
|
||||
const original = (
|
||||
" مرحباéשלום\t日本語\ncaféalphaalphaनमस्ते🦊🌍café\n" +
|
||||
"🌍مرحبامرحباनमस्तेשלום\talphaalphacaféمرحبا🌍\r\n日本語مرحبا"
|
||||
).repeat(128);
|
||||
const replacement = await hashSnapshot({
|
||||
content: bytes(
|
||||
(
|
||||
"alpha🌍éनमस्ते日本語שלום\uFEFFשלום\t\r\n" +
|
||||
"\uFEFF🦊 🦊🌍नमस्ते\uFEFFéمرحبا\r\ncafé🌍é🌍"
|
||||
).repeat(128)
|
||||
)
|
||||
});
|
||||
const f = await fixture({ "a.md": original });
|
||||
const expected = (await f.files.readSnapshot("a.md"))!;
|
||||
const apply = async () => {
|
||||
await f.disk.userWrite("a.md", bytes(original));
|
||||
await f.files.applyChanges(structuredClone(f.database.state), {
|
||||
a: { expected, replacement }
|
||||
});
|
||||
assert.deepEqual(f.disk.userFiles().get("a.md"), replacement.content);
|
||||
assert.equal(
|
||||
f.database.state.documents.a.observedHash,
|
||||
replacement.hash
|
||||
);
|
||||
};
|
||||
|
||||
await apply(); // Warm up the module and its allocator before measuring.
|
||||
const warmedMemory = process.memoryUsage.rss();
|
||||
for (let repeat = 0; repeat < 4; repeat++) {
|
||||
await apply();
|
||||
// Measure resident memory because V8's external counter can omit WASM
|
||||
// memory after GC. The old allocator grew ~150 MiB on every call.
|
||||
const growth = process.memoryUsage.rss() - warmedMemory;
|
||||
assert(
|
||||
growth < 64 * 1024 * 1024,
|
||||
`Resident memory grew by ${growth} bytes`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("deleting the source after planning does not resurrect it", async () => {
|
||||
const f = await fixture();
|
||||
const next = structuredClone(f.database.state);
|
||||
|
|
|
|||
Loading…
Reference in a new issue