Skip to content

Commit cb148a9

Browse files
committed
implement bulk transpileJsFiles in native
1 parent aadcc2e commit cb148a9

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,6 +1,7 @@
11
import crypto from 'crypto';
22
import vm from 'vm';
33
import fs from 'fs';
4+
import os from 'os';
45
import path from 'path';
56
import syntaxCheck from 'syntax-error';
67
import { parse } from '@babel/parser';
@@ -21,6 +22,20 @@ const moduleFileCache = {};
2122

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

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

101116
const transpilationWorkerThreads = getEnv('transpilationWorkerThreads');
102117
const transpilationNative = getEnv('transpilationNative');
118+
const transpilationNativeThreadsCount = getThreadsCount();
103119
const { compilerId } = this;
104120

105121
if (!transpilationNative && transpilationWorkerThreads) {
@@ -151,7 +167,26 @@ export class DataSchemaCompiler {
151167

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

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

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

0 commit comments

Comments
 (0)