diff --git a/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java b/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java index 5ff7ee70..72bb5f38 100644 --- a/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java +++ b/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java @@ -4,8 +4,10 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -69,6 +71,8 @@ public abstract class AbstractTarantoolClient metadataHolder = new AtomicReference<>(); private final ResultMapperFactoryFactoryImpl mapperFactoryFactory; + private final Map argumentsMapperCache; + private final Map resultMapperCache; private final SpacesMetadataProvider metadataProvider; private final ScheduledExecutorService timeoutScheduler; @@ -114,6 +118,8 @@ public AbstractTarantoolClient(TarantoolClientConfig config, TarantoolConnection this.config = config; this.mapperFactoryFactory = new ResultMapperFactoryFactoryImpl(); + this.argumentsMapperCache = new ConcurrentHashMap<>(); + this.resultMapperCache = new ConcurrentHashMap<>(); this.eventLoopGroup = new NioEventLoopGroup(config.getEventLoopThreadsNumber()); this.bootstrap = new Bootstrap() .group(eventLoopGroup) @@ -242,7 +248,8 @@ public CompletableFuture> call(String functionName, List arguments) private CompletableFuture> call(String functionName, List arguments, MessagePackMapper mapper) throws TarantoolClientException { - return makeRequest(functionName, arguments, null, () -> mapper, () -> mapper); + TarantoolRequestSignature signature = TarantoolRequestSignature.create(functionName, arguments, List.class); + return makeRequest(functionName, arguments, signature, () -> mapper, () -> mapper); } @Override @@ -282,7 +289,8 @@ public CompletableFuture> callForTupleResult( Supplier argumentsMapperSupplier, Class tupleClass) throws TarantoolClientException { - return call(functionName, arguments, argumentsMapperSupplier, + TarantoolRequestSignature signature = TarantoolRequestSignature.create(functionName, arguments, tupleClass); + return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, () -> mapperFactoryFactory.getTarantoolResultMapper(config.getMessagePackMapper(), tupleClass)); } @@ -348,8 +356,10 @@ public CompletableFuture callForSingleResult( Supplier argumentsMapperSupplier, Class resultClass) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, argumentsMapperSupplier, - () -> mapperFactoryFactory.getDefaultSingleValueMapper(config.getMessagePackMapper(), resultClass)); + TarantoolRequestSignature signature = TarantoolRequestSignature.create(functionName, arguments, resultClass); + return callForSingleResult( + functionName, arguments, signature, argumentsMapperSupplier, + () -> mapperFactoryFactory.getDefaultSingleValueMapper(config.getMessagePackMapper(), resultClass)); } @Override @@ -359,10 +369,24 @@ public CompletableFuture callForSingleResult( Supplier argumentsMapperSupplier, ValueConverter valueConverter) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, argumentsMapperSupplier, + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + functionName, arguments, valueConverter.getClass()); + return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, () -> mapperFactoryFactory.getSingleValueResultMapper(valueConverter)); } + private CompletableFuture callForSingleResult( + String functionName, + List arguments, + TarantoolRequestSignature signature, + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) + throws TarantoolClientException { + return makeRequestForSingleResult( + functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier) + .thenApply(CallResult::value); + } + @Override public CompletableFuture callForSingleResult( String functionName, @@ -370,7 +394,8 @@ public CompletableFuture callForSingleResult( Supplier argumentsMapperSupplier, Supplier>> resultMapperSupplier) throws TarantoolClientException { - return makeRequestForSingleResult(functionName, arguments, null, argumentsMapperSupplier, resultMapperSupplier) + return makeRequestForSingleResult( + functionName, arguments, null, argumentsMapperSupplier, resultMapperSupplier) .thenApply(CallResult::value); } @@ -438,7 +463,8 @@ public > CompletableFuture callForMultiResult( Supplier resultContainerSupplier, Class resultClass) throws TarantoolClientException { - return callForMultiResult(functionName, arguments, argumentsMapperSupplier, + TarantoolRequestSignature signature = TarantoolRequestSignature.create(functionName, arguments, resultClass); + return callForMultiResult(functionName, arguments, signature, argumentsMapperSupplier, () -> mapperFactoryFactory.getDefaultMultiValueMapper(config.getMessagePackMapper(), resultClass)); } @@ -450,10 +476,24 @@ public > CompletableFuture callForMultiResult( Supplier resultContainerSupplier, ValueConverter valueConverter) throws TarantoolClientException { - return callForMultiResult(functionName, arguments, argumentsMapperSupplier, + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + functionName, arguments, valueConverter.getClass()); + return callForMultiResult(functionName, arguments, signature, argumentsMapperSupplier, () -> mapperFactoryFactory.getMultiValueResultMapper(resultContainerSupplier, valueConverter)); } + private > CompletableFuture callForMultiResult( + String functionName, + List arguments, + TarantoolRequestSignature signature, + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) + throws TarantoolClientException { + return makeRequestForMultiResult( + functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier) + .thenApply(CallResult::value); + } + @Override public > CompletableFuture callForMultiResult( String functionName, @@ -498,9 +538,14 @@ private CompletableFuture makeRequest( builder.withArguments(arguments); } builder.withSignature(requestSignature); - MessagePackValueMapper resultMapper = resultMapperSupplier.get(); - - TarantoolCallRequest request = builder.build(argumentsMapperSupplier.get()); + MessagePackObjectMapper argumentsMapper = requestSignature != null ? + argumentsMapperCache.computeIfAbsent(requestSignature, s -> argumentsMapperSupplier.get()) : + argumentsMapperSupplier.get(); + MessagePackValueMapper resultMapper = requestSignature != null ? + resultMapperCache.computeIfAbsent(requestSignature, s -> resultMapperSupplier.get()) : + resultMapperSupplier.get(); + + TarantoolCallRequest request = builder.build(argumentsMapper); return connectionManager().getConnection() .thenCompose(c -> c.sendRequest(request).getFuture()) .thenApply(resultMapper::fromValue); @@ -540,11 +585,16 @@ public CompletableFuture> eval( Supplier argumentsMapperSupplier, Supplier resultMapperSupplier) throws TarantoolClientException { try { + TarantoolRequestSignature signature = TarantoolRequestSignature.create(expression, arguments, List.class); + MessagePackObjectMapper argumentsMapper = argumentsMapperCache.computeIfAbsent( + signature, s -> argumentsMapperSupplier.get()); + MessagePackValueMapper resultMapper = resultMapperCache.computeIfAbsent( + signature, s -> resultMapperSupplier.get()); TarantoolEvalRequest request = new TarantoolEvalRequest.Builder() .withExpression(expression) .withArguments(arguments) - .build(argumentsMapperSupplier.get()); - MessagePackValueMapper resultMapper = resultMapperSupplier.get(); + .withSignature(signature) + .build(argumentsMapper); return connectionManager().getConnection() .thenCompose(c -> c.sendRequest(request).getFuture()) .thenApply(resultMapper::fromValue); diff --git a/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java b/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java index c69896b5..5700e328 100644 --- a/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java @@ -18,6 +18,7 @@ import io.tarantool.driver.protocol.TarantoolIndexQuery; import io.tarantool.driver.protocol.TarantoolProtocolException; import io.tarantool.driver.protocol.TarantoolRequest; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.requests.TarantoolCallRequest; import io.tarantool.driver.protocol.requests.TarantoolDeleteRequest; import io.tarantool.driver.protocol.requests.TarantoolInsertRequest; @@ -28,7 +29,9 @@ import org.msgpack.value.ArrayValue; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -47,6 +50,7 @@ public abstract class TarantoolSpace private final TarantoolConnectionManager connectionManager; private final TarantoolSpaceMetadata spaceMetadata; private final TarantoolMetadataOperations metadataOperations; + private final Map methodSignatures; public TarantoolSpace( TarantoolClientConfig config, @@ -58,6 +62,28 @@ public TarantoolSpace( this.connectionManager = connectionManager; this.spaceMetadata = spaceMetadata; this.metadataOperations = metadataOperations; + this.methodSignatures = new HashMap<>(); + String spaceIdStr = String.valueOf(this.spaceId); + methodSignatures.put( + TarantoolDeleteRequest.class.getName(), + new TarantoolRequestSignature(spaceIdStr, TarantoolDeleteRequest.class.getName())); + methodSignatures.put( + TarantoolInsertRequest.class.getName(), + new TarantoolRequestSignature(spaceIdStr, TarantoolInsertRequest.class.getName())); + methodSignatures.put( + TarantoolReplaceRequest.class.getName(), + new TarantoolRequestSignature(spaceIdStr, TarantoolReplaceRequest.class.getName())); + methodSignatures.put( + TarantoolSelectRequest.class.getName(), + new TarantoolRequestSignature(spaceIdStr, TarantoolSelectRequest.class.getName())); + methodSignatures.put( + TarantoolUpdateRequest.class.getName(), + new TarantoolRequestSignature(spaceIdStr, TarantoolUpdateRequest.class.getName())); + methodSignatures.put( + TarantoolUpsertRequest.class.getName(), + new TarantoolRequestSignature(spaceIdStr, TarantoolUpsertRequest.class.getName())); + methodSignatures.put( + "truncate", new TarantoolRequestSignature(spaceIdStr, "truncate", TarantoolCallRequest.class.getName())); } @Override @@ -74,6 +100,7 @@ private CompletableFuture delete(Conditions conditions, Supplier insert(T tuple, Supplier re TarantoolInsertRequest request = new TarantoolInsertRequest.Builder() .withSpaceId(spaceId) .withTuple(tuple) + .withSignature(methodSignatures.get(TarantoolInsertRequest.class.getName())) .build(config.getMessagePackMapper()); return sendRequest(request, resultMapperSupplier); @@ -128,6 +156,7 @@ private CompletableFuture replace(T tuple, Supplier r TarantoolReplaceRequest request = new TarantoolReplaceRequest.Builder() .withSpaceId(spaceId) .withTuple(tuple) + .withSignature(methodSignatures.get(TarantoolReplaceRequest.class.getName())) .build(config.getMessagePackMapper()); return sendRequest(request, resultMapperSupplier); @@ -152,6 +181,7 @@ private CompletableFuture select(Conditions conditions, Supplier update( .withIndexId(indexQuery.getIndexId()) .withKeyValues(indexQuery.getKeyValues()) .withTupleOperations(fillFieldIndexFromMetadata(operations)) + .withSignature(methodSignatures.get(TarantoolUpdateRequest.class.getName())) .build(config.getMessagePackMapper()); return sendRequest(request, resultMapperSupplier); @@ -225,6 +256,7 @@ private CompletableFuture upsert( .withKeyValues(indexQuery.getKeyValues()) .withTuple(tuple) .withTupleOperations(fillFieldIndexFromMetadata(operations)) + .withSignature(methodSignatures.get(TarantoolUpsertRequest.class.getName())) .build(config.getMessagePackMapper()); return sendRequest(request, resultMapperSupplier); @@ -244,6 +276,7 @@ private CompletableFuture truncate(Supplier result String spaceName = spaceMetadata.getSpaceName(); TarantoolCallRequest request = new TarantoolCallRequest.Builder() .withFunctionName("box.space." + spaceName + ":truncate") + .withSignature(methodSignatures.get("truncate")) .build(config.getMessagePackMapper()); return sendRequest(request, resultMapperSupplier) .thenApply(v -> TarantoolVoidResult.INSTANCE.value()); diff --git a/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java b/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java index 0a283525..8c42f1de 100644 --- a/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java +++ b/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java @@ -1,5 +1,6 @@ package io.tarantool.driver.protocol; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Objects; @@ -69,4 +70,21 @@ public String toString() { sb.append("]"); return sb.toString(); } + + /** + * Factory method for a typical RPC usage + * + * @param functionName name of the remote function + * @param arguments list of arguments for the remote function + * @param resultClass type of the expected result. It's necessary for polymorphic functions, e.g. accepting a + * Tarantool space as an argument + * @return new request signature + */ + public static TarantoolRequestSignature create(String functionName, List arguments, Class resultClass) { + List components = new ArrayList<>(arguments.size() + 2); + components.add(functionName); + components.addAll(arguments); + components.add(resultClass.getName()); + return new TarantoolRequestSignature(components.toArray(new Object[]{})); + } }