Skip to content

Commit 471681e

Browse files
committed
wip: worker forks for indexers
1 parent 26bea3c commit 471681e

File tree

16 files changed

+385
-116
lines changed

16 files changed

+385
-116
lines changed

esbuild.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,24 @@ async function main() {
7777
plugins: [esbuildProblemMatcherPlugin, copyAssetsPlugin],
7878
});
7979

80+
// Worker build context
81+
const workerCtx = await esbuild.context({
82+
entryPoints: ['src/indexer/IndexWorker.ts'],
83+
bundle: true,
84+
format: 'cjs',
85+
minify: production,
86+
sourcemap: !production,
87+
sourcesContent: false,
88+
platform: 'node',
89+
outdir: 'dist/indexer',
90+
define: {
91+
'process.env.NODE_ENV': JSON.stringify(production ? 'production' : 'development'),
92+
},
93+
external: ['vscode'],
94+
logLevel: 'silent',
95+
plugins: [esbuildProblemMatcherPlugin],
96+
});
97+
8098
// Webview build context
8199
const webviewCtx = await esbuild.context({
82100
entryPoints: ['src/webview/index.tsx'],
@@ -98,10 +116,10 @@ async function main() {
98116
});
99117

100118
if (watch) {
101-
await Promise.all([extensionCtx.watch(), webviewCtx.watch()]);
119+
await Promise.all([extensionCtx.watch(), workerCtx.watch(), webviewCtx.watch()]);
102120
} else {
103-
await Promise.all([extensionCtx.rebuild(), webviewCtx.rebuild()]);
104-
await Promise.all([extensionCtx.dispose(), webviewCtx.dispose()]);
121+
await Promise.all([extensionCtx.rebuild(), workerCtx.rebuild(), webviewCtx.rebuild()]);
122+
await Promise.all([extensionCtx.dispose(), workerCtx.dispose(), webviewCtx.dispose()]);
105123
}
106124
}
107125

indexer.log

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[INDEXER] Indexing di.xml
2+
[INDEXER] Discovering files to index
3+
[INDEXER] Found 271 files to index in 255 ms
4+
[INDEXER] Indexed 271 files of 271 in 935ms
5+
[INDEXER] Indexing di.xml done in 1198 ms
6+
[INDEXER] Indexing module.xml
7+
[INDEXER] Discovering files to index
8+
[INDEXER] Found 435 files to index in 1228 ms
9+
[INDEXER] Indexed 435 files of 435 in 1789ms
10+
[INDEXER] Indexing module.xml done in 3018 ms
11+
[INDEXER] Indexing namespaces
12+
[INDEXER] Discovering files to index
13+
[INDEXER] Found 716 files to index in 1149 ms
14+
[Indexed] 500 files of 716
15+
[INDEXER] Indexed 716 files of 716 in 11581ms
16+
[INDEXER] Indexing namespaces done in 12755 ms
17+
[INDEXER] Indexing events.xml
18+
[INDEXER] Discovering files to index
19+
[INDEXER] Found 45 files to index in 1140 ms
20+
[INDEXER] Indexed 45 files of 45 in 121ms
21+
[INDEXER] Indexing events.xml done in 1262 ms
22+
[INDEXER] Indexing acl.xml
23+
[INDEXER] Discovering files to index
24+
[INDEXER] Found 81 files to index in 2298 ms
25+
[INDEXER] Indexed 81 files of 81 in 697ms
26+
[INDEXER] Indexing acl.xml done in 2996 ms
27+
[INDEXER] Indexing templates
28+
[INDEXER] Discovering files to index
29+
[INDEXER] Found 1020 files to index in 1258 ms
30+
[Indexed] 500 files of 1020
31+
[Indexed] 1000 files of 1020
32+
[INDEXER] Indexed 1020 files of 1020 in 443ms
33+
[INDEXER] Indexing templates done in 1704 ms
34+
[INDEXER] Indexing crontab.xml
35+
[INDEXER] Discovering files to index
36+
[INDEXER] Found 29 files to index in 1261 ms
37+
[INDEXER] Indexed 29 files of 29 in 60ms
38+
[INDEXER] Indexing crontab.xml done in 1323 ms
39+
[INDEXER] Finished indexing workspace magento-demo

