Skip to content

Commit 8ef4616

Browse files
committed
Soft automatic schema reload
Now client keeps actual schema metadata and sends schemaId header to be checked against current Tarantool schema version. If client version mismatches DB version client does schema reloading in the background. Client operation interface was reworked in scope of support not only number identifiers for spaces and indexes but also their string names. This also includes set of request builders that can be used as a public API to construct requests. The main idea here is to provide more natural DSL-like approach to build operations instead of current abstract types like List<?> or List<Object>. Closes: #7, #137 Affects: #212
1 parent 66a4fbd commit 8ef4616

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+3338
-416
lines changed

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ makes possible for the client to configure a socket provider.
123123
* `ComposableAsyncOps` - return the operation result as a `CompletionStage`
124124
* `FireAndForgetOps` - returns the query ID
125125

126+
Each operation that requires space or index to be executed, can work with
127+
number ID as well as string name of a space or an index.
128+
Assume, we have `my_space` space with space ID `512` and its primary index
129+
`primary` with index ID `0`. Then, for instance, `select` operations can be
130+
performed as the following:
131+
132+
```java
133+
client.syncOps().select(512, 0, Collections.singletonList(1), 0, 1, Iterator.EQ);
134+
// or using more convenient way
135+
client.syncOps().select("my_space", "primary", Collections.singletonList(1), 0, 1, Iterator.EQ);
136+
```
137+
126138
Feel free to override any method of `TarantoolClientImpl`. For example, to hook
127139
all the results, you could override this:
128140

Original file line numberDiff line numberDiff line change
@@ -1,62 +1,158 @@
11
package org.tarantool;
22

3+
import static org.tarantool.dsl.Requests.callRequest;
4+
import static org.tarantool.dsl.Requests.deleteRequest;
5+
import static org.tarantool.dsl.Requests.evalRequest;
6+
import static org.tarantool.dsl.Requests.insertRequest;
7+
import static org.tarantool.dsl.Requests.pingRequest;
8+
import static org.tarantool.dsl.Requests.replaceRequest;
9+
import static org.tarantool.dsl.Requests.selectRequest;
10+
import static org.tarantool.dsl.Requests.updateRequest;
11+
import static org.tarantool.dsl.Requests.upsertRequest;
312

