Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 38bb1ac

Browse files
authored
[DE-959] Improve serde perfs (#588)
* improved extraction of user-data bytes for JSON content type * improved extraction of user-data bytes for VPACK content type * improved deserialization of managed classes by avoid extracting bytes when not needed * improved serialization of JsonNode by avoid intermediate parsing when not needed * improved RawJson deserialization * improved RawJson serialization * improved extract bytes at json pointer * improved deserialize bytes at json pointer * improved serialize user data bytes * improved serialize list of user data * improved deserialize of responses of CRUD operations on multiple documents * improved RawJson serialization * fixed deserialization of multiple documents * fixed deserialization of multiple documents to user data * fixed compatibility with older Jackson versions * benchmark deserialize multiple documents * updated jackson-dataformat-velocypack 4.5.0
1 parent 648ecb5 commit 38bb1ac

File tree

39 files changed

+690
-345
lines changed

39 files changed

+690
-345
lines changed

‎.circleci/config.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,8 @@ workflows:
535535
matrix:
536536
parameters:
537537
args:
538-
- '-Dadb.jackson.version=2.18.0'
539-
- '-Dadb.jackson.version=2.17.2'
538+
- '-Dadb.jackson.version=2.18.2'
539+
- '-Dadb.jackson.version=2.17.3'
540540
- '-Dadb.jackson.version=2.16.2'
541541
- '-Dadb.jackson.version=2.15.4'
542542
- '-Dadb.jackson.version=2.14.3'
@@ -551,7 +551,7 @@ workflows:
551551
only:
552552
- main
553553
- test:
554-
name: test-native-ssl=<<matrix.ssl>>
554+
name: test-native-ssl=<<matrix.ssl>>-<<matrix.graalvm-version>>
555555
matrix:
556556
parameters:
557557
native:
@@ -571,7 +571,7 @@ workflows:
571571
only:
572572
- main
573573
- test-shaded:
574-
name: test-native-shaded-ssl=<<matrix.ssl>>
574+
name: test-native-shaded-ssl=<<matrix.ssl>>-<<matrix.graalvm-version>>
575575
matrix:
576576
parameters:
577577
native:

‎core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<relativePath>../release-parent</relativePath>
99
<groupId>com.arangodb</groupId>
1010
<artifactId>release-parent</artifactId>
11-
<version>7.14.0</version>
11+
<version>7.15.0-SNAPSHOT</version>
1212
</parent>
1313

1414
<name>core</name>

‎core/src/main/java/com/arangodb/entity/MultiDocumentEntity.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@
2020

2121
package com.arangodb.entity;
2222

23+
import java.util.ArrayList;
2324
import java.util.List;
2425

2526
/**
2627
* @author Mark Vollmary
2728
*/
2829
public final class MultiDocumentEntity<E> {
2930

30-
private List<E> documents;
31-
private List<ErrorEntity> errors;
32-
private List<Object> documentsAndErrors;
31+
private List<E> documents = newArrayList<>();
32+
private List<ErrorEntity> errors = newArrayList<>();
33+
private List<Object> documentsAndErrors = newArrayList<>();
3334
private boolean isPotentialDirtyRead = false;
3435

3536
public MultiDocumentEntity() {

‎core/src/main/java/com/arangodb/internal/InternalArangoCollection.java

Lines changed: 15 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import java.lang.reflect.Type;
3333
import java.util.ArrayList;
3434
import java.util.Collection;
35-
import java.util.List;
3635

3736
import static com.arangodb.internal.serde.SerdeUtils.constructParametricType;
3837

@@ -111,28 +110,9 @@ private InternalRequest createInsertDocumentRequest(final DocumentCreateOptions
111110

112111
protected <T> ResponseDeserializer<MultiDocumentEntity<DocumentCreateEntity<T>>> insertDocumentsResponseDeserializer(Class<T> userDataClass) {
113112
return (response) -> {
114-
final MultiDocumentEntity<DocumentCreateEntity<T>> multiDocument = new MultiDocumentEntity<>();
115-
final List<DocumentCreateEntity<T>> docs = new ArrayList<>();
116-
final List<ErrorEntity> errors = new ArrayList<>();
117-
final List<Object> documentsAndErrors = new ArrayList<>();
118-
final JsonNode body = getSerde().parse(response.getBody());
119-
for (final JsonNode next : body) {
120-
JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME);
121-
if (isError != null && isError.booleanValue()) {
122-
final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class);
123-
errors.add(error);
124-
documentsAndErrors.add(error);
125-
} else {
126-
Type type = constructParametricType(DocumentCreateEntity.class, userDataClass);
127-
final DocumentCreateEntity<T> doc = getSerde().deserialize(next, type);
128-
docs.add(doc);
129-
documentsAndErrors.add(doc);
130-
}
131-
}
132-
multiDocument.setDocuments(docs);
133-
multiDocument.setErrors(errors);
134-
multiDocument.setDocumentsAndErrors(documentsAndErrors);
135-
return multiDocument;
113+
Type type = constructParametricType(MultiDocumentEntity.class,
114+
constructParametricType(DocumentCreateEntity.class, userDataClass));
115+
return getSerde().deserialize(response.getBody(), type);
136116
};
137117
}
138118

@@ -184,31 +164,12 @@ protected InternalRequest getDocumentsRequest(final Iterable<String> keys, final
184164
return request;
185165
}
186166

187-
protected <T> ResponseDeserializer<MultiDocumentEntity<T>> getDocumentsResponseDeserializer(
188-
final Class<T> type) {
167+
protected <T> ResponseDeserializer<MultiDocumentEntity<T>> getDocumentsResponseDeserializer(final Class<T> type) {
189168
return (response) -> {
190-
final MultiDocumentEntity<T> multiDocument = new MultiDocumentEntity<>();
169+
MultiDocumentEntity<T> multiDocument = getSerde().deserialize(response.getBody(),
170+
constructParametricType(MultiDocumentEntity.class, type));
191171
boolean potentialDirtyRead = Boolean.parseBoolean(response.getMeta("X-Arango-Potential-Dirty-Read"));
192172
multiDocument.setPotentialDirtyRead(potentialDirtyRead);
193-
final List<T> docs = new ArrayList<>();
194-
final List<ErrorEntity> errors = new ArrayList<>();
195-
final List<Object> documentsAndErrors = new ArrayList<>();
196-
final JsonNode body = getSerde().parse(response.getBody());
197-
for (final JsonNode next : body) {
198-
JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME);
199-
if (isError != null && isError.booleanValue()) {
200-
final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class);
201-
errors.add(error);
202-
documentsAndErrors.add(error);
203-
} else {
204-
final T doc = getSerde().deserializeUserData(getSerde().serialize(next), type);
205-
docs.add(doc);
206-
documentsAndErrors.add(doc);
207-
}
208-
}
209-
multiDocument.setDocuments(docs);
210-
multiDocument.setErrors(errors);
211-
multiDocument.setDocumentsAndErrors(documentsAndErrors);
212173
return multiDocument;
213174
};
214175
}
@@ -250,28 +211,9 @@ private InternalRequest createReplaceDocumentRequest(final DocumentReplaceOption
250211
protected <T> ResponseDeserializer<MultiDocumentEntity<DocumentUpdateEntity<T>>> replaceDocumentsResponseDeserializer(
251212
final Class<T> returnType) {
252213
return (response) -> {
253-
final MultiDocumentEntity<DocumentUpdateEntity<T>> multiDocument = new MultiDocumentEntity<>();
254-
final List<DocumentUpdateEntity<T>> docs = new ArrayList<>();
255-
final List<ErrorEntity> errors = new ArrayList<>();
256-
final List<Object> documentsAndErrors = new ArrayList<>();
257-
final JsonNode body = getSerde().parse(response.getBody());
258-
for (final JsonNode next : body) {
259-
JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME);
260-
if (isError != null && isError.booleanValue()) {
261-
final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class);
262-
errors.add(error);
263-
documentsAndErrors.add(error);
264-
} else {
265-
Type type = constructParametricType(DocumentUpdateEntity.class, returnType);
266-
final DocumentUpdateEntity<T> doc = getSerde().deserialize(next, type);
267-
docs.add(doc);
268-
documentsAndErrors.add(doc);
269-
}
270-
}
271-
multiDocument.setDocuments(docs);
272-
multiDocument.setErrors(errors);
273-
multiDocument.setDocumentsAndErrors(documentsAndErrors);
274-
return multiDocument;
214+
Type type = constructParametricType(MultiDocumentEntity.class,
215+
constructParametricType(DocumentUpdateEntity.class, returnType));
216+
return getSerde().deserialize(response.getBody(), type);
275217
};
276218
}
277219