package-lock.json

Lines changed: 63 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@
431431
"@xml-tools/validation": "^1.0.16",
432432
"cronstrue": "^2.59.0",
433433
"fast-xml-parser": "^4.5.1",
434+
"fdir": "^6.4.6",
434435
"formik": "^2.4.6",
435436
"glob": "^11.0.1",
436437
"handlebars": "^4.7.8",
@@ -444,6 +445,7 @@
444445
"slugify": "^1.6.6",
445446
"typescript-json-serializer": "^6.0.1",
446447
"typescript-memoize": "^1.1.1",
447-
"validatorjs": "^3.22.1"
448+
"validatorjs": "^3.22.1",
449+
"vscode-uri": "^3.1.0"
448450
}
449451
}

src/indexer/IndexManager.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Progress, Uri, workspace, WorkspaceFolder } from 'vscode';
1+
import { Progress, RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode';
22
import { Indexer } from './Indexer';
33
import Common from 'util/Common';
44
import { minimatch } from 'minimatch';
@@ -20,7 +20,7 @@ import TemplateIndexer from './template/TemplateIndexer';
2020
import { TemplateIndexData } from './template/TemplateIndexData';
2121
import CronIndexer from './cron/CronIndexer';
2222
import { CronIndexData } from './cron/CronIndexData';
23-
import Config from 'common/Config';
23+
import { IndexWorkerManager } from './IndexWorkerManager';
2424

2525
type IndexerInstance =
2626
| DiIndexer
@@ -42,11 +42,12 @@ type IndexerDataMap = {
4242
};
4343

4444
class IndexManager {
45-
private static readonly INDEXING_BATCH_SIZE = 50;
45+
private static readonly INDEXING_BATCH_SIZE = 200;
4646
private static readonly REPORTING_BATCH_SIZE = 500;
4747

4848
protected indexers: IndexerInstance[] = [];
4949
protected indexStorage: IndexStorage;
50+
protected workerManager: IndexWorkerManager;
5051

5152
public constructor() {
5253
this.indexers = [
@@ -59,6 +60,7 @@ class IndexManager {
5960
new CronIndexer(),
6061
];
6162
this.indexStorage = new IndexStorage();
63+
this.workerManager = new IndexWorkerManager();
6264
}
6365

6466
public getIndexers(): IndexerInstance[] {
@@ -99,11 +101,13 @@ class IndexManager {
99101
const startDiscover = Date.now();
100102
Logger.log('INDEXER', 'Discovering files to index');
101103

102-
const files = await workspace.findFiles(
103-
indexer.getPattern(workspaceUri),
104-
indexer.getExcludePattern(workspaceUri)
104+
const indexPattern = new RelativePattern(workspaceUri, indexer.getPattern());
105+
const indexExcludePattern = new RelativePattern(
106+
workspaceUri,
107+
indexer.getExcludePattern() ?? ''
105108
);
106109

110+
const files = await workspace.findFiles(indexPattern, indexExcludePattern);
107111
const discoverDuration = Date.now() - startDiscover;
108112
Logger.log('INDEXER', 'Found', files.length, 'files to index in', discoverDuration, 'ms');
109113

@@ -114,21 +118,12 @@ class IndexManager {
114118

115119
for (let i = 0; i < files.length; i += IndexManager.INDEXING_BATCH_SIZE) {
116120
const batch = files.slice(i, i + IndexManager.INDEXING_BATCH_SIZE);
121+
const batchResult = await this.workerManager.processBatch(indexer, batch, workspaceUri);
117122

118-
const promises = batch.map(async file => {
119-
try {
120-
const data = await indexer.indexFile(file);
121-
122-
if (data !== undefined) {
123-
indexData.set(file.fsPath, data);
124-
}
125-
} catch (error) {
126-
Logger.error('Error indexing file', file.fsPath, String(error));
127-
}
123+
batchResult.forEach((data, filePath) => {
124+
indexData.set(filePath, data);
128125
});
129126

130-
await Promise.all(promises);
131-
132127
doneCount += batch.length;
133128

134129
if (doneCount % IndexManager.REPORTING_BATCH_SIZE === 0) {
@@ -235,11 +230,10 @@ class IndexManager {
235230
indexer: Indexer
236231
): Promise<void> {
237232
const indexData = this.getIndexStorageData(indexer.getId()) || new Map();
238-
const pattern = indexer.getPattern(workspaceFolder.uri);
239-
const patternString = typeof pattern === 'string' ? pattern : pattern.pattern;
233+
const pattern = indexer.getPattern();
240234

241-
if (minimatch(file.fsPath, patternString, { matchBase: true })) {
242-
const data = await indexer.indexFile(file);
235+
if (minimatch(file.fsPath, pattern, { matchBase: true })) {
236+
const data = await indexer.indexFile(file.fsPath);
243237

244238
if (data !== undefined) {
245239
indexData.set(file.fsPath, data);

src/indexer/IndexWorker.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { Indexer } from './Indexer';
2+
import DiIndexer from './di/DiIndexer';
3+
import ModuleIndexer from './module/ModuleIndexer';
4+
import AutoloadNamespaceIndexer from './autoload-namespace/AutoloadNamespaceIndexer';
5+
import EventsIndexer from './events/EventsIndexer';
6+
import AclIndexer from './acl/AclIndexer';
7+
import TemplateIndexer from './template/TemplateIndexer';
8+
import CronIndexer from './cron/CronIndexer';
9+
10+
export interface WorkerMessage {
11+
type: 'batch';
12+
indexerId: string;
13+
files: string[];
14+
workspaceUri: string;
15+
}
16+
17+
export interface WorkerResult {
18+
success: boolean;
19+
indexData: { [filePath: string]: any };
20+
error?: string;
21+
}
22+
23+
// Map of indexer IDs to their classes
24+
const indexerMap = {
25+
[DiIndexer.KEY]: DiIndexer,
26+
[ModuleIndexer.KEY]: ModuleIndexer,
27+
[AutoloadNamespaceIndexer.KEY]: AutoloadNamespaceIndexer,
28+
[EventsIndexer.KEY]: EventsIndexer,
29+
[AclIndexer.KEY]: AclIndexer,
30+
[TemplateIndexer.KEY]: TemplateIndexer,
31+
[CronIndexer.KEY]: CronIndexer,
32+
};
33+
34+
async function processBatch(message: WorkerMessage): Promise<WorkerResult> {
35+
try {
36+
const IndexerClass = indexerMap[message.indexerId as keyof typeof indexerMap];
37+
38+
if (!IndexerClass) {
39+
throw new Error(`Unknown indexer: ${message.indexerId}`);
40+
}
41+
42+
const indexer: Indexer = new IndexerClass();
43+
const indexData: { [filePath: string]: any } = {};
44+
45+
console.log(
46+
`WORKER: Processing batch of ${message.files.length} files for ${indexer.getName()}`
47+
);
48+
49+
for (const filePath of message.files) {
50+
try {
51+
const data = await indexer.indexFile(filePath);
52+
53+
if (data !== undefined) {
54+
indexData[filePath] = data;
55+
}
56+
} catch (error) {
57+
console.error('WORKER: Error indexing file', filePath, String(error));
58+
}
59+
}
60+
61+
return {
62+
success: true,
63+
indexData,
64+
};
65+
} catch (error) {
66+
return {
67+
success: false,
68+
indexData: {},
69+
error: String(error),
70+
};
71+
}
72+
}
73+
74+
// Handle messages from the main thread (child process)
75+
if (process.send) {
76+
process.on('message', async (message: WorkerMessage) => {
77+
if (message.type === 'batch') {
78+
const result = await processBatch(message);
79+
process.send!(result);
80+
}
81+
});
82+
}

0 commit comments

Comments
 (0)