tarantool / cartridge-java Goto Github PK
View Code? Open in Web Editor NEWTarantool Cartridge Java driver for Tarantool versions 1.10+ based on Netty framework
Home Page: https://tarantool.io
License: Other
Tarantool Cartridge Java driver for Tarantool versions 1.10+ based on Netty framework
Home Page: https://tarantool.io
License: Other
Internal cache in TarantoolCallResultMapperFactory produces race conditions when instantiating mappers for the same target type (e.g. TarantoolTuple).
Steps to reproduce:
call
method in the ProxyTarantoolClient concurrently with TarantoolCallResult<TarantoolTuple>
result type but for different entities (space metadata)See https://github.com/tarantool/cartridge-springdata/blob/42f9d1bf0d3c42f4ed8a7a281ba8d357f592dec9/src/main/java/org/springframework/data/tarantool/core/TarantoolTemplate.java#L232 (easy to reproduce with several scheduled threads + API calls)
mvn clean test -Pintegration
- they passmvn clean
- it fails with[ERROR] Failed to execute goal org.apache.maven.plugins:maven-clean-plugin:2.5:clean (default-clean) on project cartridge-driver: Failed to clean project: Failed to delete /home/isopov/java/workspace/cartridge-java/target/test-classes/cartridge/.rocks/bin/stateboard
I have docker accessible to my user and run integration under it not under root.
Need to add the primitive array mappers
This is an example of a built-in request retrying policy.
In case of connection failure, if there are in-flight requests, not submitted to the server, they should be resubmitted after the connection is restored (possible a new set of servers is received from disovery and the new connections are established). This must be a configurable request failure handling policy, bound to the specific kind of failures.
Suppose the driver receives a map from some stored function, where some values as MessagePack null
s (or box.NULL
). In this case DefaultMapValueConverter
will fail with an error like:
Caused by: java.lang.NullPointerException
at java.util.HashMap.merge(HashMap.java:1225)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at io.tarantool.driver.mappers.DefaultMapValueConverter.fromValue(DefaultMapValueConverter.java:24)
at io.tarantool.driver.mappers.DefaultMapValueConverter.fromValue(DefaultMapValueConverter.java:13)
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:107)
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:87)
This happens because the map collector does not allow nulls as Map.Entry
values.
DefaultMapValueConverter
needs to filter out the pairs with null values.
For Tarantool 1.10 there is no type "double" for space format, float numbers are written into the field of "number" type.
This causes a problem when writing rounded values to a space and expecting them to return as float values -- they are converted into an integer MsgPack value.
Example:
{{name = 'id', type = 'unsigned'}, {name = 'value', type = 'number'}}
box.space.test:insert({1, 1.0})
Possible w/a:
ffi.cast()
for the number value before passing it back from the space in a stored function (not applicable when using tarantool/crud or the box interface)Expected behavior
Integer/Long values are correctly converted into a Float/Double container
Actual behavior
There is no default converter between these value pairs
Add examples for:
These methods do not perform retries:
List<?> call(String, List<?>, ...)
Need to check all API and add the missing wrappers.
There is an issue in ProxyTarantoolSpaceMetadataConverter caused by the next line of code
Value fieldTypeValue = fieldMap.get(FORMAT_NAME_KEY);
Need to check all object mappers for not throwing unexpected NPEs to users.
The corresponding notNull check must be added where necessary.
An example stacktrace:
[07.12.2020 14:03] Александр Кузнецов: ""2020-12-07 13:25:31.804 [http-nio-8079-exec-7] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] [] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is jav
a.lang.NullPointerException] with root cause
"java.lang.NullPointerException: null
at io.tarantool.driver.mappers.DefaultMessagePackMapper.toValue(DefaultMessagePackMapper.java:59)
at io.tarantool.driver.mappers.DefaultMapObjectConverter.lambda$toValue$0(DefaultMapObjectConverter.java:26)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1691)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at io.tarantool.driver.mappers.DefaultMapObjectConverter.toValue(DefaultMapObjectConverter.java:26)
at io.tarantool.driver.mappers.DefaultMapObjectConverter.toValue(DefaultMapObjectConverter.java:15)
at io.tarantool.driver.mappers.DefaultMessagePackMapper.toValue(DefaultMessagePackMapper.java:63)
at io.tarantool.driver.mappers.DefaultListObjectConverter.lambda$toValue$0(DefaultListObjectConverter.java:26)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at io.tarantool.driver.mappers.DefaultListObjectConverter.toValue(DefaultListObjectConverter.java:27)
at io.tarantool.driver.mappers.DefaultListObjectConverter.toValue(DefaultListObjectConverter.java:16)
at io.tarantool.driver.mappers.DefaultMessagePackMapper.toValue(DefaultMessagePackMapper.java:63)
at io.tarantool.driver.protocol.TarantoolRequestBody.<init>(TarantoolRequestBody.java:43)
at io.tarantool.driver.protocol.requests.TarantoolCallRequest$Builder.build(TarantoolCallRequest.java:69)
at io.tarantool.driver.AbstractTarantoolClient.call(AbstractTarantoolClient.java:245)
at io.tarantool.driver.ProxyTarantoolClient.call(ProxyTarantoolClient.java:186)
For monitoring the internal driver state under load, the users should be able to get the following momentary parameters from the driver API:
Requirements:
Proposed API:
New method TarantoolClient#statistics()
which returns the following structure:
class TarantoolStatistics {
public int connectionsTotal;
public int connectionsAlive;
public BigDecimal requestsTotal;
public Map<String, List<TarantoolConnectionStatistics>> connectionsStatistics; // Remote address mapped to connections
}
class TarantoolConnectionStatistics {
public boolean isAlive;
public LocalDateTime establishedAt;
public LocalDateTime closedAt; // will be null if is not closed yet
public BigDecimal requestsTotal;
public int requestsCurrent;
public LocalDateTime lastActivityTime; // may be not very accurate, with the precision of milliseconds
}
In Tarntool 2.6+, interactive transactions became available (see https://www.tarantool.io/en/doc/latest/book/box/atomic/#transactional-manager). This opens the door to implementing transaction support in the driver. In-driver transactions will enable transactional support in the Spring Data module.
Transaction implementation in other noSQL DB drivers must be analyzed.
Currently, by default the ProxyTarantoolClient uses cartridge.get_schema
function for retrieving the schema (see
ddl.get_schema
API (see https://github.com/tarantool/ddl#input-data-format), but in fact, it returns a YAML string (see https://www.tarantool.io/en/doc/latest/book/cartridge/cartridge_api/modules/cartridge/#get-schema). Also, the README doesn't mention how to set up the TarantoolProxyClient for using a custom function (e.g. ddl.get_schema). This leads to errors when a user tries to use the ProxyTarantoolClient without additional wrappers.
cartridge.get_schema
by a "YAML schema" metadata converter variantddl.get_schema
Currently, there is no logging at all, except what comes from Netty. But logging is necessary for debug purposes and auditing the data flows.
The following sides of logging should be considered:
Example case:
{ rows: ..., metadata: ...}
TarantoolResult<TarantoolTuple>
MessageTypeCastException
This exception is not readable and requires debugging of the client code.
The possible solution is checking the MsgPack value type and returning a comprehensive error.
When trying to update a tuple by field name, the following error occurs:
Illegal parameters, field id must be a number or a string
The reason is missing field name serialization in TarantoolUpdateOperation
:
@Override
public Value toMessagePackValue(MessagePackObjectMapper mapper) {
return mapper.toValue(
Arrays.asList(getOperationType().toString(), getFieldIndex(), getValue()));
}
Use case:
.withConnections(4)
). The proxy setup may look like:global
daemon
defaults
log global
mode tcp
option tcplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend stats
bind *:8081
mode http
stats enable
stats uri /stats
stats refresh 5s
stats admin if LOCALHOST
frontend squid
bind 0.0.0.0:3309
default_backend squid_pool
backend squid_pool
balance roundrobin
mode tcp
server squid1:3309 check maxconn 30 inter 100 fall 3
server squid2:3310 check maxconn 30 inter 100 fall 3
server squid3:3309 check maxconn 30 inter 100 fall 3
server squid4:3310 check maxconn 30 inter 100 fall 3
true
It would be good to get nullability attribute from TarantoolFieldMetadata
(the equivalent for attribute is_nullable
from space format in Tarantool).
When driver is disconnected from the routers (session timeout) we don't want to see IOException warning in log.
INFO messages about connect/disconnect events should not be disabled.
2021-03-16 12:47:47.698 INFO 1 --- [ntLoopGroup-2-2] .t.d.c.TarantoolClusterConnectionManager : Disconnected from some-server
2021-03-16 12:47:47.696 WARN 1 --- [ntLoopGroup-2-2] io.netty.channel.DefaultChannelPipeline : An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler
in the pipeline did not handle the exception.
java.io.IOException: Connection reset by peer
at java.base/sun.nio.ch.FileDispatcherImpl.read0(Native Method) ~[na:na]
at java.base/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39) ~[na:na]
at java.base/sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:276) ~[na:na]
at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:233) ~[na:na]
at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:223) ~[na:na]
at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:358) ~[na:na]
at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:253) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1133) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.buffer.WrappedByteBuf.writeBytes(WrappedByteBuf.java:821) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-all-4.1.52.Final.jar!/:4.1.52.Final]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
The method must call crud.truncate of box.space.<space_obj>:truncate() for cluster and standalone client implementations.
Sometimes this test fails with
java.util.concurrent.CompletionException: org.opentest4j.AssertionFailedError: Unexpected exception thrown: io.tarantool.driver.exceptions.NoAvailableConnectionsException: No available connections
at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:320)
at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:325)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1809)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at java.base/java.lang.Thread.run(Thread.java:1676)
Caused by: org.opentest4j.AssertionFailedError: Unexpected exception thrown: io.tarantool.driver.exceptions.NoAvailableConnectionsException: No available connections
at org.junit.jupiter.api.AssertDoesNotThrow.createAssertionFailedError(AssertDoesNotThrow.java:83)
at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:54)
at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:37)
at org.junit.jupiter.api.Assertions.assertDoesNotThrow(Assertions.java:3005)
at io.tarantool.driver.core.RoundRobinStrategyTest.lambda$testSkipConnections$9(RoundRobinStrategyTest.java:119)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1806)
... 3 more
Caused by: io.tarantool.driver.exceptions.NoAvailableConnectionsException: No available connections
at io.tarantool.driver.core.TarantoolConnectionSelectionStrategies$RoundRobinStrategy.next(TarantoolConnectionSelectionStrategies.java:57)
at io.tarantool.driver.core.RoundRobinStrategyTest.lambda$testSkipConnections$8(RoundRobinStrategyTest.java:119)
at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:50)
... 7 more
and sometimes it does pass.
@RepeatedTest(value = 100)
does not help in reproducing - it seems that only first repetition can fail and all the others will always pass.
Currently, the connection state machine looks like this:
The schema above has the following pitfalls:
Currently, the existing connections to the addresses that were not returned by the address provider during the next connection sequence, are not closed after establishing new connections, although new requests will not be dispatched to them. If such connections will not be closed by the server, they may stay alive for a long time and affect the client resources.
These "old" connections must be closed after the new ones are established if they are not already closed by a disconnect event.
Cursor is an iterator that encapsulates a state which includes such parameters as the data window (currently iterated batch of data), next key in the window and mechanisms for loading the next portion of data from the server.
Cursor must have the following configurable options:
Cursor must be supported for both single and cluster storage.
Tested on Ubuntu.
When you just run integration tests there's a fail because docker container failes to bootstrap:
10:35:03.894 [main] ERROR 🐳 [testcontainers/wzumtjtg9x4spqhp:latest] - Log output from the failed container:
• Build application in /app
• Running `tarantoolctl rocks make`
Error: /app/.rocks/share/tarantool/rocks does not exist and your user does not have write permissions in /app
To fix this you need to add the following variables to environment:
export TARANTOOL_SERVER_USER=<current user>
export TARANTOOL_SERVER_GROUP=<current group>
We need to change this behavior or add the setup notes to readme.
A -- these operations cannot be atomic since they have "select for update" semantics with on-by-one tuple update. But each tuple update is atomic internally
C -- consistency cannot be guaranteed on this level
I -- isolation cannot be guaranteed, but each batch update task must be fault-tolerant to the specific kind of errors (update of a non-existing value, delete of a non-existing value)
D -- user must be able to specify the retry and recovery policies for the batch tasks
Although this exception is then wrapped in the TarantoolConnectionException, there should be more clear exception anyway rather then a rough NPE:
Caused by: io.tarantool.driver.exceptions.TarantoolConnectionException: The client is not connected to Tarantool server
at io.tarantool.driver.core.AbstractTarantoolConnectionManager.lambda$getConnection$0(AbstractTarantoolConnectionManager.java:96) ~[cartridge-driver-0.4.1.jar!/:na]
at java.base/java.util.concurrent.CompletableFuture.uniHandle(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniHandleStage(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.handle(Unknown Source) ~[na:na]
at io.tarantool.driver.core.AbstractTarantoolConnectionManager.getConnection(AbstractTarantoolConnectionManager.java:88) ~[cartridge-driver-0.4.1.jar!/:na]
at io.tarantool.driver.AbstractTarantoolClient.makeRequest(AbstractTarantoolClient.java:411) ~[cartridge-driver-0.4.1.jar!/:na]
at io.tarantool.driver.AbstractTarantoolClient.call(AbstractTarantoolClient.java:228) ~[cartridge-driver-0.4.1.jar!/:na]
at io.tarantool.driver.AbstractTarantoolClient.call(AbstractTarantoolClient.java:222) ~[cartridge-driver-0.4.1.jar!/:na]
at io.tarantool.driver.AbstractTarantoolClient.call(AbstractTarantoolClient.java:216) ~[cartridge-driver-0.4.1.jar!/:na]
... 33 common frames omitted
Caused by: java.lang.NullPointerException: null
at io.tarantool.driver.core.AbstractTarantoolConnectionManager.getConnections(AbstractTarantoolConnectionManager.java:175) ~[cartridge-driver-0.4.1.jar!/:na]
at io.tarantool.driver.core.AbstractTarantoolConnectionManager.establishConnections(AbstractTarantoolConnectionManager.java:160) ~[cartridge-driver-0.4.1.jar!/:na]
at io.tarantool.driver.core.AbstractTarantoolConnectionManager.getConnectionInternal(AbstractTarantoolConnectionManager.java:112) ~[cartridge-driver-0.4.1.jar!/:na]
... 38 common frames omitted
Installing EPEL repository seems a long action that can be omitted taking docker image already containing it.
TarantoolClient.callForSingleResult() returns CompletableFuture
get() without timeout args: TarantoolFunctionCallException with error info from Tarantool
Caused by: TarantoolFunctionCallException: {"type":"ClientError","message":"...' ...}
at io.tarantool.driver.api.SingleValueCallResultImpl.(SingleValueCallResultImpl.java:28)
at io.tarantool.driver.mappers.SingleValueCallResultConverter.fromValue(SingleValueCallResultConverter.java:23)
at io.tarantool.driver.mappers.SingleValueCallResultConverter.fromValue(SingleValueCallResultConverter.java:13)
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:107)
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:87)
at io.tarantool.driver.mappers.AbstractResultMapper.fromValue(AbstractResultMapper.java:27)
at io.tarantool.driver.handlers.TarantoolResponseHandler.channelRead0(TarantoolResponseHandler.java:51)
at io.tarantool.driver.handlers.TarantoolResponseHandler.channelRead0(TarantoolResponseHandler.java:23)
get() with timeout args: no error info from Tarantool
Caused by: java.util.concurrent.TimeoutException: null
at java.base/java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1886) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2021) ~[na:na]
Currently, the Tarantool version is not checked which may lead to the user receiving server errors or missing features like updating by JSON paths since Tarantool 2.3.
Implement checking the Tarantool version and a service for fencing the parts of code depending on the current Tarantool version:
Description:
The retry attempts are configured to 20ms delay. The exact delay between attempts is close to 500ms in case of ~30 stack frames.
Example stacktrace:
2021-03-08 12:27:41.001 WARN 1222 --- [Pool-1-worker-3] r.v.c.c.s.c.c.t.TarantoolConfiguration : retry attempt after error
java.util.concurrent.CompletionException: TarantoolFunctionCallException: {"type":"ClientError","code":77,"message":"Connection reset by peer","trace":[{"file":"builtin/box/net_box.lua","line":263}]}
at java.base/java.util.concurrent.CompletableFuture.encodeRelay(CompletableFuture.java:367) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.completeRelay(CompletableFuture.java:376) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$UniRelay.tryFire(CompletableFuture.java:1019) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088) ~[na:na]
at io.tarantool.driver.handlers.TarantoolResponseHandler.channelRead0(TarantoolResponseHandler.java:53) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.handlers.TarantoolResponseHandler.channelRead0(TarantoolResponseHandler.java:23) ~[cartridge-driver-0.4.1.jar:na]
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-all-4.1.54.Final.jar:4.1.54.Final]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: io.tarantool.driver.exceptions.TarantoolFunctionCallException: null
at io.tarantool.driver.api.SingleValueCallResultImpl.<init>(SingleValueCallResultImpl.java:28) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.SingleValueCallResultConverter.fromValue(SingleValueCallResultConverter.java:23) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.SingleValueCallResultConverter.fromValue(SingleValueCallResultConverter.java:13) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:107) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:87) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.AbstractResultMapper.fromValue(AbstractResultMapper.java:27) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.handlers.TarantoolResponseHandler.channelRead0(TarantoolResponseHandler.java:51) ~[cartridge-driver-0.4.1.jar:na]
... 23 common frames omitted
2021-03-08 12:27:41.498 WARN 1222 --- [Pool-1-worker-3] r.v.c.c.s.c.c.t.TarantoolConfiguration : retry attempt after error
io.tarantool.driver.exceptions.TarantoolFunctionCallException: null
at io.tarantool.driver.api.SingleValueCallResultImpl.<init>(SingleValueCallResultImpl.java:28) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.SingleValueCallResultConverter.fromValue(SingleValueCallResultConverter.java:23) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.SingleValueCallResultConverter.fromValue(SingleValueCallResultConverter.java:13) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:107) ~[cartridge-driver-0.4.1.jar:na]
at io.tarantool.driver.mappers.DefaultMessagePackMapper.fromValue(DefaultMessagePackMapper.java:87) ~[cartridge-driver-0.4.1.jar:na]
Possible root cause:
The exception generation in Java is slow
Possible solution:
Introduce exception caching
Data loss problem. An error is expected in assert, but it updates the last field if the fieldName that is specified in update does not exist:
updateResult = testSpace.update(conditions, TupleOperations.add("asd", 100000)).get();
assertEquals(101968, updateResult.get(0).getInteger(4));
This line changes fieldId from None to -1:
The client must return an error immediately if the authorization to Tarantool fails.
UPD: only the second (and probably further) requests hang, the first one fails with the expected error.
Use case:
ddl.get_schema procedures used for this application were augmented with log.info calls
Currently, TarantoolClient#callForSingleResult supports variants with tuple type (without explicit mapper).
We need to make the same variants for callForMultiResult.
If create a custom object converter
private val timestampConverter = new ObjectConverter[Timestamp, StringValue] {
override def toValue(obj: Timestamp): StringValue = ValueFactory.newString(obj.getTime.toString)
}
and then register it in default simple or complex types mapper (from DefaultMessagePackMapperFactory), then it does not applied for complex types (like Map, List, ArrayList) and ata runtime throws the next exception:
io.tarantool.driver.mappers.MessagePackObjectMapperException: ObjectConverter for type class java.sql.Timestamp is not found
at io.tarantool.driver.mappers.DefaultMessagePackMapper.toValue(DefaultMessagePackMapper.java:61)
at io.tarantool.driver.api.tuple.TarantoolFieldImpl.getEntity(TarantoolFieldImpl.java:50)
at io.tarantool.driver.api.tuple.TarantoolFieldImpl.toMessagePackValue(TarantoolFieldImpl.java:39)
at io.tarantool.driver.mappers.DefaultPackableObjectConverter.toValue(DefaultPackableObjectConverter.java:20)
at io.tarantool.driver.mappers.DefaultPackableObjectConverter.toValue(DefaultPackableObjectConverter.java:11)
at io.tarantool.driver.mappers.DefaultMessagePackMapper.toValue(DefaultMessagePackMapper.java:63)
at io.tarantool.driver.mappers.DefaultListObjectConverter.lambda$toValue$0(DefaultListObjectConverter.java:26)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
This is due to the fact that complex types mappers also contains their own list of converters for simple types (which is just a copy from the default mapper, see copy constructor of DefaultMessagePackMapper).
As a workaround I've found only to create instance of DefaultMessagePackMapper manually
private val tmpMapper = DefaultMessagePackMapperFactory.getInstance().defaultSimpleTypeMapper()
private val timestampConverter = new ObjectConverter[Timestamp, StringValue] {
override def toValue(obj: Timestamp): StringValue = ValueFactory.newString(obj.getTime.toString)
}
tmpMapper.registerObjectConverter(timestampConverter)
val mapper = new DefaultMessagePackMapper.Builder(tmpMapper)
.withDefaultListObjectConverter()
.withDefaultArrayValueConverter()
.withDefaultMapObjectConverter()
.withDefaultMapValueConverter()
.build();
mapper.registerObjectConverter(new DefaultPackableObjectConverter(mapper))
val config = TarantoolClientConfig.builder()
.withMessagePackMapper(mapper)
But I suppose that it is still a bug and user should only use DefaultMessagePackMapperFactory in such case.
Would be nice to implement converter for this builtin java type.
For example now I need to write
Conditions.indexEquals(0, indexParts)
Conditions.indexEquals(TarantoolIndexQuery.PRIMARY, indexParts)
It's not obvious that I should use constants from TarantoolIndexQuery class as well that constant value must be 0 (not 1).
I suggest to imrove the Conditions class API to make the following possible:
Conditions.indexEquals(Conditions.PK_INDEX, indexParts)
Conditions.primaryIndexEquals(indexParts)
TarantoolRequestRetryPolicies.byNumberOfAttempts() has an exceptionCheck argument to decide if an exception should be retried.
As a user I want predefined exception check function for network issue cases:
There is a base template which I tested for retry to happen on this cases, but it's not completed:
e -> {
boolean retryRequest = false;
if (e instanceof TimeoutException ||
e instanceof TarantoolConnectionException) {
retryRequest = true;
}
if (e instanceof CompletionException) {
Throwable cause = e.getCause();
if (cause instanceof TimeoutException ||
cause instanceof TarantoolConnectionException) {
retryRequest = true;
}
}
if (e instanceof TarantoolFunctionCallException) {
Throwable cause = e.getCause();
String message = cause.toString();
if (message.contains("Connection refused") ||
message.contains("Connection reset by peer") ||
message.contains("Peer closed")) {
retryRequest = true;
}
}
return retryRequest;
Some examples of exception messages from Tarantool on storage replica failure:
TarantoolFunctionCallException: {"type":"ClientError","code":77,"message":"Connection refused","trace":[{"file":"builtin/box/net_box.lua","line":490}]}
java.util.concurrent.CompletionException: TarantoolFunctionCallException: {"type":"ClientError","code":77,"message":"Connection reset by peer","trace":[{"file":"builtin/box/net_box.lua","line":263}]}
java.util.concurrent.CompletionException: TarantoolFunctionCallException: {"type":"ClientError","code":77,"message":"Peer closed","trace":[{"file":"builtin/box/net_box.lua","line":263}]}
Use case:
Steps to reproduce:
RetryingTarantoolTupleClient
with TarantoolRequestRetryPolicies.unbound()
callForSingleResult
) with explicit timeout (using get(time, timeUnit))
Actual behavior:
Retries continue to be performed despite that future finished with timeout
Expected behavior:
No more retries are performed after the request future is finished with timeout
Currently, when a connection fails (a disconnect event is emitted by netty), all in-flight requests for this connection that have not received a response yet will fail with TimeoutException, when the configured request timeout
exceeds.
This may cause some requests to wait unnecessarily for the timeout when it is already known that the server will not respond. In this case, we may either end these requests immediately on disconnect event or repeat these requests internally, switching them to the other alive connections.
The first variant seems better, since the requests may not be idempotent, and the decision for repeating the request lies on the user.
Maven version:
mvn --version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 1.8.0_275, vendor: Private Build, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-53-generic", arch: "amd64", family: "unix"
Steps to reproduce on ubuntu:
mvn clean test -Pintegration
mvn test
.... [INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ cartridge-driver --- [DEBUG] Configuring mojo org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile from plugin realm ClassRealm[plugin>org.apache.maven.plugins:maven-compiler-plugin:3.8.0, parent: sun.misc.Launcher$AppClassLoader@1b6d3586] [DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile' with basic configurator --> [DEBUG] (f) basedir = /home/v/work/git/cartridge-java [DEBUG] (f) buildDirectory = /home/v/work/git/cartridge-java/target [DEBUG] (f) compilePath = [/home/v/work/git/cartridge-java/target/classes, /home/v/.m2/repository/io/netty/netty-all/4.1.50.Final/netty-all-4.1.50.Final.jar, /home/v/.m2/repository/org/msgpack/msgpack-core/0.8.20/msgpack-core-0.8.20.jar, /home/v/.m2/repository/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar, /home/v/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.11.2/jackson-databind-2.11.2.jar, /home/v/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.11.2/jackson-annotations-2.11.2.jar, /home/v/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.11.2/jackson-core-2.11.2.jar] [DEBUG] (f) compileSourceRoots = [/home/v/work/git/cartridge-java/src/test/java] [DEBUG] (f) compilerId = javac [DEBUG] (f) compilerVersion = 1.8 [DEBUG] (f) debug = true [DEBUG] (f) encoding = UTF-8 [DEBUG] (f) failOnError = true [DEBUG] (f) failOnWarning = false [DEBUG] (f) forceJavacCompilerUse = false [DEBUG] (f) fork = true [DEBUG] (f) generatedTestSourcesDirectory = /home/v/work/git/cartridge-java/target/generated-test-sources/test-annotations [DEBUG] (f) mojoExecution = org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile {execution: default-testCompile} [DEBUG] (f) optimize = true [DEBUG] (f) outputDirectory = /home/v/work/git/cartridge-java/target/test-classes [DEBUG] (f) parameters = false [DEBUG] (f) project = MavenProject: io.tarantool:cartridge-driver:1.0.0-SNAPSHOT @ /home/v/work/git/cartridge-java/pom.xml [DEBUG] (f) session = org.apache.maven.execution.MavenSession@2c16fadb [DEBUG] (f) showDeprecation = true [DEBUG] (f) showWarnings = true [DEBUG] (f) skipMultiThreadWarning = false [DEBUG] (f) source = 8 [DEBUG] (f) staleMillis = 0 [DEBUG] (s) target = 8 [DEBUG] (f) testPath = [/home/v/work/git/cartridge-java/target/test-classes, /home/v/work/git/cartridge-java/target/classes, /home/v/.m2/repository/io/netty/netty-all/4.1.50.Final/netty-all-4.1.50.Final.jar, /home/v/.m2/repository/org/msgpack/msgpack-core/0.8.20/msgpack-core-0.8.20.jar, /home/v/.m2/repository/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar, /home/v/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.11.2/jackson-databind-2.11.2.jar, /home/v/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.11.2/jackson-annotations-2.11.2.jar, /home/v/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.11.2/jackson-core-2.11.2.jar, /home/v/.m2/repository/org/junit/jupiter/junit-jupiter/5.6.2/junit-jupiter-5.6.2.jar, /home/v/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.6.2/junit-jupiter-api-5.6.2.jar, /home/v/.m2/repository/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar, /home/v/.m2/repository/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar, /home/v/.m2/repository/org/junit/platform/junit-platform-commons/1.6.2/junit-platform-commons-1.6.2.jar, /home/v/.m2/repository/org/junit/jupiter/junit-jupiter-params/5.6.2/junit-jupiter-params-5.6.2.jar, /home/v/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.6.2/junit-jupiter-engine-5.6.2.jar, /home/v/.m2/repository/org/junit/platform/junit-platform-engine/1.6.2/junit-platform-engine-1.6.2.jar, /home/v/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar, /home/v/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar, /home/v/.m2/repository/org/testcontainers/testcontainers/1.15.0-rc2/testcontainers-1.15.0-rc2.jar, /home/v/.m2/repository/junit/junit/4.12/junit-4.12.jar, /home/v/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar, /home/v/.m2/repository/org/apache/commons/commons-compress/1.20/commons-compress-1.20.jar, /home/v/.m2/repository/org/rnorth/duct-tape/duct-tape/1.0.8/duct-tape-1.0.8.jar, /home/v/.m2/repository/org/rnorth/visible-assertions/visible-assertions/2.1.2/visible-assertions-2.1.2.jar, /home/v/.m2/repository/net/java/dev/jna/jna/5.2.0/jna-5.2.0.jar, /home/v/.m2/repository/com/github/docker-java/docker-java-api/3.2.5/docker-java-api-3.2.5.jar, /home/v/.m2/repository/com/github/docker-java/docker-java-transport-zerodep/3.2.5/docker-java-transport-zerodep-3.2.5.jar, /home/v/.m2/repository/com/github/docker-java/docker-java-transport/3.2.5/docker-java-transport-3.2.5.jar, /home/v/.m2/repository/org/testcontainers/junit-jupiter/1.14.3/junit-jupiter-1.14.3.jar, /home/v/.m2/repository/io/tarantool/testcontainers-java-tarantool/0.2.1-SNAPSHOT-vr/testcontainers-java-tarantool-0.2.1-SNAPSHOT-vr.jar, /home/v/.m2/repository/io/tarantool/driver/0.1.1/driver-0.1.1.jar, /home/v/.m2/repository/org/springframework/spring-core/5.2.6.RELEASE/spring-core-5.2.6.RELEASE.jar, /home/v/.m2/repository/org/springframework/spring-jcl/5.2.6.RELEASE/spring-jcl-5.2.6.RELEASE.jar, /home/v/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar, /home/v/.m2/repository/org/yaml/snakeyaml/1.26/snakeyaml-1.26.jar] [DEBUG] (f) useIncrementalCompilation = true [DEBUG] (f) verbose = false [DEBUG] -- end configuration -- [DEBUG] Using compiler 'javac'. [DEBUG] Adding /home/v/work/git/cartridge-java/target/generated-test-sources/test-annotations to test-compile source roots: /home/v/work/git/cartridge-java/src/test/java [DEBUG] New test-compile source roots: /home/v/work/git/cartridge-java/src/test/java /home/v/work/git/cartridge-java/target/generated-test-sources/test-annotations [DEBUG] CompilerReuseStrategy: reuseCreated [DEBUG] useIncrementalCompilation enabled [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5.071 s [INFO] Finished at: 2020-11-20T12:47:59+03:00 [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile (default-testCompile) on project cartridge-driver: Execution default-testCompile of goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile failed.: NullPointerException -> [Help 1] org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile (default-testCompile) on project cartridge-driver: Execution default-testCompile of goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile failed. at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81) at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192) at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105) at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957) at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289) at org.apache.maven.cli.MavenCli.main (MavenCli.java:193) at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke (Method.java:498) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282) at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406) at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347) Caused by: org.apache.maven.plugin.PluginExecutionException: Execution default-testCompile of goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:148) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81) at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192) at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105) at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957) at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289) at org.apache.maven.cli.MavenCli.main (MavenCli.java:193) at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke (Method.java:498) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282) at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406) at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347) Caused by: java.lang.NullPointerException at org.apache.maven.plugin.compiler.AbstractCompilerMojo.hasNewFile (AbstractCompilerMojo.java:1628) at org.apache.maven.plugin.compiler.AbstractCompilerMojo.hasNewFile (AbstractCompilerMojo.java:1630) at org.apache.maven.plugin.compiler.AbstractCompilerMojo.hasNewFile (AbstractCompilerMojo.java:1630) at org.apache.maven.plugin.compiler.AbstractCompilerMojo.hasNewFile (AbstractCompilerMojo.java:1630) at org.apache.maven.plugin.compiler.AbstractCompilerMojo.hasNewFile (AbstractCompilerMojo.java:1630) at org.apache.maven.plugin.compiler.AbstractCompilerMojo.isDependencyChanged (AbstractCompilerMojo.java:1596) at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute (AbstractCompilerMojo.java:793) at org.apache.maven.plugin.compiler.TestCompilerMojo.execute (TestCompilerMojo.java:181) at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81) at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192) at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105) at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957) at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289) at org.apache.maven.cli.MavenCli.main (MavenCli.java:193) at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke (Method.java:498) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282) at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406) at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347) [ERROR] [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
Follow-up after discussions of pull #2
If anyone tries to insert null-value into a space field that is part of the primary index then tarantool runs into an error. In some cases, this can leads to fatal error, and exiting the event loop.
This situation can be initiated from the Java driver as well. So, it is necessary to add a check for input data, according space format and space indices before performing insert, upsert, update operations or/and make it in the safe way.
Here is an example:
local yaml = require('yaml')
local space_name = 'megaspace'
local initial_format = {
{name = 'customer_id', type = 'string', is_nullable = false},
{name = 'id', type = 'string', is_nullable = false},
}
local new_format = {
{name = 'customer_id', type = 'string', is_nullable = false},
{name = 'id', type = 'string', is_nullable = true},
}
local function init_space(space)
print('init space: %s', space)
local _space = box.schema.space.create(space, {if_not_exists = true})
_space:format(initial_format)
_space:create_index('pk', {unique = true, parts = {'id'}, if_not_exists = true})
return _space
end
local function change_format(space)
box.space[space]:format(new_format)
end
local function add_data(data)
box.space[space_name]:insert(data)
end
box.cfg({})
--create space
local space = init_space(space_name)
print(yaml.encode(space:format()))
-- add some data
add_data(box.tuple.new({'VIP1', '1'}))
print(yaml.encode(space:select()))
-- change format
change_format(space_name)
print(yaml.encode(space:format()))
--add_data(box.tuple.new({'VIP2', box.NULL}))
Steps to reproduce:
TarantoolTuple
with different space metadata, using the methods of DefaultMapperFactoryFactory
This issue is only reproduced in a multi-thread environment.
tarantool/crud supports only that variant at the moment. Updating with conditions will be supported in #30
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.