Source:
public ResultIterator iterator() throws SQLException { ImmutableBytesPtr[] joinIds = joinInfo.getJoinIds(); assert (joinIds.length == hashExpressions.length && joinIds.length == hashPlans.length); final HashCacheClient hashClient = new HashCacheClient(plan.getContext().getConnection()); Scan scan = plan.getContext().getScan(); final ScanRanges ranges = plan.getContext().getScanRanges(); final int count = joinIds.length; final ConnectionQueryServices services = getContext().getConnection().getQueryServices(); final ExecutorService executor = services.getExecutor(); List<Future<Pair<ResultIterator, ServerCache>>> futures = new ArrayList<Future<Pair<ResultIterator, ServerCache>>>(count); final List<SQLCloseable> dependencies = new ArrayList<SQLCloseable>(count); for (int i = 0; i < count; i++) { final int index = i; futures.add(executor.submit(new JobCallable<Pair<ResultIterator, ServerCache>>() { @Override public Pair<ResultIterator, ServerCache> call() throws Exception { QueryPlan hashPlan = hashPlans[index]; ResultIterator iterator = hashPlan.iterator(); ServerCache cache = hashClient.addHashCache(ranges, iterator, hashPlan.getEstimatedSize(), hashExpressions[index], plan.getTableRef()); return new Pair<ResultIterator, ServerCache>(iterator, cache); } @Override public Object getJobId() { return HashJoinPlan.this; } })); } for (int i = 0; i < count; i++) { try { Pair<ResultIterator, ServerCache> result = futures.get(i).get(); joinIds[i].set(result.getSecond().getId()); dependencies.add(result.getFirst()); dependencies.add(result.getSecond()); } catch (InterruptedException e) { throw new SQLException("Hash join execution interrupted.", e); } catch (ExecutionException e) { throw new SQLException("Encountered exception in hash plan execution.", e.getCause()); } } HashJoinInfo.serializeHashJoinIntoScan(scan, joinInfo); return plan.iterator(dependencies); }

Target:
public ResultIterator iterator() throws SQLException { ImmutableBytesPtr[] joinIds = joinInfo.getJoinIds(); assert (joinIds.length == hashExpressions.length && joinIds.length == hashPlans.length); final HashCacheClient hashClient = new HashCacheClient(plan.getContext().getConnection()); Scan scan = plan.getContext().getScan(); final ScanRanges ranges = plan.getContext().getScanRanges(); int count = joinIds.length; ConnectionQueryServices services = getContext().getConnection().getQueryServices(); ExecutorService executor = services.getExecutor(); List<Future<ServerCache>> futures = new ArrayList<Future<ServerCache>>(count); List<SQLCloseable> dependencies = new ArrayList<SQLCloseable>(count); for (int i = 0; i < count; i++) { final int index = i; futures.add(executor.submit(new JobCallable<ServerCache>() { @Override public ServerCache call() throws Exception { QueryPlan hashPlan = hashPlans[index]; return hashClient.addHashCache(ranges, hashPlan.iterator(), hashPlan.getEstimatedSize(), hashExpressions[index], plan.getTableRef()); } @Override public Object getJobId() { return HashJoinPlan.this; } })); } for (int i = 0; i < count; i++) { try { ServerCache cache = futures.get(i).get(); joinIds[i].set(cache.getId()); dependencies.add(cache); } catch (InterruptedException e) { throw new SQLException("Hash join execution interrupted.", e); } catch (ExecutionException e) { throw new SQLException("Encountered exception in hash plan execution.", e.getCause()); } } HashJoinInfo.serializeHashJoinIntoScan(scan, joinInfo); return plan.iterator(dependencies); }