You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2022/08/26 01:34:58 UTC
[james-project] branch master updated: [BUILD_TIME] Slightly faster Cassandra startup (#1151)
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new e2811cf0c8 [BUILD_TIME] Slightly faster Cassandra startup (#1151)
e2811cf0c8 is described below
commit e2811cf0c8b5f0fe8bbf178362db97d4a939bfc9
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Fri Aug 26 08:34:53 2022 +0700
[BUILD_TIME] Slightly faster Cassandra startup (#1151)
20% speed up measured locally by:
- Using a single session for all resource creation
- Closing it async
- Creating keyspaces sequentially
- Avoid creating the user twice
- Using a faster check method than container exec
---
.../backends/cassandra/init/ClusterFactory.java | 28 +++++++++++-
.../backends/cassandra/init/KeyspaceFactory.java | 10 ++--
.../backends/cassandra/CassandraWaitStrategy.java | 19 +++++---
.../james/backends/cassandra/DockerCassandra.java | 53 ++++++++++++----------
.../SessionWithInitializedTablesFactoryTest.java | 2 +-
.../mailbox/CassandraCacheSessionModule.java | 2 +-
.../modules/mailbox/CassandraSessionModule.java | 2 +-
7 files changed, 80 insertions(+), 36 deletions(-)
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterFactory.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterFactory.java
index 6637df9815..a9b5a0223f 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterFactory.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterFactory.java
@@ -59,9 +59,35 @@ public class ClusterFactory {
}
}
+ public static CqlSession createWithoutKeyspace(ClusterConfiguration configuration) {
+ Preconditions.checkState(configuration.getUsername().isPresent() == configuration.getPassword().isPresent(), "If you specify username, you must specify password");
+
+ CqlSessionBuilder sessionBuilder = CqlSession.builder();
+
+ configuration.getHosts().forEach(server -> sessionBuilder
+ .addContactPoint(InetSocketAddress.createUnresolved(server.getHostName(), server.getPort())));
+
+
+ configuration.getUsername().ifPresent(username ->
+ configuration.getPassword().ifPresent(password ->
+ sessionBuilder.withAuthCredentials(username, password)));
+
+ sessionBuilder.withLocalDatacenter(configuration.getLocalDC().orElse("datacenter1"));
+
+ CqlSession session = sessionBuilder.build();
+
+ try {
+ ensureContactable(session);
+ return session;
+ } catch (Exception e) {
+ session.close();
+ throw e;
+ }
+ }
+
private static void createKeyspace(KeyspaceConfiguration keyspaceConfiguration, CqlSessionBuilder sessionBuilder) {
CqlSession cqlSession = sessionBuilder.build();
- KeyspaceFactory.createKeyspace(keyspaceConfiguration, cqlSession);
+ KeyspaceFactory.createKeyspace(keyspaceConfiguration, cqlSession).block();
cqlSession.forceCloseAsync();
}
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/KeyspaceFactory.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/KeyspaceFactory.java
index a52029ec77..f14c178b8e 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/KeyspaceFactory.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/KeyspaceFactory.java
@@ -27,18 +27,22 @@ import com.datastax.oss.driver.api.querybuilder.SchemaBuilder;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
+import reactor.core.publisher.Mono;
+
public class KeyspaceFactory {
- public static void createKeyspace(KeyspaceConfiguration configuration, CqlSession session) {
+ public static Mono<Void> createKeyspace(KeyspaceConfiguration configuration, CqlSession session) {
if (!keyspaceExist(session, configuration.getKeyspace())) {
- session.execute(SchemaBuilder.createKeyspace(configuration.getKeyspace())
+ return Mono.from(session.executeReactive(SchemaBuilder.createKeyspace(configuration.getKeyspace())
.ifNotExists()
.withReplicationOptions(ImmutableMap.<String, Object>builder()
.put("class", "SimpleStrategy")
.put("replication_factor", configuration.getReplicationFactor())
.build())
.withDurableWrites(configuration.isDurableWrites())
- .build());
+ .build()))
+ .then();
}
+ return Mono.empty();
}
@VisibleForTesting
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java
index 43d81ae14b..3e56fdf756 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java
@@ -19,10 +19,12 @@
package org.apache.james.backends.cassandra;
-import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
+import org.apache.james.backends.cassandra.init.ClusterFactory;
+import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.util.Host;
import org.rnorth.ducttape.unreliables.Unreliables;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.WaitStrategy;
@@ -49,11 +51,16 @@ public class CassandraWaitStrategy implements WaitStrategy {
public void waitUntilReady(WaitStrategyTarget waitStrategyTarget) {
Unreliables.retryUntilTrue(Ints.checkedCast(timeout.getSeconds()), TimeUnit.SECONDS, () -> {
try {
- return cassandraContainer
- .execInContainer("cqlsh", "-u", "cassandra", "-p", "cassandra", "-e", "show host")
- .getStdout()
- .contains("Connected to Test Cluster");
- } catch (IOException | InterruptedException e) {
+ ClusterFactory.createWithoutKeyspace(ClusterConfiguration.builder()
+ .host(Host.from(cassandraContainer.getContainerIpAddress(), cassandraContainer.getMappedPort(9042)))
+ .username("cassandra")
+ .password("cassandra")
+ .maxRetry(1)
+ .build())
+ .forceCloseAsync();
+
+ return true;
+ } catch (Exception e) {
return false;
}
}
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
index 080119c1ca..a354c5e464 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
@@ -20,7 +20,6 @@
package org.apache.james.backends.cassandra;
import java.io.Closeable;
-import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
@@ -45,6 +44,9 @@ import com.github.dockerjava.api.model.Event;
import com.github.dockerjava.api.model.EventType;
import com.google.common.collect.ImmutableMap;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
public class DockerCassandra {
/**
@@ -54,35 +56,34 @@ public class DockerCassandra {
* This process is done by using the default user provided by docker cassandra, it has the capability of creating roles,
* keyspaces, and granting permissions to those entities.
*/
- public static class CassandraResourcesManager {
-
+ public static class CassandraResourcesManager implements Closeable {
private static final String CASSANDRA_SUPER_USER = "cassandra";
private static final String CASSANDRA_SUPER_USER_PASSWORD = "cassandra";
- private final DockerCassandra cassandra;
+ private final CqlSession privilegedCluster;
private CassandraResourcesManager(DockerCassandra cassandra) {
- this.cassandra = cassandra;
+ privilegedCluster = ClusterFactory.createWithoutKeyspace(cassandra.superUserConfigurationBuilder().build());
}
- public void initializeKeyspace(KeyspaceConfiguration configuration) {
- try (CqlSession privilegedCluster = ClusterFactory.create(cassandra.superUserConfigurationBuilder().build(), configuration)) {
- KeyspaceFactory.createKeyspace(configuration, privilegedCluster);
- provisionNonPrivilegedUser(privilegedCluster);
- grantPermissionToTestingUser(privilegedCluster, configuration.getKeyspace());
- }
+ @Override
+ public void close() {
+ privilegedCluster.closeAsync();
}
- private void provisionNonPrivilegedUser(CqlSession privilegedCluster) {
- privilegedCluster.execute("CREATE ROLE IF NOT EXISTS " + CASSANDRA_TESTING_USER + " WITH PASSWORD = '" + CASSANDRA_TESTING_PASSWORD + "' AND LOGIN = true");
+ public Mono<Void> initializeKeyspace(KeyspaceConfiguration configuration) {
+ return KeyspaceFactory.createKeyspace(configuration, privilegedCluster)
+ .then(grantPermissionToTestingUser(configuration.getKeyspace()));
}
- private void grantPermissionToTestingUser(CqlSession privilegedCluster, String keyspace) {
- privilegedCluster.execute("GRANT CREATE ON KEYSPACE " + keyspace + " TO " + CASSANDRA_TESTING_USER);
- privilegedCluster.execute("GRANT SELECT ON KEYSPACE " + keyspace + " TO " + CASSANDRA_TESTING_USER);
- privilegedCluster.execute("GRANT MODIFY ON KEYSPACE " + keyspace + " TO " + CASSANDRA_TESTING_USER);
- // some tests require dropping in setups
- privilegedCluster.execute("GRANT DROP ON KEYSPACE " + keyspace + " TO " + CASSANDRA_TESTING_USER);
+ public Mono<Void> provisionNonPrivilegedUser() {
+ return Mono.from(privilegedCluster.executeReactive("CREATE ROLE IF NOT EXISTS " + CASSANDRA_TESTING_USER + " WITH PASSWORD = '" + CASSANDRA_TESTING_PASSWORD + "' AND LOGIN = true"))
+ .then();
+ }
+
+ private Mono<Void> grantPermissionToTestingUser(String keyspace) {
+ return Mono.from(privilegedCluster.executeReactive("GRANT ALL PERMISSIONS ON KEYSPACE " + keyspace + " TO " + CASSANDRA_TESTING_USER))
+ .then();
}
}
@@ -151,7 +152,7 @@ public class DockerCassandra {
@Override
public void onError(Throwable throwable) {
- logger.error("event stream failure",throwable);
+ logger.error("event stream failure", throwable);
}
@Override
@@ -159,7 +160,7 @@ public class DockerCassandra {
}
@Override
- public void close() throws IOException {
+ public void close() {
}
});
boolean doNotDeleteImageAfterUsage = false;
@@ -194,8 +195,14 @@ public class DockerCassandra {
public void start() {
if (!cassandraContainer.isRunning()) {
cassandraContainer.start();
- administrator().initializeKeyspace(mainKeyspaceConfiguration());
- administrator().initializeKeyspace(cacheKeyspaceConfiguration());
+ try (CassandraResourcesManager resourcesManager = administrator()) {
+ resourcesManager.provisionNonPrivilegedUser()
+ .then(Flux.merge(
+ resourcesManager.initializeKeyspace(mainKeyspaceConfiguration()),
+ resourcesManager.initializeKeyspace(cacheKeyspaceConfiguration()))
+ .then())
+ .block();
+ }
}
}
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
index b79c2dbc22..3c61094061 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
@@ -129,7 +129,7 @@ class SessionWithInitializedTablesFactoryTest {
.build();
KeyspaceConfiguration keyspaceConfiguration = DockerCassandra.mainKeyspaceConfiguration();
CqlSession cluster = ClusterFactory.create(clusterConfiguration, keyspaceConfiguration);
- KeyspaceFactory.createKeyspace(keyspaceConfiguration, cluster);
+ KeyspaceFactory.createKeyspace(keyspaceConfiguration, cluster).block();
return () -> new SessionWithInitializedTablesFactory( cluster, MODULE).get();
}
diff --git a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraCacheSessionModule.java b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraCacheSessionModule.java
index 027d7b5c83..7d3cc250f3 100644
--- a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraCacheSessionModule.java
+++ b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraCacheSessionModule.java
@@ -76,7 +76,7 @@ public class CassandraCacheSessionModule extends AbstractModule {
this.cluster = cluster;
if (clusterConfiguration.shouldCreateKeyspace()) {
- KeyspaceFactory.createKeyspace(keyspacesConfiguration.cacheKeyspaceConfiguration(), cluster);
+ KeyspaceFactory.createKeyspace(keyspacesConfiguration.cacheKeyspaceConfiguration(), cluster).block();
}
}
}
diff --git a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
index c33be3c8b6..38bbc6dce8 100644
--- a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
+++ b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
@@ -166,7 +166,7 @@ public class CassandraSessionModule extends AbstractModule {
this.cluster = sessionProvider.get();
if (clusterConfiguration.shouldCreateKeyspace()) {
- KeyspaceFactory.createKeyspace(keyspacesConfiguration.mainKeyspaceConfiguration(), cluster);
+ KeyspaceFactory.createKeyspace(keyspacesConfiguration.mainKeyspaceConfiguration(), cluster).block();
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org