4-
public abstract class AbstractTarantoolOps<Space, Tuple, Operation, Result>
5-
implements TarantoolClientOps<Space, Tuple, Operation, Result> {
13+
import org.tarantool.dsl.Operation;
14+
import org.tarantool.dsl.TarantoolRequestConvertible;
15+
import org.tarantool.schema.TarantoolSchemaMeta;
16+
17+
import java.util.Arrays;
18+
import java.util.List;
19+
20+
public abstract class AbstractTarantoolOps<Result>
21+
implements TarantoolClientOps<List<?>, Object, Result> {
622

723
private Code callCode = Code.CALL;
824

9-
protected abstract Result exec(Code code, Object... args);
25+
protected abstract Result exec(TarantoolRequest request);
26+
27+
protected abstract TarantoolSchemaMeta getSchemaMeta();
28+
29+
public Result select(Integer space, Integer index, List<?> key, int offset, int limit, Iterator iterator) {
30+
return execute(
31+
selectRequest(space, index)
32+
.key(key)
33+
.offset(offset).limit(limit)
34+
.iterator(iterator)
35+
);
36+
}
37+
38+
@Override
39+
public Result select(String space, String index, List<?> key, int offset, int limit, Iterator iterator) {
40+
return execute(
41+
selectRequest(space, index)
42+
.key(key)
43+
.offset(offset).limit(limit)
44+
.iterator(iterator)
45+
);
46+
}
1047

11-
public Result select(Space space, Space index, Tuple key, int offset, int limit, Iterator iterator) {
12-
return select(space, index, key, offset, limit, iterator.getValue());
48+
@Override
49+
public Result select(Integer space, Integer index, List<?> key, int offset, int limit, int iterator) {
50+
return execute(
51+
selectRequest(space, index)
52+
.key(key)
53+
.offset(offset).limit(limit)
54+
.iterator(iterator)
55+
);
1356
}
1457

15-
public Result select(Space space, Space index, Tuple key, int offset, int limit, int iterator) {
16-
return exec(
17-
Code.SELECT,
18-
Key.SPACE, space,
19-
Key.INDEX, index,
20-
Key.KEY, key,
21-
Key.ITERATOR, iterator,
22-
Key.LIMIT, limit,
23-
Key.OFFSET, offset
58+
@Override
59+
public Result select(String space, String index, List<?> key, int offset, int limit, int iterator) {
60+
return execute(
61+
selectRequest(space, index)
62+
.key(key)
63+
.offset(offset).limit(limit)
64+
.iterator(iterator)
2465
);
2566
}
2667

27-
public Result insert(Space space, Tuple tuple) {
28-
return exec(Code.INSERT, Key.SPACE, space, Key.TUPLE, tuple);
68+
@Override
69+
public Result insert(Integer space, List<?> tuple) {
70+
return execute(insertRequest(space, tuple));
71+
}
72+
73+
@Override
74+
public Result insert(String space, List<?> tuple) {
75+
return execute(insertRequest(space, tuple));
2976
}
3077

31-
public Result replace(Space space, Tuple tuple) {
32-
return exec(Code.REPLACE, Key.SPACE, space, Key.TUPLE, tuple);
78+
@Override
79+
public Result replace(Integer space, List<?> tuple) {
80+
return execute(replaceRequest(space, tuple));
3381
}
3482

35-
public Result update(Space space, Tuple key, Operation... args) {
36-
return exec(Code.UPDATE, Key.SPACE, space, Key.KEY, key, Key.TUPLE, args);
83+
@Override
84+
public Result replace(String space, List<?> tuple) {
85+
return execute(replaceRequest(space, tuple));
3786
}
3887

39-
public Result upsert(Space space, Tuple key, Tuple def, Operation... args) {
40-
return exec(Code.UPSERT, Key.SPACE, space, Key.KEY, key, Key.TUPLE, def, Key.UPSERT_OPS, args);
88+
@Override
89+
public Result update(Integer space, List<?> key, Object... operations) {
90+
Operation[] ops = Arrays.stream(operations)
91+
.map(Operation::fromArray)
92+
.toArray(org.tarantool.dsl.Operation[]::new);
93+
return execute(updateRequest(space, key, ops));
4194
}
4295

43-
public Result delete(Space space, Tuple key) {
44-
return exec(Code.DELETE, Key.SPACE, space, Key.KEY, key);
96+
@Override
97+
public Result update(String space, List<?> key, Object... operations) {
98+
Operation[] ops = Arrays.stream(operations)
99+
.map(Operation::fromArray)
100+
.toArray(org.tarantool.dsl.Operation[]::new);
101+
return execute(updateRequest(space, key, ops));
45102
}
46103

104+
@Override
105+
public Result upsert(Integer space, List<?> key, List<?> defTuple, Object... operations) {
106+
Operation[] ops = Arrays.stream(operations)
107+
.map(Operation::fromArray)
108+
.toArray(Operation[]::new);
109+
return execute(upsertRequest(space, key, defTuple, ops));
110+
}
111+
112+
@Override
113+
public Result upsert(String space, List<?> key, List<?> defTuple, Object... operations) {
114+
Operation[] ops = Arrays.stream(operations)
115+
.map(Operation::fromArray)
116+
.toArray(Operation[]::new);
117+
return execute(upsertRequest(space, key, defTuple, ops));
118+
}
119+
120+
@Override
121+
public Result delete(Integer space, List<?> key) {
122+
return execute(deleteRequest(space, key));
123+
}
124+
125+
@Override
126+
public Result delete(String space, List<?> key) {
127+
return execute(deleteRequest(space, key));
128+
}
129+
130+
@Override
47131
public Result call(String function, Object... args) {
48-
return exec(callCode, Key.FUNCTION, function, Key.TUPLE, args);
132+
return execute(
133+
callRequest(function)
134+
.arguments(args)
135+
.useCall16(callCode == Code.OLD_CALL)
136+
);
49137
}
50138

139+
@Override
51140
public Result eval(String expression, Object... args) {
52-
return exec(Code.EVAL, Key.EXPRESSION, expression, Key.TUPLE, args);
141+
return execute(evalRequest(expression).arguments(args));
53142
}
54143

144+
@Override
55145
public void ping() {
56-
exec(Code.PING);
146+
execute(pingRequest());
147+
}
148+
149+
@Override
150+
public Result execute(TarantoolRequestConvertible requestSpec) {
151+
return exec(requestSpec.toTarantoolRequest(getSchemaMeta()));
57152
}
58153

59154
public void setCallCode(Code callCode) {
60155
this.callCode = callCode;
61156
}
157+
62158
}

src/main/java/org/tarantool/Iterator.java

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.tarantool;
22

3+
import java.util.Arrays;
4+
35
// Iterator info was taken from here https://github.com/tarantool/tarantool/blob/f66584c3bcdffe61d6d99a4868a9b72d62338a11/src/box/iterator_type.h#L62
46
public enum Iterator {
57
EQ(0), // key == x ASC order
@@ -24,4 +26,12 @@ public enum Iterator {
2426
public int getValue() {
2527
return value;
2628
}
29+
30+
public static Iterator valueOf(int value) {
31+
return Arrays.stream(Iterator.values())
32+
.filter(v -> value == v.getValue())
33+
.findFirst()
34+
.orElseThrow(IllegalArgumentException::new);
35+
}
36+
2737
}

src/main/java/org/tarantool/MsgPackLite.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.tarantool;
22

3+
import org.tarantool.util.TupleTwo;
4+
35
import java.io.DataInputStream;
46
import java.io.DataOutputStream;
57
import java.io.IOException;
@@ -226,6 +228,11 @@ public void pack(Object item, OutputStream os) throws IOException {
226228
pack(kvp.getKey(), out);
227229
pack(kvp.getValue(), out);
228230
}
231+
} else if (item instanceof TupleTwo) {
232+
TupleTwo<?, ?> tuple = (TupleTwo<?, ?>) item;
233+
out.write(1 | MP_FIXMAP);
234+
pack(tuple.getFirst(), out);
235+
pack(tuple.getSecond(), out);
229236
} else {
230237
throw new IllegalArgumentException("Cannot msgpack object of type " + item.getClass().getCanonicalName());
231238
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package org.tarantool;
2+
3+
import java.util.Objects;
4+
import java.util.function.Supplier;
5+
6+
/**
7+
* Request argument factory.
8+
*
9+
* @see TarantoolRequestArgument
10+
*/
11+
public class RequestArguments {
12+
13+
private RequestArguments() {
14+
}
15+
16+
public static TarantoolRequestArgument value(Object value) {
17+
return new SimpleArgument(value);
18+
}
19+
20+
public static TarantoolRequestArgument cacheLookupValue(Supplier<Object> supplier) {
21+
return new LookupArgument(supplier);
22+
}
23+
24+
/**
25+
* Simple wrapper that holds the original value.
26+
*/
27+
private static class SimpleArgument implements TarantoolRequestArgument {
28+
29+
private Object value;
30+
31+
SimpleArgument(Object value) {
32+
Objects.requireNonNull(value);
33+
this.value = value;
34+
}
35+
36+
@Override
37+
public boolean isSerializable() {
38+
return true;
39+
}
40+
41+
@Override
42+
public Object getValue() {
43+
return value;
44+
}
45+
46+
}
47+
48+
/**
49+
* Wrapper that evaluates the value each time
50+
* it is requested.
51+
* <p>
52+
* It works like a function, where {@code argument = f(key)}.
53+
*/
54+
private static class LookupArgument implements TarantoolRequestArgument {
55+
56+
Supplier<Object> lookup;
57+
58+
LookupArgument(Supplier<Object> lookup) {
59+
this.lookup = Objects.requireNonNull(lookup);
60+
}
61+
62+
@Override
63+
public boolean isSerializable() {
64+
try {
65+
lookup.get();
66+
} catch (Exception ignored) {
67+
return false;
68+
}
69+
return true;
70+
}
71+
72+
@Override
73+
public synchronized Object getValue() {
74+
return lookup.get();
75+
}
76+
77+
}
78+
79+
}

src/main/java/org/tarantool/TarantoolBase.java

+1-12
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
import java.io.IOException;
77
import java.net.Socket;
88
import java.nio.channels.SocketChannel;
9-
import java.util.List;
109
import java.util.concurrent.atomic.AtomicLong;
1110

12-
public abstract class TarantoolBase<Result> extends AbstractTarantoolOps<Integer, List<?>, Object, Result> {
11+
public abstract class TarantoolBase<Result> extends AbstractTarantoolOps<Result> {
1312
protected String serverVersion;
1413
protected MsgPackLite msgPackLite = MsgPackLite.INSTANCE;
1514
protected AtomicLong syncId = new AtomicLong();
@@ -42,16 +41,6 @@ protected void closeChannel(SocketChannel channel) {
4241
}
4342
}
4443

45-
protected void validateArgs(Object[] args) {
46-
if (args != null) {
47-
for (int i = 0; i < args.length; i += 2) {
48-
if (args[i + 1] == null) {
49-
throw new NullPointerException(((Key) args[i]).name() + " should not be null");
50-
}
51-
}
52-
}
53-
}
54-
5544
public void setInitialRequestSize(int initialRequestSize) {
5645
this.initialRequestSize = initialRequestSize;
5746
}

src/main/java/org/tarantool/TarantoolClient.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
package org.tarantool;
22

3+
import org.tarantool.schema.TarantoolSchemaMeta;
4+
35
import java.util.List;
46
import java.util.Map;
57
import java.util.concurrent.CompletionStage;
68
import java.util.concurrent.Future;
79
import java.util.concurrent.TimeUnit;
810

911
public interface TarantoolClient {
10-
TarantoolClientOps<Integer, List<?>, Object, List<?>> syncOps();
12+
TarantoolClientOps<List<?>, Object, List<?>> syncOps();
1113

12-
TarantoolClientOps<Integer, List<?>, Object, Future<List<?>>> asyncOps();
14+
TarantoolClientOps<List<?>, Object, Future<List<?>>> asyncOps();
1315

14-
TarantoolClientOps<Integer, List<?>, Object, CompletionStage<List<?>>> composableAsyncOps();
16+
TarantoolClientOps<List<?>, Object, CompletionStage<List<?>>> composableAsyncOps();
1517

16-
TarantoolClientOps<Integer, List<?>, Object, Long> fireAndForgetOps();
18+
TarantoolClientOps<List<?>, Object, Long> fireAndForgetOps();
1719

1820
TarantoolSQLOps<Object, Long, List<Map<String, Object>>> sqlSyncOps();
1921

@@ -29,4 +31,6 @@ public interface TarantoolClient {
2931

3032
boolean waitAlive(long timeout, TimeUnit unit) throws InterruptedException;
3133

34+
TarantoolSchemaMeta getSchemaMeta();
35+
3236
}

0 commit comments

Comments
 (0)