Skip to content

Commit 2894a02

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. Closes: #7, #137
1 parent 2473ffa commit 2894a02

27 files changed

+1400
-207
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,18 @@ makes possible for the client to configure a socket provider.
122122
* `ComposableAsyncOps` - return the operation result as a `CompletionStage`
123123
* `FireAndForgetOps` - returns the query ID
124124

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

Lines changed: 206 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,244 @@
11
package org.tarantool;
22

3+
import static org.tarantool.AbstractTarantoolOps.ResolvableArgument.ofResolved;
4+
import static org.tarantool.AbstractTarantoolOps.ResolvableArgument.ofUnresolved;
35

4-
public abstract class AbstractTarantoolOps<Space, Tuple, Operation, Result>
5-
implements TarantoolClientOps<Space, Tuple, Operation, Result> {
6+
import org.tarantool.schema.TarantoolIndexNotFoundException;
7+
import org.tarantool.schema.TarantoolSpaceNotFoundException;
8+
9+
import java.util.Objects;
10+
import java.util.function.Function;
11+
import java.util.stream.Stream;
12+
13+
public abstract class AbstractTarantoolOps<Tuple, Operation, Result>
14+
implements TarantoolClientOps<Tuple, Operation, Result> {
15+
16+
private final Function<Object, Object> defaultSpaceResolver = space -> resolveSpace((String) space);
617

718
private Code callCode = Code.OLD_CALL;
819

9-
protected abstract Result exec(Code code, Object... args);
20+
protected Result exec(Code code, Object... args) {
21+
return exec(code, ResolvableArgument.ofAllResolved(args));
22+
}
23+
24+
protected abstract Result exec(Code code, ResolvableArgument... args);
25+
26+
protected abstract int resolveSpace(String space);
27+
28+
protected abstract int resolveSpaceIndex(String space, String index);
29+
30+
protected static class ResolvableArgument {
31+
32+
private Object value;
33+
private Function<Object, Object> resolver;
34+
35+
private ResolvableArgument(Object value, Function<Object, Object> resolver) {
36+
Objects.requireNonNull(value);
37+
this.value = value;
38+
this.resolver = resolver;
39+
}
40+
41+
public static ResolvableArgument ofResolved(Object resolvedValue) {
42+
return new ResolvableArgument(resolvedValue, null);
43+
}
44+
45+
public static ResolvableArgument[] ofAllResolved(Object[] resolvedValue) {
46+
return Stream.of(resolvedValue).map(ResolvableArgument::ofResolved).toArray(ResolvableArgument[]::new);
47+
}
48+
49+
public static ResolvableArgument ofUnresolved(Object unresolvedValue, Function<Object, Object> resolver) {
50+
return new ResolvableArgument(unresolvedValue, resolver);
51+
}
52+
53+
public boolean isUnresolved() {
54+
return resolver != null;
55+
}
56+
57+
public Object getValue() {
58+
if (isUnresolved()) {
59+
value = resolver.apply(value);
60+
resolver = null;
61+
}
62+
return value;
63+
}
1064

11-
public Result select(Space space, Space index, Tuple key, int offset, int limit, Iterator iterator) {
65+
@Override
66+
public String toString() {
67+
if (isUnresolved()) {
68+
return "{unresolved: " + value + "}";
69+
}
70+
return value.toString();
71+
}
72+
73+
}
74+
75+
@Override
76+
public Result select(Integer space, Integer index, Tuple key, int offset, int limit, Iterator iterator) {
1277
return select(space, index, key, offset, limit, iterator.getValue());
1378
}
1479

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
24-
);
80+
@Override
81+
public Result select(String space, String index, Tuple key, int offset, int limit, Iterator iterator) {
82+
return select(space, index, key, offset, limit, iterator.getValue());
83+
}
84+
85+
@Override
86+
public Result select(Integer space, Integer index, Tuple key, int offset, int limit, int iterator) {
87+
return doSelect(ofResolved(space), ofResolved(index), key, offset, limit, iterator);
88+
}
89+
90+
@Override
91+
public Result select(String space, String index, Tuple key, int offset, int limit, int iterator) {
92+
try {
93+
return select(resolveSpace(space), resolveSpaceIndex(space, index), key, offset, limit, iterator);
94+
} catch (TarantoolSpaceNotFoundException | TarantoolIndexNotFoundException ignored) {
95+
return doSelect(
96+
ofUnresolved(space, defaultSpaceResolver),
97+
ofUnresolved(index, indexName -> resolveSpaceIndex(space, (String) indexName)),
98+
key, offset, limit, iterator
99+
);
100+
}
101+
}
102+
103+
@Override
104+
public Result insert(Integer space, Tuple tuple) {
105+
return doInsert(ofResolved(space), tuple);
106+
}
107+
108+
@Override
109+
public Result insert(String space, Tuple tuple) {
110+
try {
111+
return insert(resolveSpace(space), tuple);
112+
} catch (TarantoolSpaceNotFoundException e) {
113+
return doInsert(ofUnresolved(space, defaultSpaceResolver), tuple);
114+
}
115+
}
116+
117+
@Override
118+
public Result replace(Integer space, Tuple tuple) {
119+
return doReplace(ofResolved(space), tuple);
120+
}
121+
122+
@Override
123+
public Result replace(String space, Tuple tuple) {
124+
try {
125+
return replace(resolveSpace(space), tuple);
126+
} catch (TarantoolSpaceNotFoundException ignored) {
127+
return doReplace(ofUnresolved(space, defaultSpaceResolver), tuple);
128+
}
129+
}
130+
131+
@Override
132+
public Result update(Integer space, Tuple key, Operation... args) {
133+
return doUpdate(ofResolved(space), key, args);
25134
}
26135

27-
public Result insert(Space space, Tuple tuple) {
28-
return exec(Code.INSERT, Key.SPACE, space, Key.TUPLE, tuple);
136+
@Override
137+
public Result update(String space, Tuple key, Operation... tuple) {
138+
try {
139+
return update(resolveSpace(space), key, tuple);
140+
} catch (TarantoolSpaceNotFoundException ignored) {
141+
return doUpdate(ofUnresolved(space, defaultSpaceResolver), key, tuple);
142+
}
29143
}
30144

31-
public Result replace(Space space, Tuple tuple) {
32-
return exec(Code.REPLACE, Key.SPACE, space, Key.TUPLE, tuple);
145+
@Override
146+
public Result upsert(Integer space, Tuple key, Tuple defTuple, Operation... ops) {
147+
return doUpsert(ofResolved(space), key, defTuple, ops);
33148
}
34149

35-
public Result update(Space space, Tuple key, Operation... args) {
36-
return exec(Code.UPDATE, Key.SPACE, space, Key.KEY, key, Key.TUPLE, args);
150+
@Override
151+
public Result upsert(String space, Tuple key, Tuple defTuple, Operation... ops) {
152+
try {
153+
return upsert(resolveSpace(space), key, defTuple, ops);
154+
} catch (TarantoolSpaceNotFoundException ignored) {
155+
return doUpsert(ofUnresolved(space, defaultSpaceResolver), key, defTuple, ops);
156+
}
37157
}
38158

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);
159+
@Override
160+
public Result delete(Integer space, Tuple key) {
161+
return doDelete(ofResolved(space), key);
41162
}
42163

43-
public Result delete(Space space, Tuple key) {
44-
return exec(Code.DELETE, Key.SPACE, space, Key.KEY, key);
164+
@Override
165+
public Result delete(String space, Tuple key) {
166+
try {
167+
return delete(resolveSpace(space), key);
168+
} catch (TarantoolSpaceNotFoundException ignored) {
169+
return doDelete(ofUnresolved(space, defaultSpaceResolver), key);
170+
}
45171
}
46172

173+
@Override
47174
public Result call(String function, Object... args) {
48175
return exec(callCode, Key.FUNCTION, function, Key.TUPLE, args);
49176
}
50177

178+
@Override
51179
public Result eval(String expression, Object... args) {
52180
return exec(Code.EVAL, Key.EXPRESSION, expression, Key.TUPLE, args);
53181
}
54182

183+
@Override
55184
public void ping() {
56185
exec(Code.PING);
57186
}
58187

59188
public void setCallCode(Code callCode) {
60189
this.callCode = callCode;
61190
}
191+
192+
private Result doDelete(ResolvableArgument space, Tuple key) {
193+
return exec(Code.DELETE, ofResolved(Key.SPACE), space, ofResolved(Key.KEY), ofResolved(key));
194+
}
195+
196+
private Result doUpsert(ResolvableArgument space, Tuple key, Tuple defTuple, Operation... ops) {
197+
return exec(
198+
Code.UPSERT,
199+
ofResolved(Key.SPACE), space,
200+
ofResolved(Key.KEY), ofResolved(key),
201+
ofResolved(Key.TUPLE), ofResolved(defTuple),
202+
ofResolved(Key.UPSERT_OPS), ofResolved(ops)
203+
);
204+
}
205+
206+
private Result doUpdate(ResolvableArgument space, Tuple key, Operation... ops) {
207+
ResolvableArgument[] arguments = new ResolvableArgument[] {
208+
209+
};
210+
211+
return exec(
212+
Code.UPDATE,
213+
ofResolved(Key.SPACE), space,
214+
ofResolved(Key.KEY), ofResolved(key),
215+
ofResolved(Key.TUPLE), ofResolved(ops)
216+
);
217+
}
218+
219+
private Result doReplace(ResolvableArgument space, Tuple tuple) {
220+
return exec(Code.REPLACE, ofResolved(Key.SPACE), space, ofResolved(Key.TUPLE), ofResolved(tuple));
221+
}
222+
223+
private Result doInsert(ResolvableArgument space, Tuple tuple) {
224+
return exec(Code.INSERT, ofResolved(Key.SPACE), space, ofResolved(Key.TUPLE), ofResolved(tuple));
225+
}
226+
227+
private Result doSelect(ResolvableArgument space,
228+
ResolvableArgument index,
229+
Tuple key,
230+
int offset,
231+
int limit,
232+
int iterator) {
233+
return exec(
234+
Code.SELECT,
235+
ofResolved(Key.SPACE), space,
236+
ofResolved(Key.INDEX), index,
237+
ofResolved(Key.KEY), ofResolved(key),
238+
ofResolved(Key.ITERATOR), ofResolved(iterator),
239+
ofResolved(Key.LIMIT), ofResolved(limit),
240+
ofResolved(Key.OFFSET), ofResolved(offset)
241+
);
242+
}
243+
62244
}

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

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import java.util.List;
1010
import java.util.concurrent.atomic.AtomicLong;
1111

12-
public abstract class TarantoolBase<Result> extends AbstractTarantoolOps<Integer, List<?>, Object, Result> {
12+
public abstract class TarantoolBase<Result> extends AbstractTarantoolOps<List<?>, Object, Result> {
1313
protected String serverVersion;
1414
protected MsgPackLite msgPackLite = MsgPackLite.INSTANCE;
1515
protected AtomicLong syncId = new AtomicLong();
@@ -42,16 +42,6 @@ protected void closeChannel(SocketChannel channel) {
4242
}
4343
}
4444

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-
5545
public void setInitialRequestSize(int initialRequestSize) {
5646
this.initialRequestSize = initialRequestSize;
5747
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
import java.util.concurrent.TimeUnit;
88

99
public interface TarantoolClient {
10-
TarantoolClientOps<Integer, List<?>, Object, List<?>> syncOps();
10+
TarantoolClientOps<List<?>, Object, List<?>> syncOps();
1111

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

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

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

1818
TarantoolSQLOps<Object, Long, List<Map<String, Object>>> sqlSyncOps();
1919

0 commit comments

Comments
 (0)