Skip to content

Commit 5ef9bfa

Browse files
committed
perf(materialize): add concurrent batch processing
1 parent c365787 commit 5ef9bfa

2 files changed

Lines changed: 34 additions & 20 deletions

File tree

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Deterministic local caching of documentation repositories.
1111

1212
Provides agents and automation tools with local access to Git-hosted documentation through a deterministic cache.
1313

14-
Documentation is synced locally and tracked in a lockfile, reusing existing copies when the resolved commit is unchanged.
14+
Documentation is synced locally, reused when unchanged, and exposed through configurable symlinks for different tools and agents.
1515

1616
## Features
1717

@@ -109,4 +109,3 @@ Use `postinstall` to ensure docs are ready for local agents immediately after in
109109
## License
110110

111111
MIT
112-

src/materialize.ts

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -104,17 +104,38 @@ export const materializeSource = async (params: MaterializeParams) => {
104104
);
105105
let bytes = 0;
106106
const manifest: Array<{ path: string; size: number }> = [];
107+
const concurrency = 64;
107108

108-
for (const relativePath of files) {
109-
const relNormalized = normalizePath(relativePath);
110-
const filePath = path.join(params.repoDir, relativePath);
111-
const fileHandle = await openFileNoFollow(filePath);
112-
if (!fileHandle) {
113-
continue;
114-
}
115-
try {
116-
const stats = await fileHandle.stat();
117-
if (!stats.isFile()) {
109+
for (let i = 0; i < files.length; i += concurrency) {
110+
const batch = files.slice(i, i + concurrency);
111+
const results = await Promise.all(
112+
batch.map(async (relativePath) => {
113+
const relNormalized = normalizePath(relativePath);
114+
const filePath = path.join(params.repoDir, relativePath);
115+
const fileHandle = await openFileNoFollow(filePath);
116+
if (!fileHandle) {
117+
return null;
118+
}
119+
try {
120+
const stats = await fileHandle.stat();
121+
if (!stats.isFile()) {
122+
return null;
123+
}
124+
const targetPath = path.join(tempDir, relativePath);
125+
ensureSafePath(tempDir, targetPath);
126+
const data = await fileHandle.readFile();
127+
await writeFile(targetPath, data);
128+
return {
129+
path: relNormalized,
130+
size: stats.size,
131+
};
132+
} finally {
133+
await fileHandle.close();
134+
}
135+
}),
136+
);
137+
for (const entry of results) {
138+
if (!entry) {
118139
continue;
119140
}
120141
if (
@@ -125,19 +146,13 @@ export const materializeSource = async (params: MaterializeParams) => {
125146
`Materialized content exceeds maxFiles (${params.maxFiles}).`,
126147
);
127148
}
128-
bytes += stats.size;
149+
bytes += entry.size;
129150
if (bytes > params.maxBytes) {
130151
throw new Error(
131152
`Materialized content exceeds maxBytes (${params.maxBytes}).`,
132153
);
133154
}
134-
const targetPath = path.join(tempDir, relativePath);
135-
ensureSafePath(tempDir, targetPath);
136-
const data = await fileHandle.readFile();
137-
await writeFile(targetPath, data);
138-
manifest.push({ path: relNormalized, size: stats.size });
139-
} finally {
140-
await fileHandle.close();
155+
manifest.push(entry);
141156
}
142157
}
143158

0 commit comments

Comments
 (0)