diff --git a/CHANGELOG.md b/CHANGELOG.md
index e187feff..287021df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,17 @@
# Changelog
## [Unreleased]
+
+### Bugfixes
+
+- Significantly reduce memory allocation overhead and excessive GC pressure ([#401](https://github.com/tarantool/cartridge-java/issues/401))
+
### Internal and API changes
- Bump org.testcontainers:junit-jupiter version to 1.19.3 ([#442](https://github.com/tarantool/cartridge-java/issues/442))
- Bump testcontainers-java-tarantool version to 1.2.0 ([#442](https://github.com/tarantool/cartridge-java/issues/442))
- Bump netty version to 4.1.104.Final ([#446](https://github.com/tarantool/cartridge-java/issues/446))
+- Bump msgpack-java version to 0.9.6
### Features
diff --git a/profile.jfc b/profile.jfc
new file mode 100644
index 00000000..2158029e
--- /dev/null
+++ b/profile.jfc
@@ -0,0 +1,809 @@
+
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+ 1000 ms
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+ 1000 ms
+
+
+
+ true
+ true
+
+
+
+ true
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 0 ms
+
+
+
+ true
+ true
+ 0 ms
+
+
+
+ true
+ true
+ 0 ms
+
+
+
+ true
+ true
+
+
+
+ false
+ true
+ 0 ms
+
+
+
+ false
+ true
+
+
+
+ false
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ 10 ms
+
+
+
+ true
+ 20 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ false
+ 0 ms
+
+
+
+ false
+ 0 ms
+
+
+
+ false
+ 0 ms
+
+
+
+ false
+ 0 ms
+
+
+
+ false
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ true
+
+
+
+ true
+ 60 s
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ false
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+ true
+
+
+
+ true
+ true
+
+
+
+ true
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ false
+ 0 ms
+
+
+
+ false
+ 0 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ false
+ true
+
+
+
+ true
+
+
+
+ false
+ everyChunk
+
+
+
+ false
+
+
+
+ true
+ true
+ 0 ns
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ 1000 ms
+
+
+
+ true
+ 100 ms
+
+
+
+ true
+ 10 s
+
+
+
+ true
+
+
+
+ false
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+ 100 ms
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ 10 s
+
+
+
+ true
+ 1000 ms
+
+
+
+ true
+ 10 s
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ endChunk
+
+
+
+ true
+ 5 s
+
+
+
+ true
+ beginChunk
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+ true
+
+
+
+ true
+ true
+
+
+
+ true
+ everyChunk
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+ 10 ms
+
+
+
+ true
+ true
+
+
+
+ false
+ true
+
+
+
+ true
+ 1000 ms
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+ 10 ms
+
+
+
+ true
+ 0 ms
+
+
+
+ 10 ms
+ true
+
+
+
+ true
+ 10 ms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10 ms
+
+ 10 ms
+
+ 10 ms
+
+ false
+
+
+
+
diff --git a/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java b/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java
index 4792b062..527541b9 100644
--- a/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java
+++ b/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java
@@ -4,6 +4,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -23,35 +24,61 @@
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
-@Fork(value = 1, jvmArgsAppend = "-Xmx1G")
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Fork(value = 1, jvmArgsAppend = {
+ "-Xms1G", "-Xmx1G", "-XX:+UseG1GC", //"-XX:+UnlockCommercialFeatures",
+ "-XX:+FlightRecorder",
+ "--add-opens=java.base/java.nio=ALL-UNNAMED", "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED",
+ "-XX:StartFlightRecording=settings=/home/fedora/sources/cartridge-java/profile.jfc"
+})
public class ClusterBenchmarkRunner {
private static final String TEST_SPACE = "test_space";
private static final String TEST_PROFILE = "test__profile";
+ private static final String CLUSTER_INIT_SCRIPT = "org/testcontainers/containers/cluster_benchmark.lua";
+
+ private static Logger logger = LoggerFactory.getLogger(ClusterBenchmarkRunner.class);
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
@Benchmark
+ @BenchmarkMode(Mode.Throughput)
+ @Warmup(iterations = 2)
@Measurement(iterations = 10)
- @OperationsPerInvocation(2)
- public void getSpaceObject(ClusterTarantoolSetup plan, Blackhole bh) {
- TarantoolSpaceOperations> testSpace =
- plan.tarantoolClient.space(TEST_SPACE);
- bh.consume(testSpace);
-
- TarantoolSpaceOperations> profileSpace =
- plan.tarantoolClient.space(TEST_PROFILE);
- bh.consume(profileSpace);
+ @OperationsPerInvocation(2000)
+ public void writeDataUsingCallAPI(ClusterTarantoolSetup plan, FuturesHolder futuresHolder) {
+ // Fill 10000 rows into both spaces
+ TarantoolTuple tarantoolTuple;
+ String uuid;
+ int nextId = 0;
+ for (int i = 0; i < 1_000; i++) {
+ uuid = UUID.randomUUID().toString();
+ nextId = plan.nextTestSpaceId + i;
+ tarantoolTuple = plan.tupleFactory.create(1_000_000 + nextId, null, uuid, 200_000 + nextId);
+ futuresHolder.allFutures.add(plan.tarantoolClient.callForSingleResult(
+ "custom_crud_insert_one_record" , Arrays.asList(TEST_SPACE, tarantoolTuple), Map.class));
+ tarantoolTuple = plan.tupleFactory.create(1_000_000 + nextId, null, uuid, 50_000 + nextId, 100_000 + i);
+ futuresHolder.allFutures.add(plan.tarantoolClient.callForSingleResult(
+ "custom_crud_insert_one_record" , Arrays.asList(TEST_PROFILE, tarantoolTuple), Map.class));
+ }
+ nextId++;
+ plan.nextTestSpaceId = nextId;
+ plan.nextProfileSpaceId = nextId;
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
+ @Warmup(iterations = 2)
@Measurement(iterations = 10)
@OperationsPerInvocation(2000)
- public void writeData(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) {
+ public void writeDataUsingSpaceAPI(
+ ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces) {
// Fill 10000 rows into both spaces
TarantoolTuple tarantoolTuple;
String uuid;
@@ -71,14 +98,18 @@ public void writeData(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, S
@Benchmark
@BenchmarkMode(Mode.Throughput)
+ @Warmup(iterations = 2)
@Measurement(iterations = 10)
@OperationsPerInvocation(1000)
- public void readDataUsingCallAPI(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Blackhole bh) {
- boolean coin = Math.random() - 0.5 > 0;
- String spaceName = coin ? TEST_SPACE : TEST_PROFILE;
+ public void readDataUsingCallAPI(
+ ClusterTarantoolSetup plan, FuturesHolder futuresHolder, ClusterDataInit clusterDataInit) {
+ boolean coin;
+ String spaceName;
long nextId;
for (int i = 0; i < 1_000; i++) {
nextId = Math.round(Math.random() * 10_000) + 1_000_000;
+ coin = Math.random() - 0.5 > 0;
+ spaceName = coin ? TEST_SPACE : TEST_PROFILE;
futuresHolder.allFutures.add(
plan.tarantoolClient.callForSingleResult(
"custom_crud_get_one_record", Arrays.asList(spaceName, nextId), List.class)
@@ -88,17 +119,20 @@ public void readDataUsingCallAPI(ClusterTarantoolSetup plan, FuturesHolder futur
@Benchmark
@BenchmarkMode(Mode.Throughput)
+ @Warmup(iterations = 2)
@Measurement(iterations = 10)
@OperationsPerInvocation(1000)
public void readDataUsingSpaceAPI(
- ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) {
- boolean coin = Math.random() - 0.5 > 0;
- TarantoolSpaceOperations> space = coin ?
- spaces.testSpace : spaces.profileSpace;
- String pkFieldName = coin ? "id" : "profile_id";
+ ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, ClusterDataInit clusterDataInit) {
+ boolean coin;
+ TarantoolSpaceOperations> space;
+ String pkFieldName;
long nextId;
for (int i = 0; i < 1_000; i++) {
nextId = Math.round(Math.random() * 10_000) + 1_000_000;
+ coin = Math.random() - 0.5 > 0;
+ space = coin ? spaces.testSpace : spaces.profileSpace;
+ pkFieldName = coin ? "id" : "profile_id";
futuresHolder.allFutures.add(
space.select(Conditions.indexEquals(pkFieldName, Collections.singletonList(nextId)))
);
@@ -109,14 +143,14 @@ public void readDataUsingSpaceAPI(
public static class FuturesHolder {
final List> allFutures = new ArrayList<>(2_000);
- @Setup(Level.Invocation)
- public void doSetup() {
- allFutures.clear();
- }
-
@TearDown(Level.Invocation)
public void doTeardown() {
- allFutures.forEach(CompletableFuture::join);
+ try {
+ allFutures.forEach(CompletableFuture::join);
+ allFutures.clear();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
}
@@ -131,4 +165,13 @@ public void doSetup(ClusterTarantoolSetup plan) {
profileSpace = plan.tarantoolClient.space(TEST_PROFILE);
}
}
+
+ @State(Scope.Thread)
+ public static class ClusterDataInit {
+
+ @Setup(Level.Iteration)
+ public void doSetup(ClusterTarantoolSetup plan) throws Exception {
+ plan.tarantoolContainer.executeScript(CLUSTER_INIT_SCRIPT);
+ }
+ }
}
diff --git a/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java b/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java
index c1ce5310..39a4d4dc 100644
--- a/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java
+++ b/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java
@@ -37,7 +37,6 @@ public class ClusterTarantoolSetup {
"cartridge-java-test",
"cartridge/instances.yml",
"cartridge/topology.lua")
- .withDirectoryBinding("cartridge")
.withLogConsumer(new Slf4jLogConsumer(logger))
.waitingFor(Wait.forLogMessage(".*Listening HTTP on.*", 5))
.withStartupTimeout(Duration.ofMinutes(2));
@@ -55,8 +54,8 @@ private void initClient() {
new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3303))
)
.withCredentials(tarantoolContainer.getUsername(), tarantoolContainer.getPassword())
- .withConnections(10)
- .withEventLoopThreadsNumber(10)
+ .withConnections(2)
+ .withEventLoopThreadsNumber(2)
.withRequestTimeout(10000)
.withProxyMethodMapping()
.build();
diff --git a/src/test/resources/cartridge/app/roles/api_router.lua b/src/test/resources/cartridge/app/roles/api_router.lua
index f0bdb7e0..c1f5e7e4 100644
--- a/src/test/resources/cartridge/app/roles/api_router.lua
+++ b/src/test/resources/cartridge/app/roles/api_router.lua
@@ -100,6 +100,10 @@ local function custom_crud_get_one_record(space_name, tuple_id)
return crud.get(space_name, {tuple_id}).rows[1]
end
+local function custom_crud_insert_one_record(space_name, tuple)
+ return crud.insert(space_name, tuple)
+end
+
local function raising_error()
error("Test error: raising_error() called")
end
@@ -251,6 +255,7 @@ local function init(opts)
rawset(_G, 'crud_error_timeout', crud_error_timeout)
rawset(_G, 'custom_crud_select', custom_crud_select)
rawset(_G, 'custom_crud_get_one_record', custom_crud_get_one_record)
+ rawset(_G, 'custom_crud_insert_one_record', custom_crud_insert_one_record)
rawset(_G, 'get_routers_status', get_routers_status)
rawset(_G, 'init_router_status', init_router_status)
rawset(_G, 'test_no_such_procedure', test_no_such_procedure)
diff --git a/src/test/resources/org/testcontainers/containers/cluster_benchmark.lua b/src/test/resources/org/testcontainers/containers/cluster_benchmark.lua
new file mode 100644
index 00000000..72da5926
--- /dev/null
+++ b/src/test/resources/org/testcontainers/containers/cluster_benchmark.lua
@@ -0,0 +1,10 @@
+local crud = require('crud')
+local uuid = require('uuid')
+
+crud.truncate('test_space')
+crud.truncate('test__profile')
+
+for i = 1, 10000 do
+ crud.insert('test_space', {1000000 + i, nil, uuid.new(), 200000 + i})
+ crud.insert('test__profile', {1000000 + i, nil, uuid.new(), 50000 + i, 100000 + i})
+end