@@ -313,28 +255,9 @@ private InternalRequest createUpdateDocumentRequest(final DocumentUpdateOptions
313255
protected <T> ResponseDeserializer<MultiDocumentEntity<DocumentUpdateEntity<T>>> updateDocumentsResponseDeserializer(
314256
final Class<T> returnType) {
315257
return (response) -> {
316-
final MultiDocumentEntity<DocumentUpdateEntity<T>> multiDocument = new MultiDocumentEntity<>();
317-
final List<DocumentUpdateEntity<T>> docs = new ArrayList<>();
318-
final List<ErrorEntity> errors = new ArrayList<>();
319-
final List<Object> documentsAndErrors = new ArrayList<>();
320-
final JsonNode body = getSerde().parse(response.getBody());
321-
for (final JsonNode next : body) {
322-
JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME);
323-
if (isError != null && isError.booleanValue()) {
324-
final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class);
325-
errors.add(error);
326-
documentsAndErrors.add(error);
327-
} else {
328-
Type type = constructParametricType(DocumentUpdateEntity.class, returnType);
329-
final DocumentUpdateEntity<T> doc = getSerde().deserialize(next, type);
330-
docs.add(doc);
331-
documentsAndErrors.add(doc);
332-
}
333-
}
334-
multiDocument.setDocuments(docs);
335-
multiDocument.setErrors(errors);
336-
multiDocument.setDocumentsAndErrors(documentsAndErrors);
337-
return multiDocument;
258+
Type type = constructParametricType(MultiDocumentEntity.class,
259+
constructParametricType(DocumentUpdateEntity.class, returnType));
260+
return getSerde().deserialize(response.getBody(), type);
338261
};
339262
}
340263

