@@ -6,6 +6,7 @@ import { parse } from '@babel/parser';
66import babelGenerator from '@babel/generator' ;
77import babelTraverse from '@babel/traverse' ;
88import R from 'ramda' ;
9+ import workerpool from 'workerpool' ;
910
1011import { getEnv , isNativeSupported } from '@cubejs-backend/shared' ;
1112import { transpileJs } from '@cubejs-backend/native' ;
@@ -94,16 +95,32 @@ export class DataSchemaCompiler {
9495 const errorsReport = new ErrorReporter ( null , [ ] , this . errorReport ) ;
9596 this . errorsReport = errorsReport ;
9697
98+ const transpilationWorkerThreads = getEnv ( 'transpilationWorkerThreads' ) ;
99+ const transpilationNative = getEnv ( 'transpilationNative' ) ;
100+
101+ if ( ! transpilationNative && transpilationWorkerThreads ) {
102+ const wc = getEnv ( 'transpilationWorkerThreadsCount' ) ;
103+ this . workerPool = workerpool . pool (
104+ path . join ( __dirname , 'transpilers/transpiler_worker' ) ,
105+ wc > 0 ? { maxWorkers : wc } : undefined ,
106+ ) ;
107+ }
108+
97109 const transpile = async ( ) => {
98110 let cubeNames ;
99111 let cubeSymbols ;
100112 let transpilerNames ;
113+ let results ;
101114
102- if ( getEnv ( ' transpilationWorkerThreads' ) ) {
115+ if ( transpilationNative || transpilationWorkerThreads ) {
103116 cubeNames = Object . keys ( this . cubeDictionary . byId ) ;
104117 // We need only cubes and all its member names for transpiling.
105118 // Cubes doesn't change during transpiling, but are changed during compilation phase,
106119 // so we can prepare them once for every phase.
120+ // Communication between main and worker threads uses
121+ // The structured clone algorithm (@see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)
122+ // which doesn't allow passing any function objects, so we need to sanitize the symbols.
123+ // Communication with native backend also involves deserialization.
107124 cubeSymbols = Object . fromEntries (
108125 Object . entries ( this . cubeSymbols . symbols )
109126 . map (
@@ -112,7 +129,9 @@ export class DataSchemaCompiler {
112129 ) ] ,
113130 ) ,
114131 ) ;
132+ }
115133
134+ if ( transpilationNative ) {
116135 // Transpilers are the same for all files within phase.
117136 transpilerNames = this . transpilers . map ( t => t . constructor . name ) ;
118137
@@ -123,9 +142,14 @@ export class DataSchemaCompiler {
123142 } ;
124143
125144 await this . transpileJsFile ( dummyFile , errorsReport , { cubeNames, cubeSymbols, transpilerNames, contextSymbols : CONTEXT_SYMBOLS } ) ;
145+
146+ results = await Promise . all ( toCompile . map ( f => this . transpileFile ( f , errorsReport , { transpilerNames } ) ) ) ;
147+ } else if ( transpilationWorkerThreads ) {
148+ results = await Promise . all ( toCompile . map ( f => this . transpileFile ( f , errorsReport , { cubeNames, cubeSymbols } ) ) ) ;
149+ } else {
150+ results = await Promise . all ( toCompile . map ( f => this . transpileFile ( f , errorsReport , { } ) ) ) ;
126151 }
127152
128- const results = await Promise . all ( toCompile . map ( f => this . transpileFile ( f , errorsReport , { transpilerNames } ) ) ) ;
129153 return results . filter ( f => ! ! f ) ;
130154 } ;
131155
@@ -141,14 +165,16 @@ export class DataSchemaCompiler {
141165 contextCompilers : this . contextCompilers ,
142166 } ) )
143167 . then ( ( ) => {
144- if ( getEnv ( 'transpilationWorkerThreads' ) ) {
168+ if ( transpilationNative ) {
145169 // Clean up cache
146170 const dummyFile = {
147171 fileName : 'terminate.js' ,
148172 content : ';' ,
149173 } ;
150174
151175 return this . transpileJsFile ( dummyFile , errorsReport , { cubeNames : [ ] , cubeSymbols : { } , transpilerNames : [ ] , contextSymbols : { } } ) ;
176+ } else if ( transpilationWorkerThreads && this . workerPool ) {
177+ this . workerPool . terminate ( ) ;
152178 }
153179
154180 return Promise . resolve ( ) ;
@@ -195,7 +221,7 @@ export class DataSchemaCompiler {
195221
196222 async transpileJsFile ( file , errorsReport , { cubeNames, cubeSymbols, contextSymbols, transpilerNames } ) {
197223 try {
198- if ( getEnv ( 'transpilationWorkerThreads ' ) ) {
224+ if ( getEnv ( 'transpilationNative ' ) ) {
199225 const reqData = {
200226 fileName : file . fileName ,
201227 transpilers : transpilerNames ,
@@ -215,6 +241,20 @@ export class DataSchemaCompiler {
215241 errorsReport . exitFile ( ) ;
216242
217243 return Object . assign ( { } , file , { content : res . code } ) ;
244+ } else if ( getEnv ( 'transpilationWorkerThreads' ) ) {
245+ const data = {
246+ fileName : file . fileName ,
247+ content : file . content ,
248+ transpilers : this . transpilers . map ( t => t . constructor . name ) ,
249+ cubeNames,
250+ cubeSymbols,
251+ } ;
252+
253+ const res = await this . workerPool . exec ( 'transpile' , [ data ] ) ;
254+ errorsReport . addErrors ( res . errors ) ;
255+ errorsReport . addWarnings ( res . warnings ) ;
256+
257+ return Object . assign ( { } , file , { content : res . content } ) ;
218258 } else {
219259 const ast = parse (
220260 file . content ,
0 commit comments