Skip to content

Commit be6439b

Browse files
committed
implement bulk transpileJsFiles in native
1 parent db1b275 commit be6439b

File tree

1 file changed

+74
-1
lines changed

1 file changed

+74
-1
lines changed

packages/cubejs-schema-compiler/src/compiler/DataSchemaCompiler.js

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import vm from 'vm';
22
import fs from 'fs';
3+
import os from 'os';
34
import path from 'path';
45
import syntaxCheck from 'syntax-error';
56
import { parse } from '@babel/parser';
@@ -20,6 +21,20 @@ const moduleFileCache = {};
2021

2122
const JINJA_SYNTAX = /{%|%}|{{|}}/ig;
2223

24+
const getThreadsCount = () => {
25+
const envThreads = getEnv('transpilationWorkerThreadsCount');
26+
if (envThreads > 0) {
27+
return envThreads;
28+
}
29+
30+
const cpuCount = os.cpus()?.length;
31+
if (cpuCount) {
32+
return Math.max(1, cpuCount - 1);
33+
}
34+
35+
return 3; // Default (like the workerpool do)
36+
};
37+
2338
export class DataSchemaCompiler {
2439
constructor(repository, options = {}) {
2540
this.repository = repository;
@@ -98,6 +113,7 @@ export class DataSchemaCompiler {
98113

99114
const transpilationWorkerThreads = getEnv('transpilationWorkerThreads');
100115
const transpilationNative = getEnv('transpilationNative');
116+
const transpilationNativeThreadsCount = getThreadsCount();
101117
const { compilerId } = this;
102118

103119
if (!transpilationNative && transpilationWorkerThreads) {
@@ -149,7 +165,26 @@ export class DataSchemaCompiler {
149165

150166
await this.transpileJsFile(dummyFile, errorsReport, { cubeNames, cubeSymbols, transpilerNames, contextSymbols: CONTEXT_SYMBOLS, compilerId, stage });
151167

152-
results = await Promise.all(toCompile.map(f => this.transpileFile(f, errorsReport, { transpilerNames, compilerId })));
168+
const nonJsFilesTasks = toCompile.filter(file => !file.fileName.endsWith('.js'))
169+
.map(f => this.transpileFile(f, errorsReport, { transpilerNames, compilerId }));
170+
171+
const jsFiles = toCompile.filter(file => file.fileName.endsWith('.js'));
172+
let jsChunks;
173+
if (jsFiles.length < transpilationNativeThreadsCount * transpilationNativeThreadsCount) {
174+
jsChunks = [jsFiles];
175+
} else {
176+
const baseSize = Math.floor(jsFiles.length / transpilationNativeThreadsCount);
177+
jsChunks = [];
178+
for (let i = 0; i < transpilationNativeThreadsCount; i++) {
179+
// For the last part, we take the remaining files so we don't lose the extra ones.
180+
const start = i * baseSize;
181+
const end = (i === transpilationNativeThreadsCount - 1) ? jsFiles.length : start + baseSize;
182+
jsChunks.push(jsFiles.slice(start, end));
183+
}
184+
}
185+
const JsFilesTasks = jsChunks.map(chunk => this.transpileJsFilesBulk(chunk, errorsReport, { transpilerNames, compilerId }));
186+
187+
results = (await Promise.all([...nonJsFilesTasks, ...JsFilesTasks])).flat();
153188
} else if (transpilationWorkerThreads) {
154189
results = await Promise.all(toCompile.map(f => this.transpileFile(f, errorsReport, { cubeNames, cubeSymbols, transpilerNames })));
155190
} else {
@@ -229,6 +264,44 @@ export class DataSchemaCompiler {
229264
}
230265
}
231266

267+
/**
268+
* Right now it is used only for transpilation in native,
269+
* so no checks for transpilation type inside this method
270+
*/
271+
async transpileJsFilesBulk(files, errorsReport, { cubeNames, cubeSymbols, contextSymbols, transpilerNames, compilerId, stage }) {
272+
// for bulk processing this data may be optimized even more by passing transpilerNames, compilerId only once for a bulk
273+
// but this requires more complex logic to be implemented in the native side.
274+
// And comparing to the file content sizes, a few bytes of JSON data is not a big deal here
275+
const reqDataArr = files.map(file => ({
276+
fileName: file.fileName,
277+
fileContent: file.content,
278+
transpilers: transpilerNames,
279+
compilerId,
280+
...(cubeNames && {
281+
metaData: {
282+
cubeNames,
283+
cubeSymbols,
284+
contextSymbols,
285+
stage
286+
},
287+
}),
288+
}));
289+
const res = await transpileJs(reqDataArr);
290+
291+
return files.map((file, index) => {
292+
errorsReport.inFile(file);
293+
if (!res[index]) { // This should not happen in theory but just to be safe
294+
errorsReport.error(`No transpilation result received for the file ${file.fileName}.`);
295+
return undefined;
296+
}
297+
errorsReport.addErrors(res[index].errors);
298+
errorsReport.addWarnings(res[index].warnings);
299+
errorsReport.exitFile();
300+
301+
return { ...file, content: res[index].code };
302+
});
303+
}
304+
232305
async transpileJsFile(file, errorsReport, { cubeNames, cubeSymbols, contextSymbols, transpilerNames, compilerId, stage }) {
233306
try {
234307
if (getEnv('transpilationNative')) {

0 commit comments

Comments
 (0)