@@ -370,28 +293,9 @@ private InternalRequest createDeleteDocumentRequest(final DocumentDeleteOptions
370293
protected <T> ResponseDeserializer<MultiDocumentEntity<DocumentDeleteEntity<T>>> deleteDocumentsResponseDeserializer(
371294
final Class<T> userDataClass) {
372295
return (response) -> {
373-
final MultiDocumentEntity<DocumentDeleteEntity<T>> multiDocument = new MultiDocumentEntity<>();
374-
final List<DocumentDeleteEntity<T>> docs = new ArrayList<>();
375-
final List<ErrorEntity> errors = new ArrayList<>();
376-
final List<Object> documentsAndErrors = new ArrayList<>();
377-
final JsonNode body = getSerde().parse(response.getBody());
378-
for (final JsonNode next : body) {
379-
JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME);
380-
if (isError != null && isError.booleanValue()) {
381-
final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class);
382-
errors.add(error);
383-
documentsAndErrors.add(error);
384-
} else {
385-
Type type = constructParametricType(DocumentDeleteEntity.class, userDataClass);
386-
final DocumentDeleteEntity<T> doc = getSerde().deserialize(next, type);
387-
docs.add(doc);
388-
documentsAndErrors.add(doc);
389-
}
390-
}
391-
multiDocument.setDocuments(docs);
392-
multiDocument.setErrors(errors);
393-
multiDocument.setDocumentsAndErrors(documentsAndErrors);
394-
return multiDocument;
296+
Type type = constructParametricType(MultiDocumentEntity.class,
297+
constructParametricType(DocumentDeleteEntity.class, userDataClass));
298+
return getSerde().deserialize(response.getBody(), type);
395299
};
396300
}
397301

‎core/src/main/java/com/arangodb/internal/net/Communication.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
import java.util.concurrent.TimeoutException;
2424
import java.util.concurrent.atomic.AtomicLong;
2525

