Source:
protected <C extends TopologyAffectedCommand & FlagAffectedCommand> Object handleFunctionalReadManyCommand( InvocationContext ctx, C command, ReadManyCommandHelper<C> helper) { if (command.hasAnyFlag(FlagBitSets.CACHE_MODE_LOCAL | FlagBitSets.SKIP_REMOTE_LOOKUP)) { return handleLocalOnlyReadManyCommand(ctx, command, helper.keys(command)); } LocalizedCacheTopology cacheTopology = checkTopologyId(command); Collection<?> keys = helper.keys(command); if (!ctx.isOriginLocal()) { return handleRemoteReadManyCommand(ctx, command, keys, helper); } if (keys.isEmpty()) { return Stream.empty(); } ConsistentHash ch = cacheTopology.getReadConsistentHash(); int estimateForOneNode = 2 * keys.size() / ch.getMembers().size(); List<Object> availableKeys = new ArrayList<>(estimateForOneNode); Map<Address, List<Object>> requestedKeys = getKeysByOwner(ctx, keys, cacheTopology, availableKeys, null); MergingCompletableFuture<Object> allFuture = new MergingCompletableFuture<>( requestedKeys.size() + (availableKeys.isEmpty() ? 0 : 1), new Object[keys.size()], helper::transformResult); handleLocallyAvailableKeys(ctx, command, availableKeys, allFuture, helper); int pos = availableKeys.size(); for (Map.Entry<Address, List<Object>> addressKeys : requestedKeys.entrySet()) { List<Object> keysForAddress = addressKeys.getValue(); ReadOnlyManyCommand remoteCommand = helper.copyForRemote(command, keysForAddress, ctx); remoteCommand.setTopologyId(command.getTopologyId()); Address target = addressKeys.getKey(); rpcManager.invokeCommand(target, remoteCommand, new MapResponseCollector(true, 1), rpcManager.getSyncRpcOptions()) .whenComplete( new ReadManyHandler(target, allFuture, ctx, command, keysForAddress, null, pos, helper)); pos += keysForAddress.size(); } return asyncValue(allFuture); }

Target:
protected <C extends TopologyAffectedCommand & FlagAffectedCommand> Object handleFunctionalReadManyCommand( InvocationContext ctx, C command, ReadManyCommandHelper<C> helper) { if (command.hasAnyFlag(FlagBitSets.CACHE_MODE_LOCAL | FlagBitSets.SKIP_REMOTE_LOOKUP)) { return handleLocalOnlyReadManyCommand(ctx, command, helper.keys(command)); } LocalizedCacheTopology cacheTopology = checkTopologyId(command); Collection<?> keys = helper.keys(command); if (!ctx.isOriginLocal()) { return handleRemoteReadManyCommand(ctx, command, keys, helper); } if (keys.isEmpty()) { return Stream.empty(); } ConsistentHash ch = cacheTopology.getReadConsistentHash(); int estimateForOneNode = 2 * keys.size() / ch.getMembers().size(); List<Object> availableKeys = new ArrayList<>(estimateForOneNode); Map<Address, List<Object>> requestedKeys = getKeysByOwner(ctx, keys, cacheTopology, availableKeys, null); MergingCompletableFuture<Object> allFuture = new MergingCompletableFuture<>( requestedKeys.size() + (availableKeys.isEmpty() ? 0 : 1), new Object[keys.size()], helper::transformResult); handleLocallyAvailableKeys(ctx, command, availableKeys, allFuture, helper); int pos = availableKeys.size(); for (Map.Entry<Address, List<Object>> addressKeys : requestedKeys.entrySet()) { List<Object> keysForAddress = addressKeys.getValue(); ReadOnlyManyCommand remoteCommand = helper.copyForRemote(command, keysForAddress, ctx); remoteCommand.setTopologyId(command.getTopologyId()); Address target = addressKeys.getKey(); rpcManager.invokeCommand(target, remoteCommand, SingletonMapResponseCollector.ignoreLeavers(), rpcManager.getSyncRpcOptions()) .whenComplete( new ReadManyHandler(target, allFuture, ctx, command, keysForAddress, null, pos, helper)); pos += keysForAddress.size(); } return asyncValue(allFuture); }