3232import com .arcadedb .query .sql .executor .ResultSet ;
3333import com .arcadedb .utility .LongLongHashMap ;
3434
35+ import com .arcadedb .query .QueryEngineManager ;
36+
3537import java .util .ArrayList ;
3638import java .util .Iterator ;
3739import java .util .List ;
3840import java .util .Locale ;
39- import java .util .concurrent .atomic .AtomicReference ;
4041import java .util .NoSuchElementException ;
4142import java .util .Set ;
43+ import java .util .concurrent .ExecutionException ;
44+ import java .util .concurrent .ExecutorService ;
45+ import java .util .concurrent .Future ;
4246
4347/**
4448 * Fused multi-hop GAV traversal operator — zero intermediate object allocation.
@@ -177,7 +181,6 @@ else if (sourceObj instanceof Vertex)
177181 // Parallel DFS: each thread processes a chunk of source vertices with its own stack
178182 @ SuppressWarnings ("unchecked" )
179183 final List <Result >[] threadResults = new List [Math .min (parallelism , Math .max (1 , (totalSources + chunkSize - 1 ) / chunkSize ))];
180- final AtomicReference <Throwable > firstError = new AtomicReference <>();
181184
182185 final int threadCount ;
183186 if (totalSources < 8192 ) {
@@ -186,8 +189,9 @@ else if (sourceObj instanceof Vertex)
186189 traverseChunk (sourceNodeIds , 0 , totalSources , hopViews , chainLength , outputNames , db , context , threadResults [0 ]);
187190 threadCount = 1 ;
188191 } else {
189- // Parallel execution
190- final Thread [] threads = new Thread [threadResults .length ];
192+ // Parallel execution using shared query worker pool
193+ final ExecutorService executor = QueryEngineManager .getInstance ().getExecutorService ();
194+ final Future <?>[] futures = new Future <?>[threadResults .length ];
191195 int launched = 0 ;
192196 for (int t = 0 ; t < threadResults .length ; t ++) {
193197 final int start = t * chunkSize ;
@@ -196,29 +200,21 @@ else if (sourceObj instanceof Vertex)
196200 break ;
197201 threadResults [t ] = new ArrayList <>();
198202 final int threadIdx = t ;
199- threads [t ] = new Thread (() -> {
200- try {
201- traverseChunk (sourceNodeIds , start , end , hopViews , chainLength , outputNames , db , context , threadResults [threadIdx ]);
202- } catch (final Throwable e ) {
203- firstError .compareAndSet (null , e );
204- }
205- });
206- threads [t ].setDaemon (true );
207- threads [t ].setName ("gav-chain-" + t );
208- threads [t ].start ();
203+ futures [t ] = executor .submit (() ->
204+ traverseChunk (sourceNodeIds , start , end , hopViews , chainLength , outputNames , db , context , threadResults [threadIdx ]));
209205 launched ++;
210206 }
211- // Wait for all threads
207+ // Wait for all tasks
212208 for (int t = 0 ; t < launched ; t ++) {
213209 try {
214- threads [t ].join ();
210+ futures [t ].get ();
215211 } catch (final InterruptedException e ) {
216212 Thread .currentThread ().interrupt ();
217213 break ;
214+ } catch (final ExecutionException e ) {
215+ throw new RuntimeException ("Parallel GAV traversal failed" , e .getCause ());
218216 }
219217 }
220- if (firstError .get () != null )
221- throw new RuntimeException ("Parallel GAV traversal failed" , (Exception ) firstError .get ());
222218 threadCount = launched ;
223219 }
224220
@@ -275,15 +271,14 @@ private ResultSet executeWithFusedAggregation(final int[] sourceNodeIds, final i
275271 final int numThreads = Math .min (parallelism , Math .max (1 , (totalSources + chunkSize - 1 ) / chunkSize ));
276272 @ SuppressWarnings ("unchecked" )
277273 final LongLongHashMap [] threadMaps = new LongLongHashMap [numThreads ];
278- final AtomicReference <Throwable > firstError = new AtomicReference <>();
279-
280274 if (totalSources < 8192 ) {
281275 // Single-threaded
282276 threadMaps [0 ] = new LongLongHashMap ();
283277 aggregateChunk (sourceNodeIds , 0 , totalSources , hopViews , chainLength , groupKeySlots , db , context , threadMaps [0 ]);
284278 } else {
285- // Parallel
286- final Thread [] threads = new Thread [numThreads ];
279+ // Parallel using shared query worker pool
280+ final ExecutorService executor = QueryEngineManager .getInstance ().getExecutorService ();
281+ final Future <?>[] futures = new Future <?>[numThreads ];
287282 int launched = 0 ;
288283 for (int t = 0 ; t < numThreads ; t ++) {
289284 final int start = t * chunkSize ;
@@ -292,28 +287,20 @@ private ResultSet executeWithFusedAggregation(final int[] sourceNodeIds, final i
292287 break ;
293288 threadMaps [t ] = new LongLongHashMap ();
294289 final int threadIdx = t ;
295- threads [t ] = new Thread (() -> {
296- try {
297- aggregateChunk (sourceNodeIds , start , end , hopViews , chainLength , groupKeySlots , db , context , threadMaps [threadIdx ]);
298- } catch (final Throwable e ) {
299- firstError .compareAndSet (null , e );
300- }
301- });
302- threads [t ].setDaemon (true );
303- threads [t ].setName ("gav-agg-" + t );
304- threads [t ].start ();
290+ futures [t ] = executor .submit (() ->
291+ aggregateChunk (sourceNodeIds , start , end , hopViews , chainLength , groupKeySlots , db , context , threadMaps [threadIdx ]));
305292 launched ++;
306293 }
307294 for (int t = 0 ; t < launched ; t ++) {
308295 try {
309- threads [t ].join ();
296+ futures [t ].get ();
310297 } catch (final InterruptedException e ) {
311298 Thread .currentThread ().interrupt ();
312299 break ;
300+ } catch (final ExecutionException e ) {
301+ throw new RuntimeException ("Parallel GAV aggregation failed" , e .getCause ());
313302 }
314303 }
315- if (firstError .get () != null )
316- throw new RuntimeException ("Parallel GAV aggregation failed" , (Exception ) firstError .get ());
317304 }
318305
319306 // Merge thread-local maps (zero boxing — primitive long operations)
0 commit comments