26-
import static com.arangodb.internal.util.SerdeUtils.toJsonString;
27-
2826
@UsedInApi
2927
public abstract class Communication implements Closeable {
3028
private static final Logger LOGGER = LoggerFactory.getLogger(Communication.class);
@@ -59,7 +57,7 @@ private CompletableFuture<InternalResponse> doExecuteAsync(
5957
final InternalRequest request, final HostHandle hostHandle, final Host host, final int attemptCount, Connection connection, long reqId
6058
) {
6159
if (LOGGER.isDebugEnabled()) {
62-
LOGGER.debug("Send Request [id={}]: {} {}", reqId, request, toJsonString(serde, request.getBody()));
60+
LOGGER.debug("Send Request [id={}]: {} {}", reqId, request, serde.toJsonString(request.getBody()));
6361
}
6462
final CompletableFuture<InternalResponse> rfuture = new CompletableFuture<>();
6563
try {
@@ -85,7 +83,7 @@ private CompletableFuture<InternalResponse> doExecuteAsync(
8583
handleException(isSafe(request), e, hostHandle, request, host, reqId, attemptCount, rfuture);
8684
} else {
8785
if (LOGGER.isDebugEnabled()) {
88-
LOGGER.debug("Received Response [id={}]: {} {}", reqId, response, toJsonString(serde, response.getBody()));
86+
LOGGER.debug("Received Response [id={}]: {} {}", reqId, response, serde.toJsonString(response.getBody()));
8987
}
9088
ArangoDBException errorEntityEx = ResponseUtils.translateError(serde, response);
9189
if (errorEntityEx instanceof ArangoDBRedirectException) {

‎core/src/main/java/com/arangodb/internal/serde/InternalDeserializers.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
import com.arangodb.entity.ReplicationFactor;
77
import com.arangodb.entity.arangosearch.CollectionLink;
88
import com.arangodb.entity.arangosearch.FieldLink;
9+
import com.arangodb.util.RawBytes;
910
import com.arangodb.util.RawJson;
1011
import com.arangodb.internal.InternalResponse;
12+
import com.fasterxml.jackson.core.JsonFactory;
13+
import com.fasterxml.jackson.core.JsonGenerator;
1114
import com.fasterxml.jackson.core.JsonParser;
1215
import com.fasterxml.jackson.core.TreeNode;
1316
import com.fasterxml.jackson.databind.DeserializationContext;
@@ -16,6 +19,8 @@
1619
import com.fasterxml.jackson.databind.node.*;
1720

1821
import java.io.IOException;
22+
import java.io.StringWriter;
23+
import java.nio.charset.StandardCharsets;
1924
import java.util.ArrayList;
2025
import java.util.Collection;
2126
import java.util.Iterator;
@@ -26,7 +31,23 @@ public final class InternalDeserializers {
2631
static final JsonDeserializer<RawJson> RAW_JSON_DESERIALIZER = new JsonDeserializer<RawJson>() {
2732
@Override
2833
public RawJson deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
29-
return RawJson.of(SerdeUtils.INSTANCE.writeJson(p.readValueAsTree()));
34+
if (JsonFactory.FORMAT_NAME_JSON.equals(p.getCodec().getFactory().getFormatName())) {
35+
return RawJson.of(new String(SerdeUtils.extractBytes(p), StandardCharsets.UTF_8));
36+
} else {
37+
StringWriter w = new StringWriter();
38+
try (JsonGenerator gen = SerdeUtils.INSTANCE.getJsonMapper().getFactory().createGenerator(w)) {
39+
gen.copyCurrentStructure(p);
40+
gen.flush();
41+
}
42+
return RawJson.of(w.toString());
43+
}
44+
}
45+
};
46+
47+
static final JsonDeserializer<RawBytes> RAW_BYTES_DESERIALIZER = new JsonDeserializer<RawBytes>() {
48+
@Override
49+
public RawBytes deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
50+
return RawBytes.of(SerdeUtils.extractBytes(p));
3051
}
3152
};
3253

@@ -134,5 +155,4 @@ public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
134155
}
135156
}
136157

137-
138158
}

‎core/src/main/java/com/arangodb/internal/serde/InternalModule.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,34 @@
33
import com.arangodb.entity.CollectionStatus;
44
import com.arangodb.entity.CollectionType;
55
import com.arangodb.entity.InvertedIndexPrimarySort;
6+
import com.arangodb.entity.MultiDocumentEntity;
67
import com.arangodb.entity.ReplicationFactor;
8+
import com.arangodb.util.RawBytes;
79
import com.arangodb.util.RawJson;
810
import com.arangodb.internal.InternalRequest;
911
import com.arangodb.internal.InternalResponse;
1012
import com.fasterxml.jackson.databind.Module;
1113
import com.fasterxml.jackson.databind.module.SimpleModule;
1214

13-
importjava.util.function.Supplier;
15+
classInternalModule {
1416

15-
enumInternalModuleimplementsSupplier<Module> {
16-
INSTANCE;
17+
staticModuleget(InternalSerdeserde) {
18+
SimpleModulemodule = newSimpleModule();
1719

18-
private final SimpleModule module;
19-
20-
InternalModule() {
21-
module = new SimpleModule();
20+
module.addDeserializer(MultiDocumentEntity.class, new MultiDocumentEntityDeserializer(serde));
2221

2322
module.addSerializer(RawJson.class, InternalSerializers.RAW_JSON_SERIALIZER);
2423
module.addSerializer(InternalRequest.class, InternalSerializers.REQUEST);
2524
module.addSerializer(CollectionType.class, InternalSerializers.COLLECTION_TYPE);
2625

2726
module.addDeserializer(RawJson.class, InternalDeserializers.RAW_JSON_DESERIALIZER);
27+
module.addDeserializer(RawBytes.class, InternalDeserializers.RAW_BYTES_DESERIALIZER);
2828
module.addDeserializer(CollectionStatus.class, InternalDeserializers.COLLECTION_STATUS);
2929
module.addDeserializer(CollectionType.class, InternalDeserializers.COLLECTION_TYPE);
3030
module.addDeserializer(ReplicationFactor.class, InternalDeserializers.REPLICATION_FACTOR);
3131
module.addDeserializer(InternalResponse.class, InternalDeserializers.RESPONSE);
3232
module.addDeserializer(InvertedIndexPrimarySort.Field.class, InternalDeserializers.INVERTED_INDEX_PRIMARY_SORT_FIELD);
33-
}
3433

35-
@Override
36-
public Module get() {
3734
return module;
3835
}
39-
4036
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /