You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/04/17 00:32:14 UTC
[james-project] 22/39: JAMES-3137 Inject a separate Cassandra
session for cache keyspace
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
commit 505d35385bd8f21bcce2eb1bb6f0e216930b47e7
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Mar 27 11:12:51 2020 +0700
JAMES-3137 Inject a separate Cassandra session for cache keyspace
---
.../init/SessionWithInitializedTablesFactory.java | 36 +++++--
.../init/configuration/InjectionNames.java | 24 +++++
.../james/backends/cassandra/CassandraCluster.java | 2 +-
.../SessionWithInitializedTablesFactoryTest.java | 3 +-
.../modules/mailbox/CassandraSessionModule.java | 26 +++++-
.../java/org/apache/james/CacheSessionTest.java | 103 +++++++++++++++++++++
6 files changed, 185 insertions(+), 9 deletions(-)
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
index 89bcf0d..b3d18f4 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
@@ -23,6 +23,7 @@ import java.util.stream.Stream;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
@@ -30,6 +31,7 @@ import org.apache.james.backends.cassandra.components.CassandraModule;
import org.apache.james.backends.cassandra.components.CassandraTable;
import org.apache.james.backends.cassandra.components.CassandraType;
import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.InjectionNames;
import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
@@ -39,18 +41,25 @@ import com.datastax.driver.core.Session;
@Singleton
public class SessionWithInitializedTablesFactory implements Provider<Session> {
private final CassandraModule module;
+ private final CassandraModule cacheModule;
private final Session session;
+ private final Session cacheSession;
@Inject
- public SessionWithInitializedTablesFactory(ClusterConfiguration clusterConfiguration, Cluster cluster, CassandraModule module) {
+ public SessionWithInitializedTablesFactory(ClusterConfiguration clusterConfiguration,
+ Cluster cluster,
+ CassandraModule module,
+ @Named(InjectionNames.CACHE) CassandraModule cacheModule) {
this.module = module;
+ this.cacheModule = cacheModule;
this.session = createSession(cluster, clusterConfiguration.getKeyspace());
+ this.cacheSession = createCacheSession(cluster, clusterConfiguration.getKeyspace());
}
private Session createSession(Cluster cluster, String keyspace) {
Session session = cluster.connect(keyspace);
try {
- if (allOperationsAreFullyPerformed(session)) {
+ if (allOperationsAreFullyPerformed(session, module)) {
new CassandraSchemaVersionDAO(session)
.updateVersion(CassandraSchemaVersionManager.MAX_VERSION)
.block();
@@ -62,17 +71,28 @@ public class SessionWithInitializedTablesFactory implements Provider<Session> {
}
}
- private boolean allOperationsAreFullyPerformed(Session session) {
- Stream<Boolean> operations = Stream.of(createTypes(session), createTables(session));
+ private Session createCacheSession(Cluster cluster, String keyspace) {
+ Session session = cluster.connect(keyspace);
+ try {
+ allOperationsAreFullyPerformed(session, cacheModule);
+ return session;
+ } catch (Exception e) {
+ session.close();
+ throw e;
+ }
+ }
+
+ private boolean allOperationsAreFullyPerformed(Session session, CassandraModule module) {
+ Stream<Boolean> operations = Stream.of(createTypes(session, module), createTables(session, module));
return operations.allMatch(updated -> updated);
}
- private boolean createTypes(Session session) {
+ private boolean createTypes(Session session, CassandraModule module) {
return new CassandraTypesCreator(module, session)
.initializeTypes() == CassandraType.InitializationStatus.FULL;
}
- private boolean createTables(Session session) {
+ private boolean createTables(Session session, CassandraModule module) {
return new CassandraTableManager(module, session)
.initializeTables() == CassandraTable.InitializationStatus.FULL;
}
@@ -82,6 +102,10 @@ public class SessionWithInitializedTablesFactory implements Provider<Session> {
return session;
}
+ public Session getCacheSession() {
+ return cacheSession;
+ }
+
@PreDestroy
public synchronized void destroy() {
session.close();
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/InjectionNames.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/InjectionNames.java
new file mode 100644
index 0000000..482b707
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/InjectionNames.java
@@ -0,0 +1,24 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.backends.cassandra.init.configuration;
+
+public interface InjectionNames {
+ String CACHE = "cache";
+}
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
index 91c61ad..3be615e 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
@@ -61,7 +61,7 @@ public final class CassandraCluster implements AutoCloseable {
.build();
this.nonPrivilegedCluster = ClusterFactory.create(configuration);
this.nonPrivilegedSession = new TestingSession(new SessionWithInitializedTablesFactory(configuration,
- nonPrivilegedCluster, module).get());
+ nonPrivilegedCluster, module, CassandraModule.EMPTY_MODULE).get());
this.typesProvider = new CassandraTypesProvider(module, nonPrivilegedSession);
}
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 817fe85..c971fea 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
@@ -126,7 +126,8 @@ class SessionWithInitializedTablesFactoryTest {
return () -> new SessionWithInitializedTablesFactory(
clusterConfiguration,
cluster,
- MODULE)
+ MODULE,
+ CassandraModule.EMPTY_MODULE)
.get();
}
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
index 7f097b3..dcf3842 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
@@ -29,6 +29,7 @@ import org.apache.james.backends.cassandra.init.ResilientClusterProvider;
import org.apache.james.backends.cassandra.init.SessionWithInitializedTablesFactory;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.InjectionNames;
import org.apache.james.backends.cassandra.utils.CassandraHealthCheck;
import org.apache.james.backends.cassandra.utils.CassandraUtils;
import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
@@ -52,6 +53,8 @@ import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
public class CassandraSessionModule extends AbstractModule {
@@ -65,13 +68,14 @@ public class CassandraSessionModule extends AbstractModule {
@Override
protected void configure() {
bind(CassandraUtils.class).in(Scopes.SINGLETON);
- bind(Session.class).toProvider(SessionWithInitializedTablesFactory.class);
bind(Cluster.class).toProvider(ResilientClusterProvider.class);
Multibinder<CassandraModule> cassandraDataDefinitions = Multibinder.newSetBinder(binder(), CassandraModule.class);
cassandraDataDefinitions.addBinding().toInstance(CassandraZonedDateTimeModule.MODULE);
cassandraDataDefinitions.addBinding().toInstance(CassandraSchemaVersionModule.MODULE);
+ Multibinder.newSetBinder(binder(), CassandraModule.class, Names.named(InjectionNames.CACHE));
+
bind(CassandraSchemaVersionManager.class).in(Scopes.SINGLETON);
bind(CassandraSchemaVersionDAO.class).in(Scopes.SINGLETON);
@@ -85,10 +89,30 @@ public class CassandraSessionModule extends AbstractModule {
@Provides
@Singleton
+ Session provideSession(SessionWithInitializedTablesFactory sessionFactory) {
+ return sessionFactory.get();
+ }
+
+ @Named(InjectionNames.CACHE)
+ @Provides
+ @Singleton
+ Session provideCacheSession(SessionWithInitializedTablesFactory sessionFactory) {
+ return sessionFactory.getCacheSession();
+ }
+
+ @Provides
+ @Singleton
CassandraModule composeDataDefinitions(Set<CassandraModule> modules) {
return CassandraModule.aggregateModules(modules);
}
+ @Named(InjectionNames.CACHE)
+ @Provides
+ @Singleton
+ CassandraModule composeCacheDefinitions(@Named(InjectionNames.CACHE) Set<CassandraModule> modules) {
+ return CassandraModule.aggregateModules(modules);
+ }
+
@Provides
@Singleton
BatchSizes getBatchSizesConfiguration(PropertiesProvider propertiesProvider) {
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CacheSessionTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CacheSessionTest.java
new file mode 100644
index 0000000..ca6f9a7
--- /dev/null
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CacheSessionTest.java
@@ -0,0 +1,103 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static org.apache.james.CassandraJamesServerMain.ALL_BUT_JMX_CASSANDRA_MODULE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.init.configuration.InjectionNames;
+import org.apache.james.lifecycle.api.StartUpCheck;
+import org.apache.james.modules.ConfigurationProbe;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.Session;
+import com.google.inject.Inject;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+
+class CacheSessionTest {
+ private static final String TABLE_NAME = "tablename";
+
+ static class CacheSessionTestCheck implements StartUpCheck {
+ static final String NAME = "CacheSessionTest-check";
+ private final Session cacheSession;
+
+ @Inject
+ CacheSessionTestCheck(@Named(InjectionNames.CACHE) Session cacheSession) {
+ this.cacheSession = cacheSession;
+ }
+
+ @Override
+ public CheckResult check() {
+ try {
+ cacheSession.execute(select().from(TABLE_NAME));
+ return CheckResult.builder()
+ .checkName(NAME)
+ .resultType(ResultType.GOOD)
+ .build();
+ } catch (Exception e) {
+ return CheckResult.builder()
+ .checkName(NAME)
+ .resultType(ResultType.BAD)
+ .description(String.format("%s do not exist", TABLE_NAME))
+ .build();
+ }
+ }
+
+ @Override
+ public String checkName() {
+ return NAME;
+ }
+ }
+
+ @RegisterExtension
+ static JamesServerExtension testExtension = new JamesServerBuilder()
+ .extension(new DockerElasticSearchExtension())
+ .extension(new CassandraExtension())
+ .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
+ .combineWith(ALL_BUT_JMX_CASSANDRA_MODULE)
+ .overrideWith(TestJMAPServerModule.limitToTenMessages()))
+ .overrideServerModule(binder -> Multibinder.newSetBinder(binder, CassandraModule.class, Names.named(InjectionNames.CACHE))
+ .addBinding()
+ .toInstance(CassandraModule.table(TABLE_NAME)
+ .comment("Testing table")
+ .statement(statement -> statement
+ .addPartitionKey("id", DataType.timeuuid())
+ .addClusteringColumn("clustering", DataType.bigint()))
+ .build()))
+ .overrideServerModule(binder -> Multibinder.newSetBinder(binder, StartUpCheck.class)
+ .addBinding()
+ .to(CacheSessionTestCheck.class))
+ .disableAutoStart()
+ .build();
+
+ @Test
+ void cacheTableShouldBeWellCreated(GuiceJamesServer jamesServer) {
+ assertThatCode(jamesServer::start)
+ .doesNotThrowAnyException();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org