perf: offload per-import localized patch to worker + cache FurnitureData parse
Per single furni import, patchLocalizedFurniDataEntries ran for every language and did a full 100k-entry JSON.parse + scan + JSON.stringify on the main thread. That CPU spike is now offloaded to the translation worker (init/prepare/finalize reuses the same pure core helpers), so importing never blocks the event loop. The main thread only does async file I/O and the network LibreTranslate calls. Falls back to the same helpers on the main thread if no worker is available. Also cache readFurniData() by file mtime+size so the 100k-entry JSON is parsed once per change instead of on every import/fix/reconcile read (invalidated on write).
This commit is contained in:
1 parent
6ed1b03e24
commit
6ae7c09682
5 files changed
+500
-224
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -199,10 +199,34 @@ export async function withFurniDataLock<T>(fn: () => Promise<T>): Promise<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cachedFurniData: {
|
||||||
|
path: string;
|
||||||
|
mtimeMs: number;
|
||||||
|
size: number;
|
||||||
|
data: Record<string, unknown>;
|
||||||
|
} | null = null;
|
||||||
|
|
||||||
export async function readFurniData(): Promise<Record<string, unknown>> {
|
export async function readFurniData(): Promise<Record<string, unknown>> {
|
||||||
const target = await getFurnitureDataReadPath();
|
const target = await getFurnitureDataReadPath();
|
||||||
|
const stat = await fs.stat(target);
|
||||||
|
if (
|
||||||
|
cachedFurniData &&
|
||||||
|
cachedFurniData.path === target &&
|
||||||
|
cachedFurniData.mtimeMs === stat.mtimeMs &&
|
||||||
|
cachedFurniData.size === stat.size
|
||||||
|
) {
|
||||||
|
// File unchanged since last parse: skip the (expensive) full JSON.parse.
|
||||||
|
return cachedFurniData.data;
|
||||||
|
}
|
||||||
const raw = await fs.readFile(/*turbopackIgnore: true*/ target, "utf-8");
|
const raw = await fs.readFile(/*turbopackIgnore: true*/ target, "utf-8");
|
||||||
return JSON.parse(raw);
|
const data = JSON.parse(raw) as Record<string, unknown>;
|
||||||
|
cachedFurniData = {
|
||||||
|
path: target,
|
||||||
|
mtimeMs: stat.mtimeMs,
|
||||||
|
size: stat.size,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function writeFurniData(
|
export async function writeFurniData(
|
||||||
@@ -216,6 +240,9 @@ export async function writeFurniData(
|
|||||||
await fs.writeFile(/*turbopackIgnore: true*/ tmp, payload, "utf-8");
|
await fs.writeFile(/*turbopackIgnore: true*/ tmp, payload, "utf-8");
|
||||||
await fs.rename(/*turbopackIgnore: true*/ tmp, target);
|
await fs.rename(/*turbopackIgnore: true*/ tmp, target);
|
||||||
}
|
}
|
||||||
|
// The file just changed: force the next read to reparse instead of serving
|
||||||
|
// a possibly-mutated cached object.
|
||||||
|
cachedFurniData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildFurniEntry(params: {
|
export function buildFurniEntry(params: {
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user