diff --git a/.gitignore b/.gitignore index b6174007b..e5294d8d1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ tmp/ *.swo .bloop/ .metals/ +.vscode/ diff --git a/pom.xml b/pom.xml index 538ae0000..d1c00272c 100644 --- a/pom.xml +++ b/pom.xml @@ -280,10 +280,10 @@ test - org.openjdk.jmh - jmh-generator-annprocess - 1.35 - test + org.openjdk.jmh + jmh-generator-annprocess + 1.35 + test org.junit.jupiter @@ -413,12 +413,19 @@ -classpath - org.openjdk.jmh.Main] + org.openjdk.jmh.Main + ${benchmark} + ${benchmarkArgs} + + true + SingleInstanceBenchmarkRunner + + release diff --git a/src/main/java/io/tarantool/driver/api/TarantoolCallOperations.java b/src/main/java/io/tarantool/driver/api/TarantoolCallOperations.java index eb6ff7ae3..d6b7b1d5d 100644 --- a/src/main/java/io/tarantool/driver/api/TarantoolCallOperations.java +++ b/src/main/java/io/tarantool/driver/api/TarantoolCallOperations.java @@ -2,7 +2,6 @@ import io.tarantool.driver.exceptions.TarantoolClientException; import io.tarantool.driver.mappers.CallResultMapper; -import io.tarantool.driver.mappers.MessagePackMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.mappers.converters.ValueConverter; import io.tarantool.driver.mappers.factories.ResultMapperFactoryFactory; @@ -54,18 +53,6 @@ public interface TarantoolCallOperations { */ CompletableFuture> call(String functionName, Collection arguments) throws TarantoolClientException; - /** - * Execute a function defined on Tarantool instance - * - * @param functionName function name, must not be null or empty - * @param arguments list of function arguments - * @param mapper mapper for arguments object-to-MessagePack entity conversion and result values conversion - * @return some result - * @throws TarantoolClientException if the client is not connected - */ - CompletableFuture> call(String functionName, Collection arguments, MessagePackMapper mapper) - throws TarantoolClientException; - /** * Execute a function defined on Tarantool instance. The call result is interpreted as an array of tuples. The value * mapper specified in the client configuration will be used for converting the result values from MessagePack @@ -85,13 +72,13 @@ CompletableFuture> callForTupleResult(String functionName * * @param desired function call result type * @param functionName function name, must not be null or empty - * @param resultMapper mapper for result value MessagePack entity-to-object conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ CompletableFuture call( String functionName, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -120,14 +107,14 @@ CompletableFuture> callForTupleResult( * @param functionName function name, must not be null or empty * @param arguments list of function arguments. The object mapper specified in the client configuration * will be used for arguments conversion to MessagePack entities - * @param resultMapper mapper for result value MessagePack entity-to-object conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ CompletableFuture call( String functionName, Collection arguments, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -138,7 +125,7 @@ CompletableFuture call( * @param desired function call result type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion * @param entityClass target result entity class * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred @@ -146,7 +133,7 @@ CompletableFuture call( CompletableFuture> callForTupleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Class entityClass) throws TarantoolClientException; @@ -156,16 +143,16 @@ CompletableFuture> callForTupleResult( * @param desired function call result type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion - * @param resultMapper mapper for result value MessagePack entity-to-object conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ CompletableFuture call( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -175,7 +162,7 @@ CompletableFuture call( * @param target result content type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion * @param resultClass target result entity class * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred @@ -183,7 +170,7 @@ CompletableFuture call( CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Class resultClass) throws TarantoolClientException; @@ -194,7 +181,7 @@ CompletableFuture callForSingleResult( * @param target result content type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion * @param valueConverter MessagePack value to entity converter for each result item * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred @@ -202,7 +189,7 @@ CompletableFuture callForSingleResult( CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, ValueConverter valueConverter) throws TarantoolClientException; @@ -213,16 +200,16 @@ CompletableFuture callForSingleResult( * @param target result content type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion - * @param resultMapper mapper for result conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -266,14 +253,14 @@ CompletableFuture callForSingleResult( * @param target result content type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param resultMapper mapper for result conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ CompletableFuture callForSingleResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -312,13 +299,13 @@ CompletableFuture callForSingleResult( * * @param target result content type * @param functionName function name, must not be null or empty - * @param resultMapper mapper for result conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ CompletableFuture callForSingleResult( String functionName, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -328,7 +315,7 @@ CompletableFuture callForSingleResult( * @param target result type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion * @param resultContainerSupplier supplier function for new empty result collection * @param resultClass target result entity class * @return some result @@ -337,7 +324,7 @@ CompletableFuture callForSingleResult( > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, Class resultClass) throws TarantoolClientException; @@ -349,7 +336,7 @@ > CompletableFuture callForMultiResult( * @param target result type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion * @param resultContainerSupplier supplier function for new empty result collection * @param valueConverter MessagePack value to entity converter for each result item * @return some result @@ -358,7 +345,7 @@ > CompletableFuture callForMultiResult( > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, ValueConverter valueConverter) throws TarantoolClientException; @@ -370,16 +357,16 @@ > CompletableFuture callForMultiResult( * @param target result type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion - * @param resultMapper mapper for result conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -427,14 +414,14 @@ > CompletableFuture callForMultiResult( * @param target result type * @param functionName function name, must not be null or empty * @param arguments list of function arguments - * @param resultMapper mapper for result conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ > CompletableFuture callForMultiResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** @@ -477,13 +464,13 @@ > CompletableFuture callForMultiResult( * @param target result content type * @param target result type * @param functionName function name, must not be null or empty - * @param resultMapper mapper for result conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected or some other error occurred */ > CompletableFuture callForMultiResult( String functionName, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException; /** diff --git a/src/main/java/io/tarantool/driver/api/TarantoolEvalOperations.java b/src/main/java/io/tarantool/driver/api/TarantoolEvalOperations.java index 68173bb05..4048d552b 100644 --- a/src/main/java/io/tarantool/driver/api/TarantoolEvalOperations.java +++ b/src/main/java/io/tarantool/driver/api/TarantoolEvalOperations.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; /** * Aggregates all value operation variants @@ -43,11 +44,11 @@ public interface TarantoolEvalOperations { * keyword return. * * @param expression lua expression, must not be null or empty - * @param resultMapper mapper for result value MessagePack entity-to-object conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected */ - CompletableFuture> eval(String expression, MessagePackValueMapper resultMapper) + CompletableFuture> eval(String expression, Supplier resultMapperSupplier) throws TarantoolClientException; /** @@ -57,11 +58,12 @@ CompletableFuture> eval(String expression, MessagePackValueMapper result * @param expression lua expression, must not be null or empty * @param arguments the list of function arguments. The object mapper specified in the client configuration * will be used for arguments conversion to MessagePack entities - * @param resultMapper mapper for result value MessagePack entity-to-object conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected */ - CompletableFuture> eval(String expression, Collection arguments, MessagePackValueMapper resultMapper) + CompletableFuture> eval( + String expression, Collection arguments, Supplier resultMapperSupplier) throws TarantoolClientException; /** @@ -70,14 +72,14 @@ CompletableFuture> eval(String expression, Collection arguments, Mess * * @param expression lua expression, must not be null or empty * @param arguments the list of function arguments - * @param argumentsMapper mapper for arguments object-to-MessagePack entity conversion - * @param resultMapper mapper for result value MessagePack entity-to-object conversion + * @param argumentsMapperSupplier mapper supplier for arguments object-to-MessagePack entity conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return some result * @throws TarantoolClientException if the client is not connected */ CompletableFuture> eval( String expression, Collection arguments, - MessagePackObjectMapper argumentsMapper, - MessagePackValueMapper resultMapper) throws TarantoolClientException; + Supplier argumentsMapperSupplier, + Supplier resultMapperSupplier) throws TarantoolClientException; } diff --git a/src/main/java/io/tarantool/driver/api/connection/TarantoolConnection.java b/src/main/java/io/tarantool/driver/api/connection/TarantoolConnection.java index 00915576f..7fe720766 100644 --- a/src/main/java/io/tarantool/driver/api/connection/TarantoolConnection.java +++ b/src/main/java/io/tarantool/driver/api/connection/TarantoolConnection.java @@ -2,12 +2,11 @@ import io.netty.channel.Channel; import io.tarantool.driver.TarantoolVersion; +import io.tarantool.driver.core.TarantoolRequestMetadata; import io.tarantool.driver.exceptions.TarantoolClientException; -import io.tarantool.driver.mappers.MessagePackValueMapper; import io.tarantool.driver.protocol.TarantoolRequest; import java.net.InetSocketAddress; -import java.util.concurrent.CompletableFuture; public interface TarantoolConnection extends AutoCloseable { /** @@ -37,11 +36,9 @@ public interface TarantoolConnection extends AutoCloseable { * Send a prepared request to the Tarantool server and flush the buffer * * @param request the request - * @param resultMapper the mapper for response body - * @param result type - * @return result future + * @return request metadata containing the request result future */ - CompletableFuture sendRequest(TarantoolRequest request, MessagePackValueMapper resultMapper); + TarantoolRequestMetadata sendRequest(TarantoolRequest request); /** * Get the Netty channel baking this connection diff --git a/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java b/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java index 25b4440ba..1a7ec1a6d 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; @@ -47,6 +49,7 @@ import io.tarantool.driver.mappers.factories.ResultMapperFactoryFactoryImpl; import io.tarantool.driver.protocol.Packable; import io.tarantool.driver.protocol.TarantoolProtocolException; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.requests.TarantoolCallRequest; import io.tarantool.driver.protocol.requests.TarantoolEvalRequest; import io.tarantool.driver.utils.Assert; @@ -68,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; @@ -113,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) @@ -224,7 +231,8 @@ public TarantoolMetadataProvider metadataProvider() { @Override public CompletableFuture> call(String functionName) throws TarantoolClientException { - return call(functionName, Collections.emptyList()); + return makeRequest(functionName, Collections.emptyList(), null, + config::getMessagePackMapper, config::getMessagePackMapper); } @Override @@ -236,13 +244,8 @@ public CompletableFuture> call(String functionName, Object... arguments) @Override public CompletableFuture> call(String functionName, Collection arguments) throws TarantoolClientException { - return call(functionName, arguments, config.getMessagePackMapper()); - } - - @Override - public CompletableFuture> call(String functionName, Collection arguments, MessagePackMapper mapper) - throws TarantoolClientException { - return makeRequest(functionName, arguments, mapper, mapper); + return makeRequest(functionName, arguments, null, + config::getMessagePackMapper, config::getMessagePackMapper); } @Override @@ -254,46 +257,50 @@ public CompletableFuture> callForTupleResult(String funct @Override public CompletableFuture call( String functionName, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return call(functionName, Collections.emptyList(), resultMapper); + return call(functionName, Collections.emptyList(), resultMapperSupplier); } @Override public CompletableFuture> callForTupleResult( String functionName, Collection arguments, Class tupleClass) throws TarantoolClientException { - return callForTupleResult(functionName, arguments, config.getMessagePackMapper(), tupleClass); + return callForTupleResult(functionName, arguments, config::getMessagePackMapper, tupleClass); } @Override public CompletableFuture call( String functionName, Collection arguments, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return call(functionName, arguments, config.getMessagePackMapper(), resultMapper); + return call(functionName, arguments, config::getMessagePackMapper, resultMapperSupplier); } @Override public CompletableFuture> callForTupleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Class tupleClass) throws TarantoolClientException { - return call(functionName, arguments, argumentsMapper, - mapperFactoryFactory.getTarantoolResultMapper(config.getMessagePackMapper(), tupleClass)); + Supplier, SingleValueCallResult>>> + resultMapperSupplier = () -> + mapperFactoryFactory.getTarantoolResultMapper(config.getMessagePackMapper(), tupleClass); + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + functionName, arguments, tupleClass, argumentsMapperSupplier, resultMapperSupplier); + return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @Override public CompletableFuture call( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, argumentsMapper, resultMapper); + return callForSingleResult(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } @Override @@ -302,7 +309,7 @@ public CompletableFuture callForSingleResult( Collection arguments, Class resultClass) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, config.getMessagePackMapper(), resultClass); + return callForSingleResult(functionName, arguments, config::getMessagePackMapper, resultClass); } @Override @@ -311,15 +318,15 @@ public CompletableFuture callForSingleResult( Collection arguments, ValueConverter valueConverter) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, config.getMessagePackMapper(), valueConverter); + return callForSingleResult(functionName, arguments, config::getMessagePackMapper, valueConverter); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, config.getMessagePackMapper(), resultMapper); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return callForSingleResult(functionName, arguments, config::getMessagePackMapper, resultMapperSupplier); } @Override @@ -337,40 +344,59 @@ public CompletableFuture callForSingleResult(String functionName, ValueCo @Override public CompletableFuture callForSingleResult( String functionName, - CallResultMapper> resultMapper) throws TarantoolClientException { - return callForSingleResult(functionName, Collections.emptyList(), resultMapper); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return callForSingleResult(functionName, Collections.emptyList(), resultMapperSupplier); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Class resultClass) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, argumentsMapper, - mapperFactoryFactory.getDefaultSingleValueMapper(config.getMessagePackMapper(), resultClass)); + Supplier>> resultMapperSupplier = () -> + mapperFactoryFactory.getDefaultSingleValueMapper(config.getMessagePackMapper(), resultClass); + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + functionName, arguments, resultClass, argumentsMapperSupplier, resultMapperSupplier); + return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, ValueConverter valueConverter) throws TarantoolClientException { - return callForSingleResult(functionName, arguments, argumentsMapper, - mapperFactoryFactory.getSingleValueResultMapper(valueConverter)); + Supplier>> resultMapperSupplier = () -> + mapperFactoryFactory.getSingleValueResultMapper(valueConverter); + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + functionName, arguments, valueConverter.getClass(), argumentsMapperSupplier, resultMapperSupplier); + return callForSingleResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); + } + + private CompletableFuture callForSingleResult( + String functionName, + Collection 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, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return makeRequestForSingleResult(functionName, arguments, argumentsMapper, resultMapper) + return makeRequestForSingleResult( + functionName, arguments, null, argumentsMapperSupplier, resultMapperSupplier) .thenApply(CallResult::value); } @@ -382,7 +408,7 @@ public > CompletableFuture callForMultiResult( Class resultClass) throws TarantoolClientException { return callForMultiResult( - functionName, arguments, config.getMessagePackMapper(), resultContainerSupplier, resultClass); + functionName, arguments, config::getMessagePackMapper, resultContainerSupplier, resultClass); } @Override @@ -391,7 +417,7 @@ public > CompletableFuture callForMultiResult( Collection arguments, Supplier resultContainerSupplier, ValueConverter valueConverter) throws TarantoolClientException { - return callForMultiResult(functionName, arguments, config.getMessagePackMapper(), + return callForMultiResult(functionName, arguments, config::getMessagePackMapper, resultContainerSupplier, valueConverter); } @@ -399,8 +425,9 @@ public > CompletableFuture callForMultiResult( public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) throws TarantoolClientException { - return callForMultiResult(functionName, arguments, config.getMessagePackMapper(), resultMapper); + Supplier>> resultMapperSupplier) + throws TarantoolClientException { + return callForMultiResult(functionName, arguments, config::getMessagePackMapper, resultMapperSupplier); } @Override @@ -424,67 +451,88 @@ public > CompletableFuture callForMultiResult( @Override public > CompletableFuture callForMultiResult( String functionName, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return callForMultiResult(functionName, Collections.emptyList(), resultMapper); + return callForMultiResult(functionName, Collections.emptyList(), resultMapperSupplier); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, Class resultClass) throws TarantoolClientException { - return callForMultiResult(functionName, arguments, argumentsMapper, - mapperFactoryFactory.getDefaultMultiValueMapper(config.getMessagePackMapper(), resultClass)); + Supplier>> resultMapperSupplier = () -> + mapperFactoryFactory.getDefaultMultiValueMapper(config.getMessagePackMapper(), resultClass); + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + functionName, arguments, resultClass, argumentsMapperSupplier, resultMapperSupplier); + return callForMultiResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, ValueConverter valueConverter) throws TarantoolClientException { - return callForMultiResult(functionName, arguments, argumentsMapper, - mapperFactoryFactory.getMultiValueResultMapper(resultContainerSupplier, valueConverter)); + Supplier>> resultMapperSupplier = () -> + mapperFactoryFactory.getMultiValueResultMapper(resultContainerSupplier, valueConverter); + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + functionName, arguments, valueConverter.getClass(), argumentsMapperSupplier, resultMapperSupplier); + return callForMultiResult(functionName, arguments, signature, argumentsMapperSupplier, resultMapperSupplier); + } + + private > CompletableFuture callForMultiResult( + String functionName, + Collection 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, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return makeRequestForMultiResult(functionName, arguments, argumentsMapper, resultMapper) + return makeRequestForMultiResult(functionName, arguments, null, argumentsMapperSupplier, resultMapperSupplier) .thenApply(CallResult::value); } private CompletableFuture> makeRequestForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - return makeRequest(functionName, arguments, argumentsMapper, resultMapper); + TarantoolRequestSignature requestSignature, + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + return makeRequest(functionName, arguments, requestSignature, argumentsMapperSupplier, resultMapperSupplier); } private > CompletableFuture> makeRequestForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - return makeRequest(functionName, arguments, argumentsMapper, resultMapper); + TarantoolRequestSignature requestSignature, + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + return makeRequest(functionName, arguments, requestSignature, argumentsMapperSupplier, resultMapperSupplier); } private CompletableFuture makeRequest( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - MessagePackValueMapper resultMapper) + TarantoolRequestSignature requestSignature, + Supplier argumentsMapperSupplier, + Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolCallRequest.Builder builder = new TarantoolCallRequest.Builder() @@ -493,9 +541,18 @@ private CompletableFuture makeRequest( if (arguments.size() > 0) { builder.withArguments(arguments); } + builder.withSignature(requestSignature); + 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, resultMapper)); + return connectionManager().getConnection() + .thenCompose(c -> c.sendRequest(request).getFuture()) + .thenApply(resultMapper::fromValue); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } @@ -509,34 +566,44 @@ public CompletableFuture> eval(String expression) throws TarantoolClient @Override public CompletableFuture> eval(String expression, Collection arguments) throws TarantoolClientException { - return eval(expression, arguments, config.getMessagePackMapper()); + return eval(expression, arguments, config::getMessagePackMapper); } @Override - public CompletableFuture> eval(String expression, MessagePackValueMapper resultMapper) + public CompletableFuture> eval( + String expression, Supplier resultMapperSupplier) throws TarantoolClientException { - return eval(expression, Collections.emptyList(), resultMapper); + return eval(expression, Collections.emptyList(), resultMapperSupplier); } @Override public CompletableFuture> eval( - String expression, Collection arguments, MessagePackValueMapper resultMapper) + String expression, Collection arguments, Supplier resultMapperSupplier) throws TarantoolClientException { - return eval(expression, arguments, config.getMessagePackMapper(), resultMapper); + return eval(expression, arguments, config::getMessagePackMapper, resultMapperSupplier); } @Override public CompletableFuture> eval( String expression, Collection arguments, - MessagePackObjectMapper argumentsMapper, - MessagePackValueMapper resultMapper) throws TarantoolClientException { + Supplier argumentsMapperSupplier, + Supplier resultMapperSupplier) throws TarantoolClientException { try { + TarantoolRequestSignature signature = TarantoolRequestSignature.create( + expression, arguments, List.class, argumentsMapperSupplier, resultMapperSupplier); + 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) + .withSignature(signature) .build(argumentsMapper); - return connectionManager().getConnection().thenCompose(c -> c.sendRequest(request, resultMapper)); + return connectionManager().getConnection() + .thenCompose(c -> c.sendRequest(request).getFuture()) + .thenApply(resultMapper::fromValue); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } diff --git a/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java b/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java index e16269f4d..51a898cf7 100644 --- a/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java +++ b/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java @@ -20,7 +20,6 @@ import io.tarantool.driver.exceptions.TarantoolClientException; import io.tarantool.driver.exceptions.TarantoolSpaceNotFoundException; import io.tarantool.driver.mappers.CallResultMapper; -import io.tarantool.driver.mappers.MessagePackMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.mappers.MessagePackValueMapper; import io.tarantool.driver.mappers.converters.ValueConverter; @@ -182,12 +181,6 @@ public CompletableFuture> call(String functionName, Collection argume return client.call(functionName, arguments); } - @Override - public CompletableFuture> call(String functionName, Collection arguments, MessagePackMapper mapper) - throws TarantoolClientException { - return client.call(functionName, arguments, mapper); - } - @Override public CompletableFuture> callForTupleResult(String functionName, Class entityClass) throws TarantoolClientException { @@ -196,8 +189,8 @@ public CompletableFuture> callForTupleResult(String funct @Override public CompletableFuture call(String functionName, - CallResultMapper> resultMapper) throws TarantoolClientException { - return client.call(functionName, resultMapper); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return client.call(functionName, resultMapperSupplier); } @Override @@ -208,51 +201,57 @@ public CompletableFuture> callForTupleResult(String funct @Override public CompletableFuture call(String functionName, Collection arguments, - CallResultMapper> resultMapper) throws TarantoolClientException { - return client.call(functionName, arguments, resultMapper); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return client.call(functionName, arguments, resultMapperSupplier); } @Override - public CompletableFuture> callForTupleResult(String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, Class entityClass) throws TarantoolClientException { - return client.callForTupleResult(functionName, arguments, argumentsMapper, entityClass); + public CompletableFuture> callForTupleResult( + String functionName, + Collection arguments, + Supplier argumentsMapperSupplier, + Class entityClass) throws TarantoolClientException { + return client.callForTupleResult(functionName, arguments, argumentsMapperSupplier, entityClass); } @Override - public CompletableFuture call(String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, CallResultMapper> resultMapper) + public CompletableFuture call( + String functionName, + Collection arguments, + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return client.call(functionName, arguments, argumentsMapper, resultMapper); + return client.call(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Class resultClass) throws TarantoolClientException { - return client.callForSingleResult(functionName, arguments, argumentsMapper, resultClass); + return client.callForSingleResult(functionName, arguments, argumentsMapperSupplier, resultClass); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, ValueConverter valueConverter) throws TarantoolClientException { - return client.callForSingleResult(functionName, arguments, argumentsMapper, valueConverter); + return client.callForSingleResult(functionName, arguments, argumentsMapperSupplier, valueConverter); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return client.callForSingleResult(functionName, arguments, argumentsMapper, resultMapper); + return client.callForSingleResult(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } @Override @@ -275,8 +274,8 @@ public CompletableFuture callForSingleResult( public CompletableFuture callForSingleResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) throws TarantoolClientException { - return client.callForSingleResult(functionName, arguments, resultMapper); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return client.callForSingleResult(functionName, arguments, resultMapperSupplier); } @Override @@ -294,39 +293,40 @@ public CompletableFuture callForSingleResult(String functionName, ValueCo @Override public CompletableFuture callForSingleResult( String functionName, - CallResultMapper> resultMapper) throws TarantoolClientException { - return client.callForSingleResult(functionName, resultMapper); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return client.callForSingleResult(functionName, resultMapperSupplier); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, Class resultClass) throws TarantoolClientException { return client.callForMultiResult( - functionName, arguments, argumentsMapper, resultContainerSupplier, resultClass); + functionName, arguments, argumentsMapperSupplier, resultContainerSupplier, resultClass); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, ValueConverter valueConverter) throws TarantoolClientException { return client.callForMultiResult( - functionName, arguments, argumentsMapper, resultContainerSupplier, valueConverter); + functionName, arguments, argumentsMapperSupplier, resultContainerSupplier, valueConverter); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) throws TarantoolClientException { - return client.callForMultiResult(functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) + throws TarantoolClientException { + return client.callForMultiResult(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } @Override @@ -353,8 +353,9 @@ public > CompletableFuture callForMultiResult( public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) throws TarantoolClientException { - return client.callForMultiResult(functionName, arguments, resultMapper); + Supplier>> resultMapperSupplier) + throws TarantoolClientException { + return client.callForMultiResult(functionName, arguments, resultMapperSupplier); } @Override @@ -378,9 +379,9 @@ public > CompletableFuture callForMultiResult( @Override public > CompletableFuture callForMultiResult( String functionName, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return client.callForMultiResult(functionName, resultMapper); + return client.callForMultiResult(functionName, resultMapperSupplier); } @Override @@ -394,25 +395,26 @@ public CompletableFuture> eval(String expression, Collection argument } @Override - public CompletableFuture> eval(String expression, MessagePackValueMapper resultMapper) + public CompletableFuture> eval( + String expression, Supplier resultMapperSupplier) throws TarantoolClientException { - return client.eval(expression, resultMapper); + return client.eval(expression, resultMapperSupplier); } @Override public CompletableFuture> eval( - String expression, Collection arguments, MessagePackValueMapper resultMapper) + String expression, Collection arguments, Supplier resultMapperSupplier) throws TarantoolClientException { - return client.eval(expression, arguments, resultMapper); + return client.eval(expression, arguments, resultMapperSupplier); } @Override public CompletableFuture> eval( String expression, Collection arguments, - MessagePackObjectMapper argumentsMapper, - MessagePackValueMapper resultMapper) throws TarantoolClientException { - return client.eval(expression, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier resultMapperSupplier) throws TarantoolClientException { + return client.eval(expression, arguments, argumentsMapperSupplier, resultMapperSupplier); } @Override diff --git a/src/main/java/io/tarantool/driver/core/RequestFutureManager.java b/src/main/java/io/tarantool/driver/core/RequestFutureManager.java index 179f3a88f..0652ced51 100644 --- a/src/main/java/io/tarantool/driver/core/RequestFutureManager.java +++ b/src/main/java/io/tarantool/driver/core/RequestFutureManager.java @@ -1,7 +1,6 @@ package io.tarantool.driver.core; import io.tarantool.driver.api.TarantoolClientConfig; -import io.tarantool.driver.mappers.MessagePackValueMapper; import io.tarantool.driver.protocol.TarantoolRequest; import java.util.Map; @@ -11,6 +10,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.msgpack.value.Value; + /** * Keeps track of submitted requests, finishing them by timeout and allowing asynchronous request processing * @@ -37,12 +38,11 @@ public RequestFutureManager(TarantoolClientConfig config, ScheduledExecutorServi * The request timeout is taken from the client configuration * * @param request request to Tarantool server - * @param resultMapper result message entity-to-object mapper - * @param target response body type - * @return {@link CompletableFuture} that completes when a response is received from Tarantool server + * @return {@link TarantoolRequestMetadata} metadata holder with request future that completes when a response + * is received from Tarantool server or request timeout is expired */ - public CompletableFuture submitRequest(TarantoolRequest request, MessagePackValueMapper resultMapper) { - return submitRequest(request, config.getRequestTimeout(), resultMapper); + public TarantoolRequestMetadata submitRequest(TarantoolRequest request) { + return submitRequest(request, config.getRequestTimeout()); } /** @@ -51,25 +51,22 @@ public CompletableFuture submitRequest(TarantoolRequest request, MessageP * * @param request request to Tarantool server * @param requestTimeout timeout after which the request will be automatically failed, milliseconds - * @param resultMapper result message entity-to-object mapper - * @param target response body type - * @return {@link CompletableFuture} that completes when a response is received from Tarantool server + * @return {@link TarantoolRequestMetadata} metadata holder with request future that completes when a response + * is received from Tarantool server or request timeout is expired */ - public CompletableFuture submitRequest( - TarantoolRequest request, - int requestTimeout, - MessagePackValueMapper resultMapper) { - CompletableFuture requestFuture = new CompletableFuture<>(); - long requestId = request.getHeader().getSync(); + public TarantoolRequestMetadata submitRequest(TarantoolRequest request, int requestTimeout) { + CompletableFuture requestFuture = new CompletableFuture<>(); + TarantoolRequestMetadata requestMetadata = new TarantoolRequestMetadata(request, requestFuture); + long requestId = requestMetadata.getRequestId(); requestFuture.whenComplete((r, e) -> requestFutures.remove(requestId)); - requestFutures.put(requestId, new TarantoolRequestMetadata(requestFuture, resultMapper)); + requestFutures.put(requestId, requestMetadata); timeoutScheduler.schedule(() -> { if (!requestFuture.isDone()) { requestFuture.completeExceptionally(new TimeoutException(String.format( - "Failed to get response for request id: %d within %d ms", requestId, requestTimeout))); + "Failed to get response for %s within %d ms", requestMetadata, requestTimeout))); } }, requestTimeout, TimeUnit.MILLISECONDS); - return requestFuture; + return requestMetadata; } /** diff --git a/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java b/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java index e086a2d22..83a172bf8 100644 --- a/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java +++ b/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java @@ -15,7 +15,6 @@ import io.tarantool.driver.core.space.RetryingTarantoolSpace; import io.tarantool.driver.exceptions.TarantoolClientException; import io.tarantool.driver.mappers.CallResultMapper; -import io.tarantool.driver.mappers.MessagePackMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.mappers.MessagePackValueMapper; import io.tarantool.driver.mappers.converters.ValueConverter; @@ -146,14 +145,6 @@ public CompletableFuture> call(String functionName, Collection argume return wrapOperation(() -> client.call(functionName, arguments)); } - @Override - public CompletableFuture> call( - String functionName, - Collection arguments, - MessagePackMapper mapper) throws TarantoolClientException { - return wrapOperation(() -> client.call(functionName, arguments, mapper)); - } - @Override public CompletableFuture> callForTupleResult(String functionName, Class entityClass) throws TarantoolClientException { @@ -162,8 +153,8 @@ public CompletableFuture> callForTupleResult(String funct @Override public CompletableFuture call(String functionName, - CallResultMapper> resultMapper) throws TarantoolClientException { - return wrapOperation(() -> client.call(functionName, resultMapper)); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return wrapOperation(() -> client.call(functionName, resultMapperSupplier)); } @Override @@ -174,51 +165,60 @@ public CompletableFuture> callForTupleResult(String funct @Override public CompletableFuture call(String functionName, Collection arguments, - CallResultMapper> resultMapper) throws TarantoolClientException { - return wrapOperation(() -> client.call(functionName, arguments, resultMapper)); + Supplier>> resultMapperSupplier) throws TarantoolClientException { + return wrapOperation(() -> client.call(functionName, arguments, resultMapperSupplier)); } @Override - public CompletableFuture> callForTupleResult(String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, Class entityClass) throws TarantoolClientException { - return wrapOperation(() -> client.callForTupleResult(functionName, arguments, argumentsMapper, entityClass)); + public CompletableFuture> callForTupleResult( + String functionName, + Collection arguments, + Supplier argumentsMapperSupplier, + Class entityClass) throws TarantoolClientException { + return wrapOperation( + () -> client.callForTupleResult(functionName, arguments, argumentsMapperSupplier, entityClass)); } @Override - public CompletableFuture call(String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, CallResultMapper> resultMapper) + public CompletableFuture call( + String functionName, + Collection arguments, + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return wrapOperation(() -> client.call(functionName, arguments, argumentsMapper, resultMapper)); + return wrapOperation(() -> client.call(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier)); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Class resultClass) throws TarantoolClientException { - return wrapOperation(() -> client.callForSingleResult(functionName, arguments, argumentsMapper, resultClass)); + return wrapOperation( + () -> client.callForSingleResult(functionName, arguments, argumentsMapperSupplier, resultClass)); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, ValueConverter valueConverter) throws TarantoolClientException { return wrapOperation(() -> - client.callForSingleResult(functionName, arguments, argumentsMapper, valueConverter)); + client.callForSingleResult(functionName, arguments, argumentsMapperSupplier, valueConverter)); } @Override public CompletableFuture callForSingleResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return wrapOperation(() -> client.callForSingleResult(functionName, arguments, argumentsMapper, resultMapper)); + return wrapOperation( + () -> client.callForSingleResult(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier)); } @Override @@ -241,9 +241,9 @@ public CompletableFuture callForSingleResult( public CompletableFuture callForSingleResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return wrapOperation(() -> client.callForSingleResult(functionName, arguments, resultMapper)); + return wrapOperation(() -> client.callForSingleResult(functionName, arguments, resultMapperSupplier)); } @Override @@ -261,43 +261,44 @@ public CompletableFuture callForSingleResult(String functionName, ValueCo @Override public CompletableFuture callForSingleResult( String functionName, - CallResultMapper> resultMapper) + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return wrapOperation(() -> client.callForSingleResult(functionName, resultMapper)); + return wrapOperation(() -> client.callForSingleResult(functionName, resultMapperSupplier)); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, Class resultClass) throws TarantoolClientException { return wrapOperation(() -> client.callForMultiResult( - functionName, arguments, argumentsMapper, resultContainerSupplier, resultClass)); + functionName, arguments, argumentsMapperSupplier, resultContainerSupplier, resultClass)); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, + Supplier argumentsMapperSupplier, Supplier resultContainerSupplier, ValueConverter valueConverter) throws TarantoolClientException { return wrapOperation(() -> client.callForMultiResult( - functionName, arguments, argumentsMapper, resultContainerSupplier, valueConverter)); + functionName, arguments, argumentsMapperSupplier, resultContainerSupplier, valueConverter)); } @Override public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) throws TarantoolClientException { - return wrapOperation(() -> client.callForMultiResult(functionName, arguments, argumentsMapper, resultMapper)); + return wrapOperation( + () -> client.callForMultiResult(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier)); } @Override @@ -326,8 +327,9 @@ public > CompletableFuture callForMultiResult( public > CompletableFuture callForMultiResult( String functionName, Collection arguments, - CallResultMapper> resultMapper) throws TarantoolClientException { - return wrapOperation(() -> client.callForMultiResult(functionName, arguments, resultMapper)); + Supplier>> resultMapperSupplier) + throws TarantoolClientException { + return wrapOperation(() -> client.callForMultiResult(functionName, arguments, resultMapperSupplier)); } @Override @@ -351,8 +353,9 @@ public > CompletableFuture callForMultiResult( @Override public > CompletableFuture callForMultiResult( String functionName, - CallResultMapper> resultMapper) throws TarantoolClientException { - return wrapOperation(() -> client.callForMultiResult(functionName, resultMapper)); + Supplier>> resultMapperSupplier) + throws TarantoolClientException { + return wrapOperation(() -> client.callForMultiResult(functionName, resultMapperSupplier)); } @Override @@ -373,24 +376,24 @@ public CompletableFuture> eval(String expression, Collection argument @Override public CompletableFuture> eval( String expression, - MessagePackValueMapper resultMapper) throws TarantoolClientException { - return wrapOperation(() -> client.eval(expression, resultMapper)); + Supplier resultMapperSupplier) throws TarantoolClientException { + return wrapOperation(() -> client.eval(expression, resultMapperSupplier)); } @Override public CompletableFuture> eval( String expression, Collection arguments, - MessagePackValueMapper resultMapper) throws TarantoolClientException { - return wrapOperation(() -> client.eval(expression, arguments, resultMapper)); + Supplier resultMapperSupplier) throws TarantoolClientException { + return wrapOperation(() -> client.eval(expression, arguments, resultMapperSupplier)); } @Override public CompletableFuture> eval( String expression, Collection arguments, - MessagePackObjectMapper argumentsMapper, - MessagePackValueMapper resultMapper) throws TarantoolClientException { - return wrapOperation(() -> client.eval(expression, arguments, argumentsMapper, resultMapper)); + Supplier argumentsMapperSupplier, + Supplier resultMapperSupplier) throws TarantoolClientException { + return wrapOperation(() -> client.eval(expression, arguments, argumentsMapperSupplier, resultMapperSupplier)); } @Override diff --git a/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java b/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java index 22132bfa9..62ab1470f 100644 --- a/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java +++ b/src/main/java/io/tarantool/driver/core/TarantoolRequestMetadata.java @@ -1,28 +1,37 @@ package io.tarantool.driver.core; -import io.tarantool.driver.mappers.MessagePackValueMapper; - +import java.util.Optional; import java.util.concurrent.CompletableFuture; +import org.msgpack.value.Value; + +import io.tarantool.driver.protocol.TarantoolRequest; +import io.tarantool.driver.protocol.TarantoolRequestSignature; + /** * Intermediate request metadata holder * * @author Alexey Kuzin */ public class TarantoolRequestMetadata { - private final CompletableFuture feature; - private final MessagePackValueMapper mapper; + private final TarantoolRequest request; + private final CompletableFuture future; + + protected TarantoolRequestMetadata(TarantoolRequest request, CompletableFuture requestFuture) { + this.request = request; + this.future = requestFuture; + } - protected TarantoolRequestMetadata(CompletableFuture feature, MessagePackValueMapper mapper) { - this.feature = feature; - this.mapper = mapper; + public CompletableFuture getFuture() { + return future; } - public CompletableFuture getFuture() { - return feature; + public Long getRequestId() { + return request.getHeader().getSync(); } - public MessagePackValueMapper getMapper() { - return mapper; + @Override + public String toString() { + return request.toString(); } } diff --git a/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionImpl.java b/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionImpl.java index 6559172f1..f7f6f0213 100644 --- a/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionImpl.java +++ b/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionImpl.java @@ -7,9 +7,11 @@ import io.tarantool.driver.api.connection.TarantoolConnectionCloseListener; import io.tarantool.driver.api.connection.TarantoolConnectionFailureListener; import io.tarantool.driver.core.RequestFutureManager; +import io.tarantool.driver.core.TarantoolRequestMetadata; import io.tarantool.driver.exceptions.TarantoolClientException; -import io.tarantool.driver.mappers.MessagePackValueMapper; import io.tarantool.driver.protocol.TarantoolRequest; + +import org.msgpack.value.Value; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,12 +67,13 @@ public boolean isConnected() { } @Override - public CompletableFuture sendRequest(TarantoolRequest request, MessagePackValueMapper resultMapper) { + public TarantoolRequestMetadata sendRequest(TarantoolRequest request) { if (!isConnected()) { throw new TarantoolClientException("Not connected to Tarantool server"); } - CompletableFuture requestFuture = requestManager.submitRequest(request, resultMapper); + TarantoolRequestMetadata requestMetadata = requestManager.submitRequest(request); + CompletableFuture requestFuture = requestMetadata.getFuture(); channel.writeAndFlush(request).addListener(f -> { if (!f.isSuccess()) { requestFuture.completeExceptionally( @@ -80,7 +83,7 @@ public CompletableFuture sendRequest(TarantoolRequest request, MessagePac } }); - return requestFuture; + return requestMetadata; } @Override diff --git a/src/main/java/io/tarantool/driver/core/metadata/ProxyMetadataProvider.java b/src/main/java/io/tarantool/driver/core/metadata/ProxyMetadataProvider.java index 550c4b6af..c7aa73657 100644 --- a/src/main/java/io/tarantool/driver/core/metadata/ProxyMetadataProvider.java +++ b/src/main/java/io/tarantool/driver/core/metadata/ProxyMetadataProvider.java @@ -11,6 +11,7 @@ import org.msgpack.value.Value; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; /** * Provides spaces and index metadata via stored function call @@ -21,8 +22,11 @@ public class ProxyMetadataProvider implements TarantoolMetadataProvider { private final String metadataFunctionName; private final TarantoolCallOperations client; + private final CallResultMapper> + metadataMapper; private final - CallResultMapper> mapper; + Supplier>> + metadataMapperSupplier; /** * Basic constructor @@ -40,14 +44,15 @@ public ProxyMetadataProvider( Class> resultClass) { this.metadataFunctionName = metadataFunctionName; this.client = client; - this.mapper = client.getResultMapperFactoryFactory() + this.metadataMapper = client.getResultMapperFactoryFactory() .singleValueResultMapperFactory() .withSingleValueResultConverter(metadataConverter, resultClass); + this.metadataMapperSupplier = () -> metadataMapper; } @Override public CompletableFuture getMetadata() { - return client.callForSingleResult(metadataFunctionName, mapper) + return client.callForSingleResult(metadataFunctionName, metadataMapperSupplier) .exceptionally(ex -> { if (ex.getCause() != null && ex.getCause() instanceof TarantoolClientException) { throw new TarantoolMetadataRequestException(metadataFunctionName, ex); diff --git a/src/main/java/io/tarantool/driver/core/metadata/SpacesMetadataProvider.java b/src/main/java/io/tarantool/driver/core/metadata/SpacesMetadataProvider.java index 42cfefc97..60134cfe1 100644 --- a/src/main/java/io/tarantool/driver/core/metadata/SpacesMetadataProvider.java +++ b/src/main/java/io/tarantool/driver/core/metadata/SpacesMetadataProvider.java @@ -12,10 +12,9 @@ import io.tarantool.driver.exceptions.TarantoolClientException; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackMapper; -import io.tarantool.driver.mappers.converters.ValueConverter; -import org.msgpack.value.ArrayValue; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; /** * Provides spaces and index metadata via requests to the system spaces in the Tarantool server instance @@ -29,7 +28,23 @@ public class SpacesMetadataProvider implements TarantoolMetadataProvider { private final TarantoolCallOperations client; private final VSpaceToTarantoolSpaceMetadataConverter spaceMetadataMapper; + private final + CallResultMapper, + SingleValueCallResult>> + spaceMetadataResultMapper; + private final + Supplier, + SingleValueCallResult>>> + spaceMetadataResultMapperSupplier; private final TarantoolIndexMetadataConverter indexMetadataMapper; + private final + CallResultMapper, + SingleValueCallResult>> + indexMetadataResultMapper; + private final + Supplier, + SingleValueCallResult>>> + indexMetadataResultMapperSupplier; /** * Basic constructor @@ -42,28 +57,33 @@ public SpacesMetadataProvider( MessagePackMapper messagePackMapper) { this.client = client; this.spaceMetadataMapper = VSpaceToTarantoolSpaceMetadataConverter.getInstance(); + this.spaceMetadataResultMapper = client + .getResultMapperFactoryFactory().singleValueTarantoolResultMapperFactory() + .withSingleValueArrayTarantoolResultConverter(spaceMetadataMapper, TarantoolSpaceMetadataResult.class); + this.spaceMetadataResultMapperSupplier = () -> spaceMetadataResultMapper; this.indexMetadataMapper = new TarantoolIndexMetadataConverter(messagePackMapper); + this.indexMetadataResultMapper = client + .getResultMapperFactoryFactory().singleValueTarantoolResultMapperFactory() + .withSingleValueArrayTarantoolResultConverter(indexMetadataMapper, TarantoolIndexMetadataResult.class); + this.indexMetadataResultMapperSupplier = () -> indexMetadataResultMapper; } @Override public CompletableFuture getMetadata() throws TarantoolClientException { CompletableFuture> spaces = - select(VSPACE_SELECT_CMD, spaceMetadataMapper, TarantoolSpaceMetadataResult.class); + select(VSPACE_SELECT_CMD, spaceMetadataResultMapperSupplier, TarantoolSpaceMetadata.class); CompletableFuture> indexes = - select(VINDEX_SELECT_CMD, indexMetadataMapper, TarantoolIndexMetadataResult.class); + select(VINDEX_SELECT_CMD, indexMetadataResultMapperSupplier, TarantoolIndexMetadata.class); return spaces.thenCombine(indexes, SpacesTarantoolMetadataContainer::new); } private CompletableFuture> select( String selectCmd, - ValueConverter resultConverter, - Class>> resultClass) + Supplier, SingleValueCallResult>>> resultMapperSupplier, + Class resultClass) throws TarantoolClientException { - CallResultMapper, SingleValueCallResult>> resultMapper = - client.getResultMapperFactoryFactory().singleValueTarantoolResultMapperFactory() - .withSingleValueArrayTarantoolResultConverter(resultConverter, resultClass); - return client.call(selectCmd, resultMapper); + return client.call(selectCmd, resultMapperSupplier); } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/AbstractProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/AbstractProxyOperation.java index 4c0dc5604..221a8c07d 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/AbstractProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/AbstractProxyOperation.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.EnumMap; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; /** * Basic implementation of a proxy operation @@ -24,20 +25,20 @@ abstract class AbstractProxyOperation implements ProxyOperation { protected final TarantoolCallOperations client; protected final String functionName; protected final Collection arguments; - protected final CallResultMapper> resultMapper; - private final MessagePackObjectMapper argumentsMapper; + private final Supplier argumentsMapperSupplier; + private final Supplier>> resultMapperSupplier; AbstractProxyOperation( TarantoolCallOperations client, String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { this.client = client; - this.argumentsMapper = argumentsMapper; + this.argumentsMapperSupplier = argumentsMapperSupplier; this.arguments = arguments; this.functionName = functionName; - this.resultMapper = resultMapper; + this.resultMapperSupplier = resultMapperSupplier; } public TarantoolCallOperations getClient() { @@ -52,13 +53,17 @@ public Collection getArguments() { return arguments; } - public CallResultMapper> getResultMapper() { - return resultMapper; + public Supplier getArgumentsMapperSupplier() { + return argumentsMapperSupplier; + } + + public Supplier>> getResultMapperSupplier() { + return resultMapperSupplier; } @Override public CompletableFuture execute() { - return client.callForSingleResult(functionName, arguments, argumentsMapper, resultMapper); + return client.callForSingleResult(functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } abstract static @@ -66,9 +71,9 @@ class GenericOperationsBuilder { protected TarantoolCallOperations client; protected String functionName; - protected MessagePackObjectMapper argumentsMapper; - protected CallResultMapper> resultMapper; protected EnumMap arguments; + protected Supplier argumentsMapperSupplier; + protected Supplier>> resultMapperSupplier; GenericOperationsBuilder() { this.arguments = new EnumMap<>(ProxyOperationArgument.class); @@ -114,22 +119,23 @@ public B withFunctionName(String functionName) { /** * Specify entity-to-MessagePack mapper for arguments contents conversion * - * @param objectMapper mapper for arguments entity-to-MessagePack entity conversion + * @param argumentsMapperSupplier mapper supplier for arguments entity-to-MessagePack entity conversion * @return builder */ - public B withArgumentsMapper(MessagePackObjectMapper objectMapper) { - this.argumentsMapper = objectMapper; + public B withArgumentsMapperSupplier(Supplier argumentsMapperSupplier) { + this.argumentsMapperSupplier = argumentsMapperSupplier; return self(); } /** * Specify MessagePack-to-entity mapper for result contents conversion * - * @param resultMapper mapper for result value MessagePack entity-to-object conversion + * @param resultMapperSupplier mapper supplier for result value MessagePack entity-to-object conversion * @return builder */ - public B withResultMapper(CallResultMapper> resultMapper) { - this.resultMapper = resultMapper; + public B withResultMapperSupplier( + Supplier>> resultMapperSupplier) { + this.resultMapperSupplier = resultMapperSupplier; return self(); } diff --git a/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java index 905b3fa57..d61f05f5b 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java @@ -7,6 +7,7 @@ import io.tarantool.driver.mappers.MessagePackObjectMapper; import java.util.Collection; +import java.util.function.Supplier; /** * Proxy operation for delete @@ -21,9 +22,9 @@ private DeleteProxyOperation( TarantoolCallOperations client, String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -44,7 +45,8 @@ public Builder self() { public DeleteProxyOperation build() { return new DeleteProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java index a3d925c0d..4651116cb 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java @@ -8,6 +8,7 @@ import io.tarantool.driver.protocol.Packable; import java.util.Collection; +import java.util.function.Supplier; /** * Proxy operation for inserting many records at once @@ -23,9 +24,9 @@ public final class InsertManyProxyOperation arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -45,7 +46,8 @@ public Builder self() { public InsertManyProxyOperation build() { return new InsertManyProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java index b0ad065df..84db85f45 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java @@ -8,6 +8,7 @@ import io.tarantool.driver.protocol.Packable; import java.util.Collection; +import java.util.function.Supplier; /** * Proxy operation for insert @@ -23,9 +24,9 @@ private InsertProxyOperation( TarantoolCallOperations client, String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -46,7 +47,8 @@ public Builder self() { public InsertProxyOperation build() { return new InsertProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java index 1dd4eaae0..bcd7de08f 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java @@ -8,6 +8,7 @@ import io.tarantool.driver.protocol.Packable; import java.util.Collection; +import java.util.function.Supplier; /** * Proxy operation for replacing many records at once @@ -23,9 +24,9 @@ public final class ReplaceManyProxyOperation arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -46,7 +47,8 @@ public Builder self() { public ReplaceManyProxyOperation build() { return new ReplaceManyProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java index ccf09ffaa..a97c603b4 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java @@ -8,6 +8,7 @@ import io.tarantool.driver.protocol.Packable; import java.util.Collection; +import java.util.function.Supplier; /** * Proxy operation for replace @@ -24,9 +25,9 @@ public final class ReplaceProxyOperation arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -47,7 +48,8 @@ public Builder self() { public ReplaceProxyOperation build() { return new ReplaceProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java index 3a39358b9..5205ba0d0 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java @@ -14,6 +14,7 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; +import java.util.function.Supplier; /** * Proxy operation for select @@ -28,9 +29,9 @@ private SelectProxyOperation( TarantoolCallOperations client, String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -70,7 +71,8 @@ public SelectProxyOperation build() { .ifPresent(after -> options.put(ProxyOption.AFTER.toString(), after)); return new SelectProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java index 869499cc8..e18bd6c94 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java @@ -7,6 +7,7 @@ import io.tarantool.driver.mappers.MessagePackObjectMapper; import java.util.Collection; +import java.util.function.Supplier; /** * Proxy operation for update @@ -21,9 +22,9 @@ public final class UpdateProxyOperation extends AbstractProxyOperation { TarantoolCallOperations client, String functionName, Collection arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -44,7 +45,8 @@ public Builder self() { public UpdateProxyOperation build() { return new UpdateProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java index fcc2046e0..d1e3f615c 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java @@ -8,6 +8,7 @@ import io.tarantool.driver.protocol.Packable; import java.util.Collection; +import java.util.function.Supplier; /** * Proxy operation for upsert @@ -23,9 +24,9 @@ public final class UpsertProxyOperation arguments, - MessagePackObjectMapper argumentsMapper, - CallResultMapper> resultMapper) { - super(client, functionName, arguments, argumentsMapper, resultMapper); + Supplier argumentsMapperSupplier, + Supplier>> resultMapperSupplier) { + super(client, functionName, arguments, argumentsMapperSupplier, resultMapperSupplier); } /** @@ -46,7 +47,8 @@ public Builder self() { public UpsertProxyOperation build() { return new UpsertProxyOperation<>( - this.client, this.functionName, this.arguments.values(), this.argumentsMapper, this.resultMapper); + this.client, this.functionName, this.arguments.values(), + this.argumentsMapperSupplier, this.resultMapperSupplier); } } } diff --git a/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java b/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java index 65cb7f3c0..bf7230562 100644 --- a/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java @@ -46,6 +46,7 @@ import java.util.Collection; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; /** * Basic proxy {@link TarantoolSpaceOperations} implementation, which uses calls to API functions defined in @@ -80,7 +81,7 @@ public ProxyTarantoolSpace( @Override public CompletableFuture delete(Conditions conditions) throws TarantoolClientException { - return delete(conditions, rowsMetadataTupleResultMapper(), ProxyDeleteOptions.create()); + return delete(conditions, this::rowsMetadataTupleResultMapper, ProxyDeleteOptions.create()); } @Override @@ -88,12 +89,12 @@ public CompletableFuture delete(Conditions conditions, DeleteOptions options) if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return delete(conditions, rowsMetadataTupleResultMapper(), options); + return delete(conditions, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture delete( Conditions conditions, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, DeleteOptions options) throws TarantoolClientException { TarantoolIndexQuery indexQuery = conditions.toIndexQuery(metadataOperations, spaceMetadata); @@ -103,8 +104,8 @@ private CompletableFuture delete( .withSpaceName(spaceName) .withFunctionName(operationsMapping.getDeleteFunctionName()) .withIndexQuery(indexQuery) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); @@ -113,7 +114,7 @@ private CompletableFuture delete( @Override public CompletableFuture insert(T tuple) throws TarantoolClientException { - return insert(tuple, rowsMetadataTupleResultMapper(), ProxyInsertOptions.create()); + return insert(tuple, this::rowsMetadataTupleResultMapper, ProxyInsertOptions.create()); } @Override @@ -121,12 +122,12 @@ public CompletableFuture insert(T tuple, InsertOptions options) throws Tarant if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return insert(tuple, rowsMetadataTupleResultMapper(), options); + return insert(tuple, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture insert( T tuple, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, InsertOptions options) throws TarantoolClientException { InsertProxyOperation operation = new InsertProxyOperation.Builder() @@ -134,8 +135,8 @@ private CompletableFuture insert( .withSpaceName(spaceName) .withFunctionName(operationsMapping.getInsertFunctionName()) .withTuple(tuple) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); @@ -144,7 +145,7 @@ private CompletableFuture insert( @Override public CompletableFuture insertMany(Collection tuples) { - return insertMany(tuples, rowsMetadataTupleResultMapper(), ProxyInsertManyOptions.create() + return insertMany(tuples, this::rowsMetadataTupleResultMapper, ProxyInsertManyOptions.create() .withStopOnError(StopOnError.TRUE) .withRollbackOnError(RollbackOnError.TRUE) ); @@ -156,12 +157,12 @@ public CompletableFuture insertMany(Collection tuples, InsertManyOptions o if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return insertMany(tuples, rowsMetadataTupleResultMapper(), options); + return insertMany(tuples, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture insertMany( Collection tuples, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, InsertManyOptions options) throws TarantoolClientException { InsertManyProxyOperation operation = new InsertManyProxyOperation.Builder() @@ -169,8 +170,8 @@ private CompletableFuture insertMany( .withSpaceName(spaceName) .withFunctionName(operationsMapping.getInsertManyFunctionName()) .withTuples(tuples) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); @@ -179,7 +180,7 @@ private CompletableFuture insertMany( @Override public CompletableFuture replace(T tuple) throws TarantoolClientException { - return replace(tuple, rowsMetadataTupleResultMapper(), ProxyReplaceOptions.create()); + return replace(tuple, this::rowsMetadataTupleResultMapper, ProxyReplaceOptions.create()); } @Override @@ -187,12 +188,12 @@ public CompletableFuture replace(T tuple, ReplaceOptions options) throws Tara if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return replace(tuple, rowsMetadataTupleResultMapper(), options); + return replace(tuple, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture replace( T tuple, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, ReplaceOptions options) throws TarantoolClientException { ReplaceProxyOperation operation = new ReplaceProxyOperation.Builder() @@ -200,8 +201,8 @@ private CompletableFuture replace( .withSpaceName(spaceName) .withFunctionName(operationsMapping.getReplaceFunctionName()) .withTuple(tuple) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); @@ -210,7 +211,7 @@ private CompletableFuture replace( @Override public CompletableFuture replaceMany(Collection tuples) throws TarantoolClientException { - return replaceMany(tuples, rowsMetadataTupleResultMapper(), ProxyReplaceManyOptions.create() + return replaceMany(tuples, this::rowsMetadataTupleResultMapper, ProxyReplaceManyOptions.create() .withStopOnError(StopOnError.TRUE) .withRollbackOnError(RollbackOnError.TRUE) ); @@ -221,12 +222,12 @@ public CompletableFuture replaceMany(Collection tuples, ReplaceManyOptions if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return replaceMany(tuples, rowsMetadataTupleResultMapper(), options); + return replaceMany(tuples, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture replaceMany( Collection tuples, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, ReplaceManyOptions options) throws TarantoolClientException { ReplaceManyProxyOperation operation = new ReplaceManyProxyOperation.Builder() @@ -234,8 +235,8 @@ private CompletableFuture replaceMany( .withSpaceName(spaceName) .withFunctionName(operationsMapping.getReplaceManyFunctionName()) .withTuples(tuples) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); @@ -244,7 +245,7 @@ private CompletableFuture replaceMany( @Override public CompletableFuture select(Conditions conditions) throws TarantoolClientException { - return select(conditions, rowsMetadataTupleResultMapper(), ProxySelectOptions.create()); + return select(conditions, this::rowsMetadataTupleResultMapper, ProxySelectOptions.create()); } @Override @@ -254,12 +255,12 @@ public CompletableFuture select( if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return select(conditions, rowsMetadataTupleResultMapper(), options); + return select(conditions, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture select( Conditions conditions, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, SelectOptions options) throws TarantoolClientException { SelectProxyOperation operation = new SelectProxyOperation.Builder(metadataOperations, spaceMetadata) @@ -267,8 +268,8 @@ private CompletableFuture select( .withSpaceName(spaceName) .withFunctionName(operationsMapping.getSelectFunctionName()) .withConditions(conditions) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); @@ -277,7 +278,7 @@ private CompletableFuture select( @Override public CompletableFuture update(Conditions conditions, T tuple) { - return update(conditions, makeOperationsFromTuple(tuple), rowsMetadataTupleResultMapper(), + return update(conditions, makeOperationsFromTuple(tuple), this::rowsMetadataTupleResultMapper, ProxyUpdateOptions.create() ); } @@ -287,7 +288,7 @@ public CompletableFuture update(Conditions conditions, T tuple, UpdateOptions if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return update(conditions, makeOperationsFromTuple(tuple), rowsMetadataTupleResultMapper(), options); + return update(conditions, makeOperationsFromTuple(tuple), this::rowsMetadataTupleResultMapper, options); } /** @@ -300,7 +301,7 @@ public CompletableFuture update(Conditions conditions, T tuple, UpdateOptions @Override public CompletableFuture update(Conditions conditions, TupleOperations operations) { - return update(conditions, operations, rowsMetadataTupleResultMapper(), ProxyUpdateOptions.create()); + return update(conditions, operations, this::rowsMetadataTupleResultMapper, ProxyUpdateOptions.create()); } @Override @@ -308,13 +309,13 @@ public CompletableFuture update(Conditions conditions, TupleOperations operat if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return update(conditions, operations, rowsMetadataTupleResultMapper(), options); + return update(conditions, operations, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture update( Conditions conditions, TupleOperations operations, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, UpdateOptions options) { TarantoolIndexQuery indexQuery = conditions.toIndexQuery(metadataOperations, spaceMetadata); @@ -324,8 +325,8 @@ private CompletableFuture update( .withFunctionName(operationsMapping.getUpdateFunctionName()) .withIndexQuery(indexQuery) .withTupleOperation(operations) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); @@ -334,7 +335,7 @@ private CompletableFuture update( @Override public CompletableFuture upsert(Conditions conditions, T tuple, TupleOperations operations) { - return upsert(conditions, tuple, operations, rowsMetadataTupleResultMapper(), ProxyUpsertOptions.create()); + return upsert(conditions, tuple, operations, this::rowsMetadataTupleResultMapper, ProxyUpsertOptions.create()); } @Override @@ -344,14 +345,14 @@ public CompletableFuture upsert( if (options == null) { throw new IllegalArgumentException("Options should not be null"); } - return upsert(conditions, tuple, operations, rowsMetadataTupleResultMapper(), options); + return upsert(conditions, tuple, operations, this::rowsMetadataTupleResultMapper, options); } private CompletableFuture upsert( Conditions conditions, T tuple, TupleOperations operations, - CallResultMapper> resultMapper, + Supplier>> resultMapperSupplier, UpsertOptions options) { UpsertProxyOperation operation = new UpsertProxyOperation.Builder() @@ -360,8 +361,8 @@ private CompletableFuture upsert( .withFunctionName(operationsMapping.getUpsertFunctionName()) .withTuple(tuple) .withTupleOperation(operations) - .withArgumentsMapper(config.getMessagePackMapper()) - .withResultMapper(resultMapper) + .withArgumentsMapperSupplier(config::getMessagePackMapper) + .withResultMapperSupplier(resultMapperSupplier) .withOptions(options) .build(); diff --git a/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolTupleSpace.java b/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolTupleSpace.java index 488489950..aef5f6a52 100644 --- a/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolTupleSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolTupleSpace.java @@ -24,6 +24,9 @@ public class ProxyTarantoolTupleSpace private final TarantoolClientConfig config; private final TarantoolCallOperations client; + private final + CallResultMapper, SingleValueCallResult>> + rowsMetadataTupleResultMapper; /** * Basic constructor @@ -43,6 +46,9 @@ public ProxyTarantoolTupleSpace( super(config, client, mappingConfig, metadataOperations, spaceMetadata); this.config = config; this.client = client; + this.rowsMetadataTupleResultMapper = client + .getResultMapperFactoryFactory().getTarantoolTupleResultMapperFactory() + .withSingleValueRowsMetadataToTarantoolTupleResultMapper(config.getMessagePackMapper(), getMetadata()); } @Override @@ -53,8 +59,7 @@ protected TupleOperations makeOperationsFromTuple(TarantoolTuple tuple) { @Override protected CallResultMapper, SingleValueCallResult>> rowsMetadataTupleResultMapper() { - return client.getResultMapperFactoryFactory().getTarantoolTupleResultMapperFactory() - .withSingleValueRowsMetadataToTarantoolTupleResultMapper(config.getMessagePackMapper(), getMetadata()); + return rowsMetadataTupleResultMapper; } @Override 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 25ac8d9d1..5700e328f 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,9 +29,12 @@ 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; import java.util.stream.Collectors; /** @@ -46,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, @@ -57,14 +62,36 @@ 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 public CompletableFuture delete(Conditions conditions) throws TarantoolClientException { - return delete(conditions, arrayTupleResultMapper()); + return delete(conditions, this::arrayTupleResultMapper); } - private CompletableFuture delete(Conditions conditions, MessagePackValueMapper resultMapper) + private CompletableFuture delete(Conditions conditions, Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolIndexQuery indexQuery = conditions.toIndexQuery(metadataOperations, spaceMetadata); @@ -73,9 +100,10 @@ private CompletableFuture delete(Conditions conditions, MessagePackValueMappe .withSpaceId(spaceId) .withIndexId(indexQuery.getIndexId()) .withKeyValues(indexQuery.getKeyValues()) + .withSignature(methodSignatures.get(TarantoolDeleteRequest.class.getName())) .build(config.getMessagePackMapper()); - return sendRequest(request, resultMapper); + return sendRequest(request, resultMapperSupplier); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } @@ -83,7 +111,7 @@ private CompletableFuture delete(Conditions conditions, MessagePackValueMappe @Override public CompletableFuture insert(T tuple) throws TarantoolClientException { - return insert(tuple, arrayTupleResultMapper()); + return insert(tuple, this::arrayTupleResultMapper); } @Override @@ -94,15 +122,16 @@ public CompletableFuture insertMany(Collection tuples) throws TarantoolCli "Standalone node API does not support inserting several tuples at once yet"); } - private CompletableFuture insert(T tuple, MessagePackValueMapper resultMapper) + private CompletableFuture insert(T tuple, Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolInsertRequest request = new TarantoolInsertRequest.Builder() .withSpaceId(spaceId) .withTuple(tuple) + .withSignature(methodSignatures.get(TarantoolInsertRequest.class.getName())) .build(config.getMessagePackMapper()); - return sendRequest(request, resultMapper); + return sendRequest(request, resultMapperSupplier); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } @@ -110,7 +139,7 @@ private CompletableFuture insert(T tuple, MessagePackValueMapper resultMapper @Override public CompletableFuture replace(T tuple) throws TarantoolClientException { - return replace(tuple, arrayTupleResultMapper()); + return replace(tuple, this::arrayTupleResultMapper); } @Override @@ -121,15 +150,16 @@ public CompletableFuture replaceMany(Collection tuples) throws TarantoolCl "Standalone node API does not support replacing several tuples at once yet"); } - private CompletableFuture replace(T tuple, MessagePackValueMapper resultMapper) + private CompletableFuture replace(T tuple, Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolReplaceRequest request = new TarantoolReplaceRequest.Builder() .withSpaceId(spaceId) .withTuple(tuple) + .withSignature(methodSignatures.get(TarantoolReplaceRequest.class.getName())) .build(config.getMessagePackMapper()); - return sendRequest(request, resultMapper); + return sendRequest(request, resultMapperSupplier); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } @@ -137,10 +167,10 @@ private CompletableFuture replace(T tuple, MessagePackValueMapper resultMappe @Override public CompletableFuture select(Conditions conditions) throws TarantoolClientException { - return select(conditions, arrayTupleResultMapper()); + return select(conditions, this::arrayTupleResultMapper); } - private CompletableFuture select(Conditions conditions, MessagePackValueMapper resultMapper) + private CompletableFuture select(Conditions conditions, Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolIndexQuery indexQuery = conditions.toIndexQuery(metadataOperations, spaceMetadata); @@ -151,9 +181,10 @@ private CompletableFuture select(Conditions conditions, MessagePackValueMappe .withKeyValues(indexQuery.getKeyValues()) .withLimit(conditions.getLimit()) .withOffset(conditions.getOffset()) + .withSignature(methodSignatures.get(TarantoolSelectRequest.class.getName())) .build(config.getMessagePackMapper()); - return sendRequest(request, resultMapper); + return sendRequest(request, resultMapperSupplier); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } @@ -161,7 +192,7 @@ private CompletableFuture select(Conditions conditions, MessagePackValueMappe @Override public CompletableFuture update(Conditions conditions, T tuple) { - return update(conditions, makeOperationsFromTuple(tuple), arrayTupleResultMapper()); + return update(conditions, makeOperationsFromTuple(tuple), this::arrayTupleResultMapper); } /** @@ -174,13 +205,13 @@ public CompletableFuture update(Conditions conditions, T tuple) { @Override public CompletableFuture update(Conditions conditions, TupleOperations operations) { - return update(conditions, operations, arrayTupleResultMapper()); + return update(conditions, operations, this::arrayTupleResultMapper); } private CompletableFuture update( Conditions conditions, TupleOperations operations, - MessagePackValueMapper resultMapper) + Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolIndexQuery indexQuery = conditions.toIndexQuery(metadataOperations, spaceMetadata); @@ -197,9 +228,10 @@ private CompletableFuture update( .withIndexId(indexQuery.getIndexId()) .withKeyValues(indexQuery.getKeyValues()) .withTupleOperations(fillFieldIndexFromMetadata(operations)) + .withSignature(methodSignatures.get(TarantoolUpdateRequest.class.getName())) .build(config.getMessagePackMapper()); - return sendRequest(request, resultMapper); + return sendRequest(request, resultMapperSupplier); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } @@ -207,14 +239,14 @@ private CompletableFuture update( @Override public CompletableFuture upsert(Conditions conditions, T tuple, TupleOperations operations) { - return upsert(conditions, tuple, operations, arrayTupleResultMapper()); + return upsert(conditions, tuple, operations, this::arrayTupleResultMapper); } private CompletableFuture upsert( Conditions conditions, T tuple, TupleOperations operations, - MessagePackValueMapper resultMapper) + Supplier resultMapperSupplier) throws TarantoolClientException { try { TarantoolIndexQuery indexQuery = conditions.toIndexQuery(metadataOperations, spaceMetadata); @@ -224,9 +256,10 @@ private CompletableFuture upsert( .withKeyValues(indexQuery.getKeyValues()) .withTuple(tuple) .withTupleOperations(fillFieldIndexFromMetadata(operations)) + .withSignature(methodSignatures.get(TarantoolUpsertRequest.class.getName())) .build(config.getMessagePackMapper()); - return sendRequest(request, resultMapper); + return sendRequest(request, resultMapperSupplier); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); } @@ -234,17 +267,18 @@ private CompletableFuture upsert( @Override public CompletableFuture truncate() throws TarantoolClientException { - return truncate(arrayTupleResultMapper()); + return truncate(this::arrayTupleResultMapper); } - private CompletableFuture truncate(MessagePackValueMapper resultMapper) + private CompletableFuture truncate(Supplier resultMapperSupplier) throws TarantoolClientException { try { String spaceName = spaceMetadata.getSpaceName(); TarantoolCallRequest request = new TarantoolCallRequest.Builder() .withFunctionName("box.space." + spaceName + ":truncate") + .withSignature(methodSignatures.get("truncate")) .build(config.getMessagePackMapper()); - return sendRequest(request, resultMapper) + return sendRequest(request, resultMapperSupplier) .thenApply(v -> TarantoolVoidResult.INSTANCE.value()); } catch (TarantoolProtocolException e) { throw new TarantoolClientException(e); @@ -259,8 +293,12 @@ private CompletableFuture truncate(MessagePackValueMapper resultMapper) */ protected abstract MessagePackValueMapper arrayTupleResultMapper(); - private CompletableFuture sendRequest(TarantoolRequest request, MessagePackValueMapper resultMapper) { - return connectionManager.getConnection().thenCompose(c -> c.sendRequest(request, resultMapper)); + private CompletableFuture sendRequest( + TarantoolRequest request, Supplier resultMapperSupplier) { + MessagePackValueMapper resultMapper = resultMapperSupplier.get(); + return connectionManager.getConnection() + .thenCompose(c -> c.sendRequest(request).getFuture()) + .thenApply(resultMapper::fromValue); } @Override diff --git a/src/main/java/io/tarantool/driver/core/space/TarantoolTupleSpace.java b/src/main/java/io/tarantool/driver/core/space/TarantoolTupleSpace.java index 8c85ed4a1..c3941a071 100644 --- a/src/main/java/io/tarantool/driver/core/space/TarantoolTupleSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/TarantoolTupleSpace.java @@ -23,6 +23,7 @@ public class TarantoolTupleSpace extends private final TarantoolCallOperations client; private final TarantoolClientConfig config; + private final MessagePackValueMapper arrayTupleResultMapper; /** * Basic constructor @@ -42,6 +43,8 @@ public TarantoolTupleSpace( super(config, connectionManager, metadataOperations, spaceMetadata); this.client = client; this.config = config; + this.arrayTupleResultMapper = client.getResultMapperFactoryFactory().getTarantoolTupleResultMapperFactory() + .withArrayValueToTarantoolTupleResultConverter(config.getMessagePackMapper(), getMetadata()); } @Override @@ -51,8 +54,7 @@ protected TupleOperations makeOperationsFromTuple(TarantoolTuple tuple) { @Override protected MessagePackValueMapper arrayTupleResultMapper() { - return client.getResultMapperFactoryFactory().getTarantoolTupleResultMapperFactory() - .withArrayValueToTarantoolTupleResultConverter(config.getMessagePackMapper(), getMetadata()); + return arrayTupleResultMapper; } @Override diff --git a/src/main/java/io/tarantool/driver/handlers/TarantoolRequestHandler.java b/src/main/java/io/tarantool/driver/handlers/TarantoolRequestHandler.java index db5dabb46..b44002b4f 100644 --- a/src/main/java/io/tarantool/driver/handlers/TarantoolRequestHandler.java +++ b/src/main/java/io/tarantool/driver/handlers/TarantoolRequestHandler.java @@ -5,15 +5,20 @@ import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; import io.tarantool.driver.core.RequestFutureManager; +import io.tarantool.driver.core.TarantoolRequestMetadata; import io.tarantool.driver.exceptions.TarantoolClientException; import io.tarantool.driver.protocol.TarantoolRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Performs registration of requests and pushes them forward. Should stay first in the channel pipeline * * @author Alexey Kuzin */ public class TarantoolRequestHandler extends ChannelOutboundHandlerAdapter { + private final Logger log = LoggerFactory.getLogger(TarantoolRequestHandler.class); private final RequestFutureManager futureManager; public TarantoolRequestHandler(RequestFutureManager futureManager) { @@ -25,8 +30,15 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) TarantoolRequest request = (TarantoolRequest) msg; ctx.write(request).addListener((ChannelFutureListener) channelFuture -> { if (!channelFuture.isSuccess()) { - futureManager.getRequest(request.getHeader().getSync()).getFuture() - .completeExceptionally(new TarantoolClientException(channelFuture.cause())); + TarantoolRequestMetadata requestMeta = futureManager.getRequest(request.getHeader().getSync()); + // The request metadata may has been deleted already after timeout + if (requestMeta != null) { + requestMeta.getFuture() + .completeExceptionally(new TarantoolClientException(channelFuture.cause())); + } else { + log.info( + "Received an error for {} but it is already timed out: {}", request, channelFuture.cause()); + } } }); } diff --git a/src/main/java/io/tarantool/driver/handlers/TarantoolResponseHandler.java b/src/main/java/io/tarantool/driver/handlers/TarantoolResponseHandler.java index 677fc79d6..dba9e8176 100644 --- a/src/main/java/io/tarantool/driver/handlers/TarantoolResponseHandler.java +++ b/src/main/java/io/tarantool/driver/handlers/TarantoolResponseHandler.java @@ -10,6 +10,8 @@ import io.tarantool.driver.protocol.TarantoolErrorResult; import io.tarantool.driver.protocol.TarantoolOkResult; import io.tarantool.driver.protocol.TarantoolResponse; + +import org.msgpack.value.Value; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,7 +38,7 @@ public TarantoolResponseHandler(RequestFutureManager futureManager) { protected void channelRead0(ChannelHandlerContext ctx, TarantoolResponse tarantoolResponse) throws Exception { TarantoolRequestMetadata requestMeta = futureManager.getRequest(tarantoolResponse.getSyncId()); if (requestMeta != null) { - CompletableFuture requestFuture = requestMeta.getFuture(); + CompletableFuture requestFuture = requestMeta.getFuture(); if (!requestFuture.isDone()) { switch (tarantoolResponse.getResponseType()) { case IPROTO_NOT_OK: @@ -48,7 +50,7 @@ protected void channelRead0(ChannelHandlerContext ctx, TarantoolResponse taranto try { TarantoolOkResult okResult = new TarantoolOkResult(tarantoolResponse.getSyncId(), tarantoolResponse.getBody().getData()); - requestFuture.complete(requestMeta.getMapper().fromValue(okResult.getData())); + requestFuture.complete(okResult.getData()); } catch (Throwable e) { requestFuture.completeExceptionally(e); } @@ -65,7 +67,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E TarantoolDecoderException ex = (TarantoolDecoderException) cause.getCause(); TarantoolRequestMetadata requestMeta = futureManager.getRequest(ex.getHeader().getSync()); if (requestMeta != null) { - CompletableFuture requestFuture = requestMeta.getFuture(); + CompletableFuture requestFuture = requestMeta.getFuture(); if (!requestFuture.isDone()) { requestFuture.completeExceptionally(cause); return; diff --git a/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultCollectionToArrayValueConverter.java b/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultCollectionToArrayValueConverter.java index 379ba3916..c12b08852 100644 --- a/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultCollectionToArrayValueConverter.java +++ b/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultCollectionToArrayValueConverter.java @@ -30,6 +30,6 @@ public ArrayValue toValue(Collection object) { for (Object value : object) { values[i++] = value == null ? ValueFactory.newNil() : mapper.toValue(value); } - return ValueFactory.newArray(values, false); + return ValueFactory.newArray(values, true); } } diff --git a/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultListToArrayValueConverter.java b/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultListToArrayValueConverter.java index 920644d5f..867eeef9f 100644 --- a/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultListToArrayValueConverter.java +++ b/src/main/java/io/tarantool/driver/mappers/converters/object/DefaultListToArrayValueConverter.java @@ -30,6 +30,6 @@ public ArrayValue toValue(List object) { for (Object value : object) { values[i++] = value == null ? ValueFactory.newNil() : mapper.toValue(value); } - return ValueFactory.newArray(values, false); + return ValueFactory.newArray(values, true); } } diff --git a/src/main/java/io/tarantool/driver/protocol/TarantoolRequest.java b/src/main/java/io/tarantool/driver/protocol/TarantoolRequest.java index a7decfb4a..219868330 100644 --- a/src/main/java/io/tarantool/driver/protocol/TarantoolRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/TarantoolRequest.java @@ -6,6 +6,7 @@ import org.msgpack.core.MessagePacker; import java.io.IOException; +import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; @@ -16,7 +17,7 @@ * * @author Alexey Kuzin */ -public class TarantoolRequest { +public abstract class TarantoolRequest { private static final AtomicLong syncId = new AtomicLong(0); private static final Supplier syncIdSupplier = @@ -24,17 +25,20 @@ public class TarantoolRequest { private final TarantoolHeader header; private final TarantoolRequestBody body; + private final Optional signature; /** * Basic constructor. Sets an auto-incremented request ID into the Tarantool packet header. * - * @param type request type code supported by Tarantool - * @param body request body, may be empty + * @param type request type code supported by Tarantool + * @param body request body, may be empty + * @param signature request signature, may be null * @see TarantoolRequestType */ - public TarantoolRequest(TarantoolRequestType type, TarantoolRequestBody body) { + public TarantoolRequest(TarantoolRequestType type, TarantoolRequestBody body, TarantoolRequestSignature signature) { this.header = new TarantoolHeader(syncIdSupplier.get(), type.getCode()); this.body = body; + this.signature = Optional.ofNullable(signature); } /** @@ -51,10 +55,19 @@ public TarantoolHeader getHeader() { * * @return instance of a {@link Packable} */ - public Packable getBody() { + public TarantoolRequestBody getBody() { return body; } + /** + * Get signature + * + * @return request signature that uniquely represents the operation and argument types + */ + public Optional getSignature() { + return signature; + } + /** * Encode incapsulated data using {@link MessagePacker} * @@ -71,4 +84,30 @@ public void toMessagePack(MessagePacker packer, MessagePackObjectMapper mapper) throw new TarantoolDecoderException(header, e); } } + + @Override + public String toString() { + return !signature.isPresent() ? + String.format("request id: %d", header.getSync()) : + String.format("request signature: %s", signature.get()); + } + + /** + * Base class for request builder implementations + */ + protected abstract static class Builder> { + protected TarantoolRequestSignature signature; + + protected abstract B self(); + + /** + * Set request signature + * + * @param signature request signature + */ + public B withSignature(TarantoolRequestSignature signature) { + this.signature = signature; + return self(); + } + } } diff --git a/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java b/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java new file mode 100644 index 000000000..d22a2ecb8 --- /dev/null +++ b/src/main/java/io/tarantool/driver/protocol/TarantoolRequestSignature.java @@ -0,0 +1,105 @@ +package io.tarantool.driver.protocol; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import io.tarantool.driver.mappers.MessagePackObjectMapper; +import io.tarantool.driver.mappers.MessagePackValueMapper; + +/** + * Represents a request signature, uniquely defining the operation and the + * argument types. May include some argument values as well. + * + * The hashcode calculation is not thread safe. + * + * @author Alexey Kuzin + */ +public class TarantoolRequestSignature { + + private List components = new LinkedList<>(); + private int hashCode = 1; + + /** + * Constructor. + * + * Stores either the component values if the component is of type String or the + * class names and calculates the hashcode from the passed initial set of + * components. + * + * @param initialComponents initial signature components + */ + public TarantoolRequestSignature(Object... initialComponents) { + for (Object component : initialComponents) { + String componentValue = component instanceof String ? (String) component : component.getClass().getName(); + components.add(componentValue); + hashCode = 31 * hashCode + Objects.hashCode(componentValue); + } + } + + /** + * Add a signature component to the end of the components list + * + * Appends either the component value if the component is of type String or the + * component class to the components list and re-calculates the hashcode. + * + * @param component signature component + * @return this signature object instance + */ + public TarantoolRequestSignature addComponent(Object component) { + String componentValue = component instanceof String ? (String) component : component.getClass().getName(); + components.add(componentValue); + hashCode = 31 * hashCode + Objects.hashCode(componentValue); + return this; + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object other) { + return other instanceof TarantoolRequestSignature + && Objects.equals(this.components, ((TarantoolRequestSignature) other).components); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("["); + for (Object component : components) { + sb.append(String.valueOf(component)).append(","); + } + 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 + * @param argumentsMapperSupplier arguments mapper supplier + * @param resultMapperSupplier result mapper supplier + * @return new request signature + */ + public static TarantoolRequestSignature create(String functionName, Collection arguments, Class resultClass, + Supplier argumentsMapperSupplier, + Supplier resultMapperSupplier) { + List components = new ArrayList<>(arguments.size() + 4); + components.add(functionName); + for (Object argument : arguments) { + components.add(argument.getClass().getName()); + } + components.add(resultClass.getName()); + components.add(Integer.toHexString(argumentsMapperSupplier.hashCode())); + components.add(Integer.toHexString(resultMapperSupplier.hashCode())); + return new TarantoolRequestSignature(components.toArray(new Object[] {})); + } +} diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolAuthRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolAuthRequest.java index 0275cb981..f2bcf19dd 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolAuthRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolAuthRequest.java @@ -6,6 +6,7 @@ import io.tarantool.driver.protocol.TarantoolProtocolException; import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import io.tarantool.driver.utils.Assert; @@ -25,14 +26,14 @@ public final class TarantoolAuthRequest extends TarantoolRequest { private static final int IPROTO_USER_NAME = 0x23; private static final int IPROTO_AUTH_DATA = 0x21; - private TarantoolAuthRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_AUTH, body); + private TarantoolAuthRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_AUTH, body, signature); } /** * Tarantool authentication request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { private final Map authMap; @@ -43,6 +44,11 @@ public Builder() { authMap = new HashMap<>(2, 1); } + @Override + protected Builder self() { + return this; + } + public Builder withUsername(String username) { Assert.hasText(username, "Username must not be empty"); @@ -63,7 +69,7 @@ public TarantoolAuthRequest build() throws TarantoolProtocolException { "Username and auth data must be specified for Tarantool auth request"); } MessagePackObjectMapper mapper = DefaultMessagePackMapperFactory.getInstance().defaultComplexTypesMapper(); - return new TarantoolAuthRequest(new TarantoolRequestBody(authMap, mapper)); + return new TarantoolAuthRequest(new TarantoolRequestBody(authMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolCallRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolCallRequest.java index a566e73f4..d0c888a52 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolCallRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolCallRequest.java @@ -5,6 +5,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.Collection; @@ -20,14 +21,14 @@ */ public final class TarantoolCallRequest extends TarantoolRequest { - private TarantoolCallRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_CALL, body); + private TarantoolCallRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_CALL, body, signature); } /** * Tarantool call request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -35,6 +36,11 @@ public Builder() { this.bodyMap = new HashMap<>(2, 1); } + @Override + protected Builder self() { + return this; + } + /** * Specify function name * @@ -69,7 +75,7 @@ public TarantoolCallRequest build(MessagePackObjectMapper mapper) throws Taranto throw new TarantoolProtocolException("Function name must be specified in the call request"); } - return new TarantoolCallRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolCallRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolDeleteRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolDeleteRequest.java index 2a3f89352..720ebda45 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolDeleteRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolDeleteRequest.java @@ -6,6 +6,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.HashMap; @@ -23,14 +24,14 @@ */ public final class TarantoolDeleteRequest extends TarantoolRequest { - private TarantoolDeleteRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_DELETE, body); + private TarantoolDeleteRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_DELETE, body, signature); } /** * Tarantool delete request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -38,6 +39,11 @@ public Builder() { this.bodyMap = new HashMap<>(3, 1); } + @Override + protected Builder self() { + return this; + } + /** * Specify tarantool space ID for operation * @@ -93,7 +99,7 @@ public TarantoolDeleteRequest build(MessagePackObjectMapper mapper) throws Taran throw new TarantoolProtocolException("Key values must be specified in the delete request"); } - return new TarantoolDeleteRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolDeleteRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolEvalRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolEvalRequest.java index d3e1ec95b..2f9c71309 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolEvalRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolEvalRequest.java @@ -5,6 +5,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.Collection; @@ -20,14 +21,14 @@ */ public final class TarantoolEvalRequest extends TarantoolRequest { - private TarantoolEvalRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_EVAL, body); + private TarantoolEvalRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_EVAL, body, signature); } /** * Tarantool eval request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -35,6 +36,11 @@ public Builder() { this.bodyMap = new HashMap<>(2, 1); } + @Override + protected Builder self() { + return this; + } + /** * Specify lua expression * @@ -69,7 +75,7 @@ public TarantoolEvalRequest build(MessagePackObjectMapper mapper) throws Taranto throw new TarantoolProtocolException("Lua expression must be specified in the eval request"); } - return new TarantoolEvalRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolEvalRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolInsertRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolInsertRequest.java index a2feb3b71..3b731924a 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolInsertRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolInsertRequest.java @@ -6,6 +6,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.HashMap; @@ -20,14 +21,14 @@ */ public final class TarantoolInsertRequest extends TarantoolRequest { - private TarantoolInsertRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_INSERT, body); + private TarantoolInsertRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_INSERT, body, signature); } /** * Tarantool insert request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -35,6 +36,11 @@ public Builder() { this.bodyMap = new HashMap<>(2, 1); } + @Override + protected Builder self() { + return this; + } + /** * Specify tarantool space ID for operation * @@ -72,7 +78,7 @@ public TarantoolInsertRequest build(MessagePackObjectMapper mapper) throws Taran throw new TarantoolProtocolException("Tuple value must be specified for the insert request"); } - return new TarantoolInsertRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolInsertRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolReplaceRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolReplaceRequest.java index a6e7ab55b..308e3316f 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolReplaceRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolReplaceRequest.java @@ -6,6 +6,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.HashMap; @@ -20,14 +21,14 @@ */ public final class TarantoolReplaceRequest extends TarantoolRequest { - private TarantoolReplaceRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_REPLACE, body); + private TarantoolReplaceRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_REPLACE, body, signature); } /** * Tarantool replace request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -35,6 +36,11 @@ public Builder() { this.bodyMap = new HashMap<>(2, 1); } + @Override + protected Builder self() { + return this; + } + /** * Specify tarantool space ID for operation * @@ -72,7 +78,7 @@ public TarantoolReplaceRequest build(MessagePackObjectMapper mapper) throws Tara throw new TarantoolProtocolException("Tuple value must be specified for the replace request"); } - return new TarantoolReplaceRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolReplaceRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolSelectRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolSelectRequest.java index d520fb113..d131b11f8 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolSelectRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolSelectRequest.java @@ -6,6 +6,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.HashMap; @@ -21,14 +22,14 @@ */ public final class TarantoolSelectRequest extends TarantoolRequest { - private TarantoolSelectRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_SELECT, body); + private TarantoolSelectRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_SELECT, body, signature); } /** * Tarantool select request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -36,6 +37,11 @@ public Builder() { this.bodyMap = new HashMap<>(6, 1); } + @Override + protected Builder self() { + return this; + } + /** * Specify tarantool space ID for operation * @@ -128,7 +134,7 @@ public TarantoolSelectRequest build(MessagePackObjectMapper mapper) throws Taran if (!bodyMap.containsKey(TarantoolRequestFieldType.IPROTO_KEY.getCode())) { throw new TarantoolProtocolException("Key values must be specified in the select request"); } - return new TarantoolSelectRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolSelectRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpdateRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpdateRequest.java index 826c51ddd..d894afb7e 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpdateRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpdateRequest.java @@ -7,6 +7,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.HashMap; @@ -25,14 +26,14 @@ public final class TarantoolUpdateRequest extends TarantoolRequest { /** * (non-Javadoc) */ - private TarantoolUpdateRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_UPDATE, body); + private TarantoolUpdateRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_UPDATE, body, signature); } /** * Tarantool update request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -40,6 +41,11 @@ public Builder() { this.bodyMap = new HashMap<>(4, 1); } + @Override + protected Builder self() { + return this; + } + public Builder withSpaceId(int spaceId) { this.bodyMap.put(TarantoolRequestFieldType.IPROTO_SPACE_ID.getCode(), spaceId); return this; @@ -74,7 +80,7 @@ public TarantoolUpdateRequest build(MessagePackObjectMapper mapper) throws Taran throw new TarantoolProtocolException("Update operations must be specified for the update request"); } - return new TarantoolUpdateRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolUpdateRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpsertRequest.java b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpsertRequest.java index d23816cd2..941687ae1 100644 --- a/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpsertRequest.java +++ b/src/main/java/io/tarantool/driver/protocol/requests/TarantoolUpsertRequest.java @@ -7,6 +7,7 @@ import io.tarantool.driver.protocol.TarantoolRequest; import io.tarantool.driver.protocol.TarantoolRequestBody; import io.tarantool.driver.protocol.TarantoolRequestFieldType; +import io.tarantool.driver.protocol.TarantoolRequestSignature; import io.tarantool.driver.protocol.TarantoolRequestType; import java.util.HashMap; @@ -25,14 +26,14 @@ public final class TarantoolUpsertRequest extends TarantoolRequest { /** * (non-Javadoc) */ - private TarantoolUpsertRequest(TarantoolRequestBody body) { - super(TarantoolRequestType.IPROTO_UPSERT, body); + private TarantoolUpsertRequest(TarantoolRequestBody body, TarantoolRequestSignature signature) { + super(TarantoolRequestType.IPROTO_UPSERT, body, signature); } /** * Tarantool update request builder */ - public static class Builder { + public static class Builder extends TarantoolRequest.Builder { Map bodyMap; @@ -40,6 +41,11 @@ public Builder() { this.bodyMap = new HashMap<>(4, 1); } + @Override + protected Builder self() { + return this; + } + public Builder withSpaceId(int spaceId) { this.bodyMap.put(TarantoolRequestFieldType.IPROTO_SPACE_ID.getCode(), spaceId); return this; @@ -74,7 +80,7 @@ public TarantoolUpsertRequest build(MessagePackObjectMapper mapper) throws Taran throw new TarantoolProtocolException("Update operations must be specified for the upsert request"); } - return new TarantoolUpsertRequest(new TarantoolRequestBody(bodyMap, mapper)); + return new TarantoolUpsertRequest(new TarantoolRequestBody(bodyMap, mapper), signature); } } } diff --git a/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java b/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java new file mode 100644 index 000000000..4792b0620 --- /dev/null +++ b/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java @@ -0,0 +1,134 @@ +package io.tarantool.driver.benchmark; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +import io.tarantool.driver.api.TarantoolResult; +import io.tarantool.driver.api.conditions.Conditions; +import io.tarantool.driver.api.space.TarantoolSpaceOperations; +import io.tarantool.driver.api.tuple.TarantoolTuple; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.infra.Blackhole; + +@Fork(value = 1, jvmArgsAppend = "-Xmx1G") +public class ClusterBenchmarkRunner { + private static final String TEST_SPACE = "test_space"; + private static final String TEST_PROFILE = "test__profile"; + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + + @Benchmark + @Measurement(iterations = 10) + @OperationsPerInvocation(2) + public void getSpaceObject(ClusterTarantoolSetup plan, Blackhole bh) { + TarantoolSpaceOperations> testSpace = + plan.tarantoolClient.space(TEST_SPACE); + bh.consume(testSpace); + + TarantoolSpaceOperations> profileSpace = + plan.tarantoolClient.space(TEST_PROFILE); + bh.consume(profileSpace); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Measurement(iterations = 10) + @OperationsPerInvocation(2000) + public void writeData(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) { + // Fill 10000 rows into both spaces + TarantoolTuple tarantoolTuple; + String uuid; + int nextId = 0; + for (int i = 0; i < 1_000; i++) { + uuid = UUID.randomUUID().toString(); + nextId = plan.nextTestSpaceId + i; + tarantoolTuple = plan.tupleFactory.create(1_000_000 + nextId, null, uuid, 200_000 + nextId); + futuresHolder.allFutures.add(spaces.testSpace.insert(tarantoolTuple)); + tarantoolTuple = plan.tupleFactory.create(1_000_000 + nextId, null, uuid, 50_000 + nextId, 100_000 + i); + futuresHolder.allFutures.add(spaces.profileSpace.insert(tarantoolTuple)); + } + nextId++; + plan.nextTestSpaceId = nextId; + plan.nextProfileSpaceId = nextId; + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Measurement(iterations = 10) + @OperationsPerInvocation(1000) + public void readDataUsingCallAPI(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Blackhole bh) { + boolean coin = Math.random() - 0.5 > 0; + String spaceName = coin ? TEST_SPACE : TEST_PROFILE; + long nextId; + for (int i = 0; i < 1_000; i++) { + nextId = Math.round(Math.random() * 10_000) + 1_000_000; + futuresHolder.allFutures.add( + plan.tarantoolClient.callForSingleResult( + "custom_crud_get_one_record", Arrays.asList(spaceName, nextId), List.class) + ); + } + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Measurement(iterations = 10) + @OperationsPerInvocation(1000) + public void readDataUsingSpaceAPI( + ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) { + boolean coin = Math.random() - 0.5 > 0; + TarantoolSpaceOperations> space = coin ? + spaces.testSpace : spaces.profileSpace; + String pkFieldName = coin ? "id" : "profile_id"; + long nextId; + for (int i = 0; i < 1_000; i++) { + nextId = Math.round(Math.random() * 10_000) + 1_000_000; + futuresHolder.allFutures.add( + space.select(Conditions.indexEquals(pkFieldName, Collections.singletonList(nextId))) + ); + } + } + + @State(Scope.Thread) + public static class FuturesHolder { + final List> allFutures = new ArrayList<>(2_000); + + @Setup(Level.Invocation) + public void doSetup() { + allFutures.clear(); + } + + @TearDown(Level.Invocation) + public void doTeardown() { + allFutures.forEach(CompletableFuture::join); + } + } + + @State(Scope.Thread) + public static class Spaces { + TarantoolSpaceOperations> testSpace; + TarantoolSpaceOperations> profileSpace; + + @Setup(Level.Iteration) + public void doSetup(ClusterTarantoolSetup plan) { + testSpace = plan.tarantoolClient.space(TEST_SPACE); + profileSpace = plan.tarantoolClient.space(TEST_PROFILE); + } + } +} diff --git a/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java b/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java new file mode 100644 index 000000000..c1ce53105 --- /dev/null +++ b/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java @@ -0,0 +1,80 @@ +package io.tarantool.driver.benchmark; + +import java.time.Duration; + +import io.tarantool.driver.api.TarantoolClient; +import io.tarantool.driver.api.TarantoolClientFactory; +import io.tarantool.driver.api.TarantoolResult; +import io.tarantool.driver.api.TarantoolServerAddress; +import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory; +import io.tarantool.driver.api.tuple.TarantoolTuple; +import io.tarantool.driver.api.tuple.TarantoolTupleFactory; +import io.tarantool.driver.mappers.factories.DefaultMessagePackMapperFactory; +import io.tarantool.driver.mappers.MessagePackMapper; + +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.TarantoolCartridgeContainer; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.containers.wait.strategy.Wait; + +@State(Scope.Benchmark) +public class ClusterTarantoolSetup { + public Logger logger = LoggerFactory.getLogger(ClusterTarantoolSetup.class); + + final MessagePackMapper defaultMapper = + DefaultMessagePackMapperFactory.getInstance().defaultComplexTypesMapper(); + final TarantoolTupleFactory tupleFactory = new DefaultTarantoolTupleFactory(defaultMapper); + + final TarantoolCartridgeContainer tarantoolContainer = + new TarantoolCartridgeContainer( + "Dockerfile", + "cartridge-java-test", + "cartridge/instances.yml", + "cartridge/topology.lua") + .withDirectoryBinding("cartridge") + .withLogConsumer(new Slf4jLogConsumer(logger)) + .waitingFor(Wait.forLogMessage(".*Listening HTTP on.*", 5)) + .withStartupTimeout(Duration.ofMinutes(2)); + + TarantoolClient> tarantoolClient; + + int nextTestSpaceId; + int nextProfileSpaceId; + + private void initClient() { + tarantoolClient = TarantoolClientFactory.createClient() + .withAddresses( + new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3301)), + new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3302)), + new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3303)) + ) + .withCredentials(tarantoolContainer.getUsername(), tarantoolContainer.getPassword()) + .withConnections(10) + .withEventLoopThreadsNumber(10) + .withRequestTimeout(10000) + .withProxyMethodMapping() + .build(); + } + + @Setup(Level.Trial) + public void doSetup() { + System.out.println("Do Setup"); + if (!tarantoolContainer.isRunning()) { + tarantoolContainer.start(); + } + initClient(); + } + + @TearDown(Level.Trial) + public void doTearDown() throws Exception { + System.out.println("Do TearDown"); + tarantoolClient.close(); + tarantoolContainer.close(); + } +} diff --git a/src/test/java/io/tarantool/driver/benchmark/BenchmarkRunner.java b/src/test/java/io/tarantool/driver/benchmark/SingleInstanceBenchmarkRunner.java similarity index 88% rename from src/test/java/io/tarantool/driver/benchmark/BenchmarkRunner.java rename to src/test/java/io/tarantool/driver/benchmark/SingleInstanceBenchmarkRunner.java index 733390289..6fbdb371f 100644 --- a/src/test/java/io/tarantool/driver/benchmark/BenchmarkRunner.java +++ b/src/test/java/io/tarantool/driver/benchmark/SingleInstanceBenchmarkRunner.java @@ -20,7 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; -public class BenchmarkRunner { +public class SingleInstanceBenchmarkRunner { public static void main(String[] args) throws Exception { org.openjdk.jmh.Main.main(args); } @@ -29,7 +29,7 @@ public static void main(String[] args) throws Exception { @Fork(1) @BenchmarkMode(Mode.Throughput) @OperationsPerInvocation(1000) - public void acceptingDiffTypes(TarantoolSetup plan, Blackhole bh) { + public void acceptingDiffTypes(SingleInstanceTarantoolSetup plan, Blackhole bh) { List result = plan.tarantoolClient.call( "return_arrays_with_different_types" ).join(); @@ -66,12 +66,12 @@ public void acceptingDiffTypes(TarantoolSetup plan, Blackhole bh) { @Fork(1) @BenchmarkMode(Mode.Throughput) @OperationsPerInvocation(1000) - public void acceptingDiffTypesAsTuplesAndUnpackIt(TarantoolSetup plan, Blackhole bh) { + public void acceptingDiffTypesAsTuplesAndUnpackIt(SingleInstanceTarantoolSetup plan, Blackhole bh) { TarantoolResult tuples = plan.tarantoolClient.call( "return_arrays_with_different_types", Collections.emptyList(), - plan.defaultMapper, - plan.resultMapper + plan.defaultMapperSupplier, + plan.resultMapperSupplier ).join(); assertEquals(1000, tuples.size()); @@ -104,12 +104,12 @@ public void acceptingDiffTypesAsTuplesAndUnpackIt(TarantoolSetup plan, Blackhole @Fork(1) @BenchmarkMode(Mode.Throughput) @OperationsPerInvocation(1000) - public void acceptingDiffTypesAsTuplesAndUnpackItWithTargetType(TarantoolSetup plan, Blackhole bh) { + public void acceptingDiffTypesAsTuplesAndUnpackItWithTargetType(SingleInstanceTarantoolSetup plan, Blackhole bh) { TarantoolResult tuples = plan.tarantoolClient.call( "return_arrays_with_different_types", Collections.emptyList(), - plan.defaultMapper, - plan.resultMapper + plan.defaultMapperSupplier, + plan.resultMapperSupplier ).join(); assertEquals(1000, tuples.size()); @@ -142,7 +142,7 @@ public void acceptingDiffTypesAsTuplesAndUnpackItWithTargetType(TarantoolSetup p @Fork(1) @BenchmarkMode(Mode.Throughput) @OperationsPerInvocation(1000) - public void passingArrayOfArraysWithDiffTypes(TarantoolSetup plan, Blackhole bh) { + public void passingArrayOfArraysWithDiffTypes(SingleInstanceTarantoolSetup plan, Blackhole bh) { bh.consume(plan.tarantoolClient.call( "empty_function", plan.arraysWithDiffElements).join()); } @@ -151,7 +151,7 @@ public void passingArrayOfArraysWithDiffTypes(TarantoolSetup plan, Blackhole bh) @Fork(1) @BenchmarkMode(Mode.Throughput) @OperationsPerInvocation(1000) - public void passingArrayOfArraysWithNestedArrays(TarantoolSetup plan, Blackhole bh) { + public void passingArrayOfArraysWithNestedArrays(SingleInstanceTarantoolSetup plan, Blackhole bh) { bh.consume(plan.tarantoolClient.call( "empty_function", plan.arraysWithNestedArrays).join()); } @@ -160,7 +160,7 @@ public void passingArrayOfArraysWithNestedArrays(TarantoolSetup plan, Blackhole @Fork(1) @BenchmarkMode(Mode.Throughput) @OperationsPerInvocation(1000) - public void passingArrayOfArraysWithNestedMaps(TarantoolSetup plan, Blackhole bh) { + public void passingArrayOfArraysWithNestedMaps(SingleInstanceTarantoolSetup plan, Blackhole bh) { bh.consume(plan.tarantoolClient.call( "empty_function", plan.arraysWithNestedMaps).join()); } @@ -168,7 +168,7 @@ public void passingArrayOfArraysWithNestedMaps(TarantoolSetup plan, Blackhole bh @Benchmark @Fork(1) @BenchmarkMode(Mode.Throughput) - public void spaceCall(TarantoolSetup plan, Blackhole bh) { + public void spaceCall(SingleInstanceTarantoolSetup plan, Blackhole bh) { bh.consume(plan.retryingTarantoolClient.space( "test_space")); } diff --git a/src/test/java/io/tarantool/driver/benchmark/TarantoolSetup.java b/src/test/java/io/tarantool/driver/benchmark/SingleInstanceTarantoolSetup.java similarity index 90% rename from src/test/java/io/tarantool/driver/benchmark/TarantoolSetup.java rename to src/test/java/io/tarantool/driver/benchmark/SingleInstanceTarantoolSetup.java index 0431dea7d..d987071d8 100644 --- a/src/test/java/io/tarantool/driver/benchmark/TarantoolSetup.java +++ b/src/test/java/io/tarantool/driver/benchmark/SingleInstanceTarantoolSetup.java @@ -8,9 +8,9 @@ import io.tarantool.driver.api.tuple.TarantoolTuple; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackMapper; +import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactory; import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactoryImpl; -import io.tarantool.driver.mappers.factories.ResultMapperFactoryFactoryImpl; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; @@ -25,10 +25,11 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.function.Supplier; @State(Scope.Benchmark) -public class TarantoolSetup { - public Logger log = LoggerFactory.getLogger(TarantoolSetup.class); +public class SingleInstanceTarantoolSetup { + public Logger log = LoggerFactory.getLogger(SingleInstanceTarantoolSetup.class); public TarantoolContainer tarantoolContainer = new TarantoolContainer() .withScriptFileName("org/testcontainers/containers/benchmark.lua") @@ -37,8 +38,11 @@ public class TarantoolSetup { TarantoolClient> tarantoolClient; TarantoolClient> retryingTarantoolClient; MessagePackMapper defaultMapper; + Supplier defaultMapperSupplier = () -> defaultMapper; CallResultMapper, SingleValueCallResult>> resultMapper; + Supplier, SingleValueCallResult>>> + resultMapperSupplier; List> arraysWithDiffElements; List> arraysWithNestedArrays; List> arraysWithNestedMaps; @@ -61,6 +65,7 @@ private void initClient() { defaultMapper = tarantoolClient.getConfig().getMessagePackMapper(); resultMapper = tarantoolTupleResultMapperFactory .withSingleValueArrayToTarantoolTupleResultMapper(defaultMapper, spaceMetadata); + resultMapperSupplier = () -> resultMapper; log.info("Successfully connected to Tarantool, version = {}", tarantoolClient.getVersion()); } diff --git a/src/test/java/io/tarantool/driver/core/CustomConnection.java b/src/test/java/io/tarantool/driver/core/CustomConnection.java index 99c97d6da..b025652b6 100644 --- a/src/test/java/io/tarantool/driver/core/CustomConnection.java +++ b/src/test/java/io/tarantool/driver/core/CustomConnection.java @@ -6,11 +6,9 @@ import io.tarantool.driver.api.connection.TarantoolConnectionCloseListener; import io.tarantool.driver.api.connection.TarantoolConnectionFailureListener; import io.tarantool.driver.exceptions.TarantoolClientException; -import io.tarantool.driver.mappers.MessagePackValueMapper; import io.tarantool.driver.protocol.TarantoolRequest; import java.net.InetSocketAddress; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -65,7 +63,7 @@ public boolean isConnected() { } @Override - public CompletableFuture sendRequest(TarantoolRequest request, MessagePackValueMapper resultMapper) { + public TarantoolRequestMetadata sendRequest(TarantoolRequest request) { return null; } diff --git a/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java b/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java index 99f5ae789..d7bf94288 100644 --- a/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java +++ b/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java @@ -25,6 +25,7 @@ import io.tarantool.driver.core.metadata.TestMetadataProvider; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackMapper; +import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactory; import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactoryImpl; import io.tarantool.driver.mappers.factories.DefaultMessagePackMapperFactory; @@ -37,6 +38,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertIterableEquals; @@ -48,12 +50,16 @@ public class ProxyOperationBuildersTest { private final MessagePackMapper defaultMapper = DefaultMessagePackMapperFactory.getInstance().defaultComplexTypesMapper(); private final TarantoolTupleFactory factory = new DefaultTarantoolTupleFactory(defaultMapper); + private final Supplier defaultMapperSupplier = () -> defaultMapper; TarantoolTupleResultMapperFactory tarantoolTupleResultMapperFactory = TarantoolTupleResultMapperFactoryImpl.getInstance(); private final CallResultMapper, SingleValueCallResult>> defaultResultMapper = tarantoolTupleResultMapperFactory .withSingleValueArrayToTarantoolTupleResultMapper(defaultMapper, null); + private final + Supplier, SingleValueCallResult>>> + defaultResultMapperSupplier = () -> defaultResultMapper; @Test public void deleteOperationBuilderTest() { @@ -66,8 +72,8 @@ public void deleteOperationBuilderTest() { .withSpaceName("space1") .withFunctionName("function1") .withIndexQuery(indexQuery) - .withResultMapper(defaultResultMapper) - .withArgumentsMapper(defaultMapper) + .withResultMapperSupplier(defaultResultMapperSupplier) + .withArgumentsMapperSupplier(defaultMapperSupplier) .withOptions(ProxyDeleteOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) ) @@ -80,7 +86,7 @@ public void deleteOperationBuilderTest() { assertEquals("function1", deleteProxyOperation.getFunctionName()); assertIterableEquals(Arrays.asList("space1", Collections.singletonList(42L), options), deleteProxyOperation.getArguments()); - assertEquals(defaultResultMapper, deleteProxyOperation.getResultMapper()); + assertEquals(defaultResultMapperSupplier, deleteProxyOperation.getResultMapperSupplier()); } @Test @@ -94,8 +100,8 @@ public void insertOperationBuilderTest() { .withSpaceName("space1") .withFunctionName("function1") .withTuple(tarantoolTuple) - .withArgumentsMapper(defaultMapper) - .withResultMapper(defaultResultMapper) + .withArgumentsMapperSupplier(defaultMapperSupplier) + .withResultMapperSupplier(defaultResultMapperSupplier) .withOptions(ProxyInsertOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) ) @@ -107,7 +113,7 @@ public void insertOperationBuilderTest() { assertEquals(client, insertOperation.getClient()); assertEquals("function1", insertOperation.getFunctionName()); assertIterableEquals(Arrays.asList("space1", tarantoolTuple, options), insertOperation.getArguments()); - assertEquals(defaultResultMapper, insertOperation.getResultMapper()); + assertEquals(defaultResultMapperSupplier, insertOperation.getResultMapperSupplier()); } @Test @@ -123,8 +129,8 @@ public void insertManyOperationBuilderTest() { .withSpaceName("space1") .withFunctionName("function1") .withTuples(tarantoolTuples) - .withResultMapper(defaultResultMapper) - .withArgumentsMapper(defaultMapper) + .withResultMapperSupplier(defaultResultMapperSupplier) + .withArgumentsMapperSupplier(defaultMapperSupplier) .withOptions(ProxyInsertManyOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) .withRollbackOnError(RollbackOnError.TRUE) @@ -139,7 +145,8 @@ public void insertManyOperationBuilderTest() { assertEquals(client, operation.getClient()); assertEquals("function1", operation.getFunctionName()); assertIterableEquals(Arrays.asList("space1", tarantoolTuples, options), operation.getArguments()); - assertEquals(defaultResultMapper, operation.getResultMapper()); + assertEquals(defaultMapperSupplier, operation.getArgumentsMapperSupplier()); + assertEquals(defaultResultMapperSupplier, operation.getResultMapperSupplier()); } @Test @@ -153,8 +160,8 @@ public void replaceOperationBuilderTest() { .withSpaceName("space1") .withFunctionName("function1") .withTuple(tarantoolTuple) - .withResultMapper(defaultResultMapper) - .withArgumentsMapper(defaultMapper) + .withResultMapperSupplier(defaultResultMapperSupplier) + .withArgumentsMapperSupplier(defaultMapperSupplier) .withOptions(ProxyReplaceOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) ) @@ -166,7 +173,8 @@ public void replaceOperationBuilderTest() { assertEquals(client, operation.getClient()); assertEquals("function1", operation.getFunctionName()); assertIterableEquals(Arrays.asList("space1", tarantoolTuple, options), operation.getArguments()); - assertEquals(defaultResultMapper, operation.getResultMapper()); + assertEquals(defaultMapperSupplier, operation.getArgumentsMapperSupplier()); + assertEquals(defaultResultMapperSupplier, operation.getResultMapperSupplier()); } @Test @@ -182,8 +190,8 @@ public void replaceManyOperationBuilderTest() { .withSpaceName("space1") .withFunctionName("function1") .withTuples(tarantoolTuples) - .withResultMapper(defaultResultMapper) - .withArgumentsMapper(defaultMapper) + .withResultMapperSupplier(defaultResultMapperSupplier) + .withArgumentsMapperSupplier(defaultMapperSupplier) .withOptions(ProxyReplaceManyOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) .withRollbackOnError(RollbackOnError.TRUE) @@ -199,7 +207,8 @@ public void replaceManyOperationBuilderTest() { assertEquals(client, operation.getClient()); assertEquals("function1", operation.getFunctionName()); assertIterableEquals(Arrays.asList("space1", tarantoolTuples, options), operation.getArguments()); - assertEquals(defaultResultMapper, operation.getResultMapper()); + assertEquals(defaultMapperSupplier, operation.getArgumentsMapperSupplier()); + assertEquals(defaultResultMapperSupplier, operation.getResultMapperSupplier()); } @Test @@ -220,8 +229,8 @@ public void selectOperationBuilderTest() { .withSpaceName("space1") .withConditions(conditions) .withFunctionName("function1") - .withResultMapper(defaultResultMapper) - .withArgumentsMapper(defaultMapper) + .withResultMapperSupplier(defaultResultMapperSupplier) + .withArgumentsMapperSupplier(defaultMapperSupplier) .withOptions(ProxySelectOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) .withBatchSize(123456) @@ -243,7 +252,7 @@ public void selectOperationBuilderTest() { assertEquals(selectArguments, argumentValues.get(1)); Map actualOptions = (Map) argumentValues.get(2); assertEquals(options.toString(), actualOptions.toString()); - assertEquals(defaultResultMapper, op.getResultMapper()); + assertEquals(defaultResultMapperSupplier, op.getResultMapperSupplier()); } @Test @@ -258,8 +267,8 @@ public void updateOperationBuilderTest() { .withFunctionName("function1") .withIndexQuery(indexQuery) .withTupleOperation(TupleOperations.add(3, 90).andAdd(4, 5)) - .withResultMapper(defaultResultMapper) - .withArgumentsMapper(defaultMapper) + .withResultMapperSupplier(defaultResultMapperSupplier) + .withArgumentsMapperSupplier(defaultMapperSupplier) .withOptions(ProxyUpdateOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) ) @@ -276,7 +285,8 @@ public void updateOperationBuilderTest() { TupleOperations.add(3, 90).andAdd(4, 5).asProxyOperationList(), options), operation.getArguments()); - assertEquals(defaultResultMapper, operation.getResultMapper()); + assertEquals(defaultMapperSupplier, operation.getArgumentsMapperSupplier()); + assertEquals(defaultResultMapperSupplier, operation.getResultMapperSupplier()); } @Test @@ -294,8 +304,8 @@ public void upsertOperationBuilderTest() { .withFunctionName("function1") .withTuple(tarantoolTuple) .withTupleOperation(TupleOperations.add(3, 90).andAdd(4, 5)) - .withResultMapper(defaultResultMapper) - .withArgumentsMapper(defaultMapper) + .withResultMapperSupplier(defaultResultMapperSupplier) + .withArgumentsMapperSupplier(defaultMapperSupplier) .withOptions(ProxyUpsertOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) ) @@ -309,7 +319,8 @@ public void upsertOperationBuilderTest() { assertIterableEquals(Arrays.asList("space1", tarantoolTuple, TupleOperations.add(3, 90).andAdd(4, 5).asProxyOperationList(), options), operation.getArguments()); - assertEquals(defaultResultMapper, operation.getResultMapper()); + assertEquals(defaultMapperSupplier, operation.getArgumentsMapperSupplier()); + assertEquals(defaultResultMapperSupplier, operation.getResultMapperSupplier()); } @Test diff --git a/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java b/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java index 079feb975..691c01af3 100644 --- a/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java +++ b/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java @@ -13,6 +13,7 @@ import io.tarantool.driver.exceptions.TarantoolSpaceOperationException; import io.tarantool.driver.mappers.DefaultMessagePackMapper; import io.tarantool.driver.mappers.MessagePackMapper; +import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactory; import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactoryImpl; import io.tarantool.driver.mappers.factories.DefaultMessagePackMapperFactory; @@ -31,6 +32,7 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -359,14 +361,15 @@ public void callTest() throws Exception { @Test public void callForTarantoolResultTest() throws Exception { MessagePackMapper defaultMapper = client.getConfig().getMessagePackMapper(); + Supplier defaultMapperSupplier = () -> defaultMapper; TarantoolTupleResultMapperFactory factory = TarantoolTupleResultMapperFactoryImpl.getInstance(); TarantoolSpaceMetadata spaceMetadata = client.metadata().getSpaceByName("test_space").get(); TarantoolResult result = client.call( "user_function_complex_query", Collections.singletonList(1000), - defaultMapper, - factory.withSingleValueArrayToTarantoolTupleResultMapper(defaultMapper, spaceMetadata) + defaultMapperSupplier, + () -> factory.withSingleValueArrayToTarantoolTupleResultMapper(defaultMapper, spaceMetadata) ).get(); assertTrue(result.size() >= 3); @@ -377,8 +380,8 @@ public void callForTarantoolResultTest() throws Exception { result = client.call( "user_function_complex_query", Collections.singletonList(1000), - defaultMapper, - factory.withSingleValueArrayToTarantoolTupleResultMapper(defaultMapper, null) + defaultMapperSupplier, + () -> factory.withSingleValueArrayToTarantoolTupleResultMapper(defaultMapper, null) ).get(); assertTrue(result.size() >= 3); tuple = result.get(0); diff --git a/src/test/java/io/tarantool/driver/integration/CustomConnection.java b/src/test/java/io/tarantool/driver/integration/CustomConnection.java index 18fcf3214..e83a57f37 100644 --- a/src/test/java/io/tarantool/driver/integration/CustomConnection.java +++ b/src/test/java/io/tarantool/driver/integration/CustomConnection.java @@ -5,12 +5,11 @@ import io.tarantool.driver.api.connection.TarantoolConnection; import io.tarantool.driver.api.connection.TarantoolConnectionCloseListener; import io.tarantool.driver.api.connection.TarantoolConnectionFailureListener; +import io.tarantool.driver.core.TarantoolRequestMetadata; import io.tarantool.driver.exceptions.TarantoolClientException; -import io.tarantool.driver.mappers.MessagePackValueMapper; import io.tarantool.driver.protocol.TarantoolRequest; import java.net.InetSocketAddress; -import java.util.concurrent.CompletableFuture; /** * @author Alexey Kuzin @@ -44,8 +43,8 @@ public boolean isConnected() { } @Override - public CompletableFuture sendRequest(TarantoolRequest request, MessagePackValueMapper resultMapper) { - return connection.sendRequest(request, resultMapper); + public TarantoolRequestMetadata sendRequest(TarantoolRequest request) { + return connection.sendRequest(request); } @Override diff --git a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java index a620eebc7..feef3bab7 100644 --- a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java +++ b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java @@ -10,6 +10,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.Supplier; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -419,12 +420,15 @@ public void test_crudMetadataResponse_shouldReturnTuple_withoutDDLMetadata() CallResultMapper, SingleValueCallResult>> defaultResultMapper = mapperFactoryFactory.singleValueTupleResultMapperFactory() .withSingleValueRowsMetadataToTarantoolTupleResultMapper(defaultMapper, null); + Supplier, + SingleValueCallResult>>> + defaultResultMapperSupplier = () -> defaultResultMapper; TarantoolResult result = client.callForSingleResult( "get_composite_data_with_crud", Collections.singletonList(id), - defaultResultMapper + defaultResultMapperSupplier ).get(); assertEquals(1, result.size()); TarantoolTuple tuple = result.get(0); @@ -458,9 +462,11 @@ public void test_universalConverter_shouldWorkWithBoxAndCrudCorrectly() { .buildCallResultMapper(), TarantoolTupleResult.class ); + Supplier>> + callReturnMapperSupplier = () -> callReturnMapper; TarantoolResult crudResult = - client.call("crud.select", Collections.singletonList("test_space"), callReturnMapper).join(); + client.call("crud.select", Collections.singletonList("test_space"), callReturnMapperSupplier).join(); assertEquals(1, crudResult.size()); TarantoolTuple tuple = crudResult.get(0); @@ -469,13 +475,13 @@ public void test_universalConverter_shouldWorkWithBoxAndCrudCorrectly() { assertEquals(field2, tuple.getObject("field2").orElse(null)); TarantoolResult boxResult = - client.call("select_router_space", new ArrayList<>(), callReturnMapper).join(); + client.call("select_router_space", new ArrayList<>(), callReturnMapperSupplier).join(); assertEquals(1, boxResult.size()); tuple = boxResult.get(0); assertEquals(1, tuple.getObject(0).orElse(null)); - Object primitiveObject = client.call("returning_number", new ArrayList<>(), callReturnMapper).join(); + Object primitiveObject = client.call("returning_number", new ArrayList<>(), callReturnMapperSupplier).join(); assertEquals(2, primitiveObject); } @@ -538,8 +544,9 @@ public void functionAggregateResultViaCallTest() throws ExecutionException, Inte composite.field4 = (Double) valueMap.get("field4"); return composite; }, TestCompositeCallResult.class); + Supplier>> mapperSupplier = () -> mapper; TestComposite actual = - client.callForSingleResult("get_composite_data", Collections.singletonList(123000), mapper).get(); + client.callForSingleResult("get_composite_data", Collections.singletonList(123000), mapperSupplier).get(); assertEquals("Jane Doe", actual.field1); assertEquals(999, actual.field2); diff --git a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java index 73be37c9b..1d5f6e8f6 100644 --- a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java +++ b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java @@ -41,6 +41,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -376,8 +377,9 @@ public void functionAggregateResultViaCallTest() throws ExecutionException, Inte composite.field4 = (Double) valueMap.get("field4"); return composite; }, TestCompositeCallResult.class); + Supplier>> mapperSupplier = () -> mapper; TestComposite actual = - client.callForSingleResult("get_composite_data", Collections.singletonList(123000), mapper).get(); + client.callForSingleResult("get_composite_data", Collections.singletonList(123000), mapperSupplier).get(); assertEquals("Jane Doe", actual.field1); assertEquals(999, actual.field2); diff --git a/src/test/java/io/tarantool/driver/integration/TarantoolRequestSignaturesIT.java b/src/test/java/io/tarantool/driver/integration/TarantoolRequestSignaturesIT.java new file mode 100644 index 000000000..0feb7ab8a --- /dev/null +++ b/src/test/java/io/tarantool/driver/integration/TarantoolRequestSignaturesIT.java @@ -0,0 +1,136 @@ +package io.tarantool.driver.integration; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import io.tarantool.driver.api.TarantoolClient; +import io.tarantool.driver.api.TarantoolClientFactory; +import io.tarantool.driver.api.TarantoolResult; +import io.tarantool.driver.api.TarantoolServerAddress; +import io.tarantool.driver.api.conditions.Conditions; +import io.tarantool.driver.api.space.TarantoolSpaceOperations; +import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory; +import io.tarantool.driver.api.tuple.TarantoolTuple; +import io.tarantool.driver.api.tuple.TarantoolTupleFactory; +import io.tarantool.driver.mappers.factories.DefaultMessagePackMapperFactory; +import io.tarantool.driver.mappers.MessagePackMapper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Alexey Kuzin + */ +public class TarantoolRequestSignaturesIT extends SharedCartridgeContainer { + private static final String TEST_SPACE = "test_space"; + private static final String TEST_PROFILE = "test__profile"; + + private static final MessagePackMapper defaultMapper = + DefaultMessagePackMapperFactory.getInstance().defaultComplexTypesMapper(); + private static final TarantoolTupleFactory tupleFactory = new DefaultTarantoolTupleFactory(defaultMapper); + private static TarantoolClient> client; + + @BeforeAll + public static void setUp() throws Exception { + startCluster(); + initClient(); + truncateSpace(TEST_SPACE); + truncateSpace(TEST_PROFILE); + } + + public static void initClient() { + client = TarantoolClientFactory.createClient() + .withAddresses( + new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3301)), + new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3302)), + new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3303)) + ) + .withCredentials(container.getUsername(), container.getPassword()) + .withConnections(10) + .withEventLoopThreadsNumber(10) + .withRequestTimeout(10000) + .withProxyMethodMapping() + .build(); + } + + private static void truncateSpace(String spaceName) { + client.space(spaceName).truncate().join(); + } + + @Test + public void test_cachingWithRequestSignatures_shouldNotProvideCollisions() throws InterruptedException { + TarantoolSpaceOperations> testSpace = + client.space(TEST_SPACE); + TarantoolSpaceOperations> profileSpace = + client.space(TEST_PROFILE); + + // Fill 10000 rows into both spaces + TarantoolTuple tarantoolTuple; + String uuid; + List> allFutures = new ArrayList<>(20_000); + for (int i = 0; i < 10_000; i++) { + uuid = UUID.randomUUID().toString(); + tarantoolTuple = tupleFactory.create(1_000_000 + i, null, uuid, 200_000 + i); + allFutures.add(testSpace.insert(tarantoolTuple)); + tarantoolTuple = tupleFactory.create(1_000_000 + i, null, uuid, 50_000 + i, 100_000 + i); + allFutures.add(profileSpace.insert(tarantoolTuple)); + if (i % 2000 == 0) { + allFutures.forEach(CompletableFuture::join); // to not catch storage timeouts + allFutures.clear(); + } + } + allFutures.forEach(CompletableFuture::join); + + // Make requests concurrently + allFutures.clear(); + int nextTestSpaceId = 10_000; + AtomicLong testSpaceSum = new AtomicLong(0); + AtomicInteger testCounter = new AtomicInteger(0); + int nextProfileSpaceId = 10_000; + AtomicLong profileSpaceSum = new AtomicLong(0); + AtomicInteger profileCounter = new AtomicInteger(0); + boolean coin; + int nextId; + while (nextTestSpaceId > 0 || nextProfileSpaceId > 0) { + coin = Math.random() - 0.5 > 0; + if (coin && nextTestSpaceId > 0 || nextProfileSpaceId <= 0) { + nextId = 1_000_000 + --nextTestSpaceId; + allFutures.add( + client.callForSingleResult( + "custom_crud_get_one_record", Arrays.asList(TEST_SPACE, nextId), List.class) + .thenAccept(t -> { + testSpaceSum.getAndAdd((Integer) t.get(3)); + testCounter.getAndIncrement(); + }) + ); + } else { + nextId = 1_000_000 + --nextProfileSpaceId; + allFutures.add( + // this method actually calls callForSingleResult inside too but with different mapper stack + profileSpace.select(Conditions.indexEquals("profile_id", Collections.singletonList(nextId))) + .thenAccept(t -> { + profileSpaceSum.getAndAdd(t.get(0).getInteger("balance")); + profileCounter.getAndIncrement(); + }) + ); + } + } + allFutures.forEach(CompletableFuture::join); + + assertEquals(10_000, testCounter.get()); + assertEquals(10_000, profileCounter.get()); + + // Check that all requests returned correct values + int baseSum = 9999 * 10000 / 2; + assertEquals(2_000_000_000L + baseSum, testSpaceSum.get()); + assertEquals(1_000_000_000L + baseSum, profileSpaceSum.get()); + } +} diff --git a/src/test/java/io/tarantool/driver/protocol/TarantoolRequestSignatureTest.java b/src/test/java/io/tarantool/driver/protocol/TarantoolRequestSignatureTest.java new file mode 100644 index 000000000..affd29d7f --- /dev/null +++ b/src/test/java/io/tarantool/driver/protocol/TarantoolRequestSignatureTest.java @@ -0,0 +1,102 @@ +package io.tarantool.driver.protocol; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +/** + * @author Alexey Kuzin + */ +public class TarantoolRequestSignatureTest { + + @Test + public void testEquals() { + Map testCases = new HashMap<>(); + testCases.put( + "two empty signatures should be equal", + new TarantoolRequestSignatureTestCase( + new TarantoolRequestSignature(), + new TarantoolRequestSignature(), + true + )); + testCases.put( + "empty and non-empty signatures should be not equal", + new TarantoolRequestSignatureTestCase( + new TarantoolRequestSignature( + "function", Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature(), + false + )); + testCases.put( + "two signatures can be equal with different component contents", + new TarantoolRequestSignatureTestCase( + new TarantoolRequestSignature( + "function", Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature( + "function", Arrays.asList(new Object[]{"param three", 4})), + true + )); + testCases.put( + "two signatures with different String components should not be equal", + new TarantoolRequestSignatureTestCase( + new TarantoolRequestSignature( + "function", Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature( + "other_function", Arrays.asList(new Object[]{"param three", 4})), + false + )); + testCases.put( + "two signatures should not be equal with different component order", + new TarantoolRequestSignatureTestCase( + new TarantoolRequestSignature( + "function", Arrays.asList(new Object[]{"param one", "param two"})), + new TarantoolRequestSignature( + Arrays.asList(new Object[]{"param three", 4}), "function"), + false + )); + + for (String testName: testCases.keySet()) { + TarantoolRequestSignatureTestCase testCase = testCases.get(testName); + if (testCase.equals) { + assertEquals(testCase.first.hashCode(), testCase.second.hashCode(), testName); + assertEquals(testCase.first, testCase.second, testName); + } else { + assertNotEquals(testCase.first.hashCode(), testCase.second.hashCode(), testName); + assertNotEquals(testCase.first, testCase.second, testName); + } + } + } + + @Test + public void testSignatureAddComponent() { + TarantoolRequestSignature signature = new TarantoolRequestSignature( + "function", Arrays.asList(new Object[]{"param one", "param two"})); + TarantoolRequestSignature updatedSignature = new TarantoolRequestSignature( + "function", Arrays.asList(new Object[]{"param one", "param two"})); + updatedSignature.addComponent("one more parameter"); + assertNotEquals(signature.hashCode(), updatedSignature.hashCode()); + assertNotEquals(signature, updatedSignature, "updated signature should not be equal to the source"); + int oldHashCode = updatedSignature.hashCode(); + updatedSignature.addComponent("last parameter"); + assertNotEquals(updatedSignature.hashCode(), oldHashCode); + } + + static class TarantoolRequestSignatureTestCase { + TarantoolRequestSignature first; + TarantoolRequestSignature second; + boolean equals; + + TarantoolRequestSignatureTestCase( + TarantoolRequestSignature first, TarantoolRequestSignature second, boolean equals) { + this.first = first; + this.second = second; + this.equals = equals; + } + } +} diff --git a/src/test/java/io/tarantool/driver/protocol/TarantoolAuthRequestTest.java b/src/test/java/io/tarantool/driver/protocol/requests/TarantoolAuthRequestTest.java similarity index 92% rename from src/test/java/io/tarantool/driver/protocol/TarantoolAuthRequestTest.java rename to src/test/java/io/tarantool/driver/protocol/requests/TarantoolAuthRequestTest.java index 6e601ad82..306d714ac 100644 --- a/src/test/java/io/tarantool/driver/protocol/TarantoolAuthRequestTest.java +++ b/src/test/java/io/tarantool/driver/protocol/requests/TarantoolAuthRequestTest.java @@ -1,8 +1,10 @@ -package io.tarantool.driver.protocol; +package io.tarantool.driver.protocol.requests; import io.tarantool.driver.auth.TarantoolAuthMechanism; import io.tarantool.driver.mappers.factories.DefaultMessagePackMapperFactory; -import io.tarantool.driver.protocol.requests.TarantoolAuthRequest; +import io.tarantool.driver.protocol.TarantoolHeader; +import io.tarantool.driver.protocol.TarantoolProtocolException; +import io.tarantool.driver.protocol.TarantoolRequestType; import org.junit.jupiter.api.Test; import org.msgpack.core.MessageBufferPacker; import org.msgpack.core.MessagePack; diff --git a/src/test/resources/cartridge/app/roles/api_router.lua b/src/test/resources/cartridge/app/roles/api_router.lua index 25f785214..f0bdb7e01 100644 --- a/src/test/resources/cartridge/app/roles/api_router.lua +++ b/src/test/resources/cartridge/app/roles/api_router.lua @@ -96,6 +96,10 @@ local function custom_crud_select(space_name) return crud.select(space_name) end +local function custom_crud_get_one_record(space_name, tuple_id) + return crud.get(space_name, {tuple_id}).rows[1] +end + local function raising_error() error("Test error: raising_error() called") end @@ -246,6 +250,7 @@ local function init(opts) rawset(_G, 'box_error_non_network_error', box_error_non_network_error) rawset(_G, 'crud_error_timeout', crud_error_timeout) rawset(_G, 'custom_crud_select', custom_crud_select) + rawset(_G, 'custom_crud_get_one_record', custom_crud_get_one_record) rawset(_G, 'get_routers_status', get_routers_status) rawset(_G, 'init_router_status', init_router_status) rawset(_G, 'test_no_such_procedure', test_no_such_procedure) diff --git a/src/test/resources/cartridge/init.lua b/src/test/resources/cartridge/init.lua index 21d1d6c3a..37f6ae5c5 100755 --- a/src/test/resources/cartridge/init.lua +++ b/src/test/resources/cartridge/init.lua @@ -17,6 +17,9 @@ local ok, err = cartridge.cfg({ 'app.roles.custom', }, cluster_cookie = 'testapp-cluster-cookie', +}, { + readahead = 10 * 1024 * 1024, -- 10 MB + net_msg_max = 11140, }) assert(ok, tostring(err))