From d6dec1e5d0425ab6fb8be233249c1be2ccfa1091 Mon Sep 17 00:00:00 2001 From: Benoit TELLIER Date: Wed, 25 Feb 2026 14:35:56 +0100 Subject: [PATCH 1/2] JAMES-4177 Finner grain management of Cassandra profiles --- .../CassandraQuotaCurrentValueDao.java | 25 +++++--- .../components/CassandraQuotaLimitDao.java | 18 ++++-- .../cassandra/utils/ProfileLocator.java | 56 ++++++++++++++++++ .../src/test/resources/cassandra-driver.conf | 29 ++++++++- .../distributed/configure/cassandra.adoc | 57 +++++++++++++++++- .../cassandra/mail/CassandraACLDAOV2.java | 21 +++++-- .../mail/CassandraApplicableFlagDAO.java | 15 ++++- .../mail/CassandraAttachmentDAOV2.java | 16 ++++- .../mail/CassandraDeletedMessageDAO.java | 36 +++++++---- .../mail/CassandraFirstUnseenDAO.java | 39 ++++++++---- .../mail/CassandraMailboxCounterDAO.java | 39 ++++++------ .../cassandra/mail/CassandraMailboxDAO.java | 21 +++++-- .../mail/CassandraMailboxPathV3DAO.java | 9 ++- .../mail/CassandraMailboxRecentsDAO.java | 6 ++ .../cassandra/mail/CassandraMessageDAOV3.java | 33 +++++++++-- .../cassandra/mail/CassandraMessageIdDAO.java | 47 +++++++++++---- .../mail/CassandraMessageIdToImapUidDAO.java | 59 ++++--------------- .../mail/CassandraModSeqProvider.java | 13 +++- .../cassandra/mail/CassandraThreadDAO.java | 17 +++++- .../mail/CassandraThreadLookupDAO.java | 20 +++++-- .../cassandra/mail/CassandraUidProvider.java | 13 +++- .../mail/CassandraUserMailboxRightsDAO.java | 19 ++++-- .../CassandraMailboxManagerTest.java | 3 +- .../mail/CassandraMessageDAOV3Test.java | 4 +- .../cassandra-driver.conf | 8 ++- .../cassandra/CassandraDomainList.java | 21 +++++-- .../CassandraMappingsSourcesDAO.java | 15 ++++- .../CassandraRecipientRewriteTableDAO.java | 15 ++++- .../user/cassandra/CassandraUsersDAO.java | 55 ++++++++++++----- .../CassandraNotificationRegistryDAO.java | 15 ++++- .../cassandra/CassandraVacationDAO.java | 13 +++- .../CassandraPushSubscriptionDAO.java | 17 ++++-- ...MetaDataFixInconsistenciesServiceTest.java | 3 +- ...3MetaDataFixInconsistenciesRoutesTest.java | 3 +- 34 files changed, 583 insertions(+), 197 deletions(-) create mode 100644 backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/ProfileLocator.java diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java index aec997b27b4..21e7411ef6b 100644 --- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java +++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java @@ -33,6 +33,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.quota.QuotaComponent; import org.apache.james.core.quota.QuotaCurrentValue; import org.apache.james.core.quota.QuotaType; @@ -42,6 +43,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.delete.Delete; import com.datastax.oss.driver.api.querybuilder.select.Select; import com.datastax.oss.driver.api.querybuilder.update.Update; @@ -59,6 +61,8 @@ public class CassandraQuotaCurrentValueDao { private final PreparedStatement getQuotaCurrentValueStatement; private final PreparedStatement getQuotasByComponentStatement; private final PreparedStatement deleteQuotaCurrentValueStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraQuotaCurrentValueDao(CqlSession session) { @@ -68,6 +72,8 @@ public CassandraQuotaCurrentValueDao(CqlSession session) { this.getQuotaCurrentValueStatement = session.prepare(getQuotaCurrentValueStatement().build()); this.getQuotasByComponentStatement = session.prepare(getQuotasByComponentStatement().build()); this.deleteQuotaCurrentValueStatement = session.prepare(deleteQuotaCurrentValueStatement().build()); + this.readProfile = ProfileLocator.READ.locateProfile(session, "CURRENT-QUOTA"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "CURRENT-QUOTA"); } public Mono increase(QuotaCurrentValue.Key quotaKey, long amount) { @@ -75,7 +81,8 @@ public Mono increase(QuotaCurrentValue.Key quotaKey, long amount) { .setString(QUOTA_COMPONENT, quotaKey.getQuotaComponent().getValue()) .setString(IDENTIFIER, quotaKey.getIdentifier()) .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue()) - .setLong(CURRENT_VALUE, amount)) + .setLong(CURRENT_VALUE, amount) + .setExecutionProfile(writeProfile)) .onErrorResume(ex -> { LOGGER.warn("Failure when increasing {} {} quota for {}. Quota current value is thus not updated and needs recomputation", quotaKey.getQuotaComponent().getValue(), quotaKey.getQuotaType().getValue(), quotaKey.getIdentifier(), ex); @@ -88,7 +95,8 @@ public Mono decrease(QuotaCurrentValue.Key quotaKey, long amount) { .setString(QUOTA_COMPONENT, quotaKey.getQuotaComponent().getValue()) .setString(IDENTIFIER, quotaKey.getIdentifier()) .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue()) - .setLong(CURRENT_VALUE, amount)) + .setLong(CURRENT_VALUE, amount) + .setExecutionProfile(writeProfile)) .onErrorResume(ex -> { LOGGER.warn("Failure when decreasing {} {} quota for {}. Quota current value is thus not updated and needs recomputation", quotaKey.getQuotaComponent().getValue(), quotaKey.getQuotaType().getValue(), quotaKey.getIdentifier(), ex); @@ -100,22 +108,25 @@ public Mono getQuotaCurrentValue(QuotaCurrentValue.Key quotaK return queryExecutor.executeSingleRow(getQuotaCurrentValueStatement.bind() .setString(QUOTA_COMPONENT, quotaKey.getQuotaComponent().getValue()) .setString(IDENTIFIER, quotaKey.getIdentifier()) - .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue())) - .map(row -> convertRowToModel(row)); + .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue()) + .setExecutionProfile(readProfile)) + .map(this::convertRowToModel); } public Mono deleteQuotaCurrentValue(QuotaCurrentValue.Key quotaKey) { return queryExecutor.executeVoid(deleteQuotaCurrentValueStatement.bind() .setString(QUOTA_COMPONENT, quotaKey.getQuotaComponent().getValue()) .setString(IDENTIFIER, quotaKey.getIdentifier()) - .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue())); + .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue()) + .setExecutionProfile(writeProfile)); } public Flux getQuotasByComponent(QuotaComponent quotaComponent, String identifier) { return queryExecutor.executeRows(getQuotasByComponentStatement.bind() .setString(QUOTA_COMPONENT, quotaComponent.getValue()) - .setString(IDENTIFIER, identifier)) - .map(row -> convertRowToModel(row)); + .setString(IDENTIFIER, identifier) + .setExecutionProfile(readProfile)) + .map(this::convertRowToModel); } private Update increaseStatement() { diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java index 2b3090a6403..d031f90bc2d 100644 --- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java +++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java @@ -34,6 +34,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.quota.QuotaComponent; import org.apache.james.core.quota.QuotaLimit; import org.apache.james.core.quota.QuotaScope; @@ -42,6 +43,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.delete.Delete; import com.datastax.oss.driver.api.querybuilder.insert.Insert; import com.datastax.oss.driver.api.querybuilder.select.Select; @@ -55,6 +57,8 @@ public class CassandraQuotaLimitDao { private final PreparedStatement getQuotaLimitsStatement; private final PreparedStatement setQuotaLimitStatement; private final PreparedStatement deleteQuotaLimitStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraQuotaLimitDao(CqlSession session) { @@ -63,6 +67,8 @@ public CassandraQuotaLimitDao(CqlSession session) { this.getQuotaLimitsStatement = session.prepare(getQuotaLimitsStatement().build()); this.setQuotaLimitStatement = session.prepare(setQuotaLimitStatement().build()); this.deleteQuotaLimitStatement = session.prepare((deleteQuotaLimitStatement().build())); + this.readProfile = ProfileLocator.READ.locateProfile(session, "QUOTA-LIMITS"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "QUOTA-LIMITS"); } public Mono getQuotaLimit(QuotaLimit.QuotaLimitKey quotaKey) { @@ -70,7 +76,8 @@ public Mono getQuotaLimit(QuotaLimit.QuotaLimitKey quotaKey) { .setString(QUOTA_COMPONENT, quotaKey.getQuotaComponent().getValue()) .setString(QUOTA_SCOPE, quotaKey.getQuotaScope().getValue()) .setString(IDENTIFIER, quotaKey.getIdentifier()) - .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue())) + .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue()) + .setExecutionProfile(readProfile)) .map(this::convertRowToModel); } @@ -78,7 +85,8 @@ public Flux getQuotaLimits(QuotaComponent quotaComponent, QuotaScope return queryExecutor.executeRows(getQuotaLimitsStatement.bind() .setString(QUOTA_COMPONENT, quotaComponent.getValue()) .setString(QUOTA_SCOPE, quotaScope.getValue()) - .setString(IDENTIFIER, identifier)) + .setString(IDENTIFIER, identifier) + .setExecutionProfile(readProfile)) .map(this::convertRowToModel); } @@ -88,7 +96,8 @@ public Mono setQuotaLimit(QuotaLimit quotaLimit) { .setString(QUOTA_SCOPE, quotaLimit.getQuotaScope().getValue()) .setString(IDENTIFIER, quotaLimit.getIdentifier()) .setString(QUOTA_TYPE, quotaLimit.getQuotaType().getValue()) - .set(QUOTA_LIMIT, quotaLimit.getQuotaLimit().orElse(null), Long.class)); + .set(QUOTA_LIMIT, quotaLimit.getQuotaLimit().orElse(null), Long.class) + .setExecutionProfile(writeProfile)); } public Mono deleteQuotaLimit(QuotaLimit.QuotaLimitKey quotaKey) { @@ -96,7 +105,8 @@ public Mono deleteQuotaLimit(QuotaLimit.QuotaLimitKey quotaKey) { .setString(QUOTA_COMPONENT, quotaKey.getQuotaComponent().getValue()) .setString(QUOTA_SCOPE, quotaKey.getQuotaScope().getValue()) .setString(IDENTIFIER, quotaKey.getIdentifier()) - .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue())); + .setString(QUOTA_TYPE, quotaKey.getQuotaType().getValue()) + .setExecutionProfile(writeProfile)); } private Select getQuotaLimitStatement() { diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/ProfileLocator.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/ProfileLocator.java new file mode 100644 index 00000000000..747b2a0a0a7 --- /dev/null +++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/ProfileLocator.java @@ -0,0 +1,56 @@ +/**************************************************************** + * 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.utils; + +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverConfig; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; + +public enum ProfileLocator { + READ(profileLocatorFunction("READ")), + WRITE(profileLocatorFunction("WRITE")); + + private static BiFunction profileLocatorFunction(String baseProfileName) { + return (session, daoName) -> { + DriverConfig config = session.getContext().getConfig(); + Map profiles = config.getProfiles(); + String profileName = baseProfileName + "-" + daoName; + + return Optional.ofNullable(profiles.get(profileName)) + .map(DriverExecutionProfile.class::cast) + .or(() -> Optional.ofNullable(profiles.get(baseProfileName))) + .orElseGet(config::getDefaultProfile); + }; + } + + private final BiFunction profileLocatorFunction; + + ProfileLocator(BiFunction profileLocatorFunction) { + this.profileLocatorFunction = profileLocatorFunction; + } + + public DriverExecutionProfile locateProfile(CqlSession session, String daoName) { + return profileLocatorFunction.apply(session, daoName); + } +} diff --git a/backends-common/cassandra/src/test/resources/cassandra-driver.conf b/backends-common/cassandra/src/test/resources/cassandra-driver.conf index 09e228b6699..fff72656e90 100644 --- a/backends-common/cassandra/src/test/resources/cassandra-driver.conf +++ b/backends-common/cassandra/src/test/resources/cassandra-driver.conf @@ -1,5 +1,28 @@ datastax-java-driver { - basic.request { - timeout = 5 seconds - } + basic.request { + timeout = 5 seconds + consistency = QUORUM + page-size = 5000 + serial-consistency = SERIAL + } + profiles { + # Provides controls on Execution profiles used by James + LWT { + basic.request.consistency = SERIAL + basic.request.serial-consistency = SERIAL + } + READ { + basic.request.consistency = QUORUM + } + WRITE { + basic.request.consistency = QUORUM + } + OPTIMISTIC_CONSISTENCY_LEVEL { + basic.request.consistency = LOCAL_ONE + basic.request.serial-consistency = LOCAL_ONE + } + BATCH { + basic.request.timeout = 1 hour + } + } } diff --git a/docs/modules/servers/pages/distributed/configure/cassandra.adoc b/docs/modules/servers/pages/distributed/configure/cassandra.adoc index a953ece3043..9821b4d0cca 100644 --- a/docs/modules/servers/pages/distributed/configure/cassandra.adoc +++ b/docs/modules/servers/pages/distributed/configure/cassandra.adoc @@ -162,4 +162,59 @@ features to your users, you can consider disabling them in order to improve perf | Optional, default to 0. Defensive value to add to uids and modseqs generated. This can be used as an heuristic to maintain consistency even when consensus of Lightweight Transactions is broken, exemple during a disaster recovery process. -|=== \ No newline at end of file +|=== + +== Extra execution profiles + +Operators can specify fin grain execution profiles. This allows setting per-dao request settings - like consistency levels. + +DAO would try to select at start time the most specific profile and fallback to `READ` and `WRITE` profiles. + +Profiles include: + + - READ-ACLV2 + - WRITE-ACLV2 + - READ-APPLICABLE-FLAGS + - WRITE-APPLICABLE-FLAGS + - READ-ATTACHMENTV2 + - WRITE-ATTACHMENTV2 + - READ-MAILBOX + - WRITE-MAILBOX + - READ-MAILBOXPATHV3 + - WRITE-MAILBOXPATHV3 + - READ-THREAD + - WRITE-THREAD + - READ-THREAD-LOOKUP + - WRITE-THREAD-LOOKUP + - READ-UID (only used for IMAP STATUS/SELECT) + - READ-MODSEQ (only used for IMAP STATUS/SELECT) + - READ-MESSAGEV3 + - WRITE-MESSAGEV3 + - READ-RECENTS + - WRITE-RECENTS + - READ-IMAP-UID-TABLE + - WRITE-IMAP-UID-TABLE + - READ-FIRST-UNSEEN + - WRITE-FIRST-UNSEEN + - READ-MARKED-AS-DELETED + - WRITE-MARKED-AS-DELETED + - READ-VACATION + - WRITE-VACATION + - READ-VACATION-REGISTRY + - WRITE-VACATION-REGISTRY + - READ-USER + - WRITE-USER + - READ-RRT + - WRITE-RRT + - READ-RRT-SOURCE + - WRITE-RRT-SOURCE + - READ-DOMAIN + - WRITE-DOMAIN + - READ-CURRENT-QUOTA + - WRITE-CURRENT-QUOTA + - READ-QUOTA-LIMITS + - WRITE-QUOTA-LIMITS + - READ-PUSH-SUBSCRIPTION + - WRITE-PUSH-SUBSCRIPTION + - READ-USER-ACL + - WRITE-USER-ACL diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java index 71ee33537fc..3522279dd38 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java @@ -29,12 +29,14 @@ import org.apache.commons.lang3.NotImplementedException; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.cassandra.table.CassandraACLV2Table; import org.apache.james.mailbox.model.MailboxACL; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.github.fge.lambdas.Throwing; import com.google.common.collect.ImmutableMap; @@ -49,10 +51,14 @@ public class CassandraACLDAOV2 { private final PreparedStatement replaceRights; private final PreparedStatement delete; private final PreparedStatement read; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraACLDAOV2(CqlSession session) { this.executor = new CassandraAsyncExecutor(session); + this.readProfile = ProfileLocator.READ.locateProfile(session, "ACLV2"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "ACLV2"); this.insertRights = prepareInsertRights(session); this.removeRights = prepareRemoveRights(session); this.replaceRights = prepareReplaceRights(session); @@ -100,13 +106,15 @@ private PreparedStatement prepareRead(CqlSession session) { public Mono delete(CassandraId cassandraId) { return executor.executeVoid( delete.bind() - .setUuid(CassandraACLV2Table.ID, cassandraId.asUuid())); + .setUuid(CassandraACLV2Table.ID, cassandraId.asUuid()) + .setExecutionProfile(writeProfile)); } public Mono getACL(CassandraId cassandraId) { return executor.executeRows( read.bind() - .set(CassandraACLV2Table.ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID)) + .set(CassandraACLV2Table.ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .map(Throwing.function(row -> { MailboxACL.EntryKey entryKey = MailboxACL.EntryKey.deserialize(row.getString(CassandraACLV2Table.KEY)); MailboxACL.Rfc4314Rights rights = row.getSet(CassandraACLV2Table.RIGHTS, String.class) @@ -125,17 +133,20 @@ public Mono updateACL(CassandraId cassandraId, MailboxACL.ACLCommand comma return executor.executeVoid(insertRights.bind() .setUuid(CassandraACLV2Table.ID, cassandraId.asUuid()) .setString(CassandraACLV2Table.KEY, command.getEntryKey().serialize()) - .setSet(CassandraACLV2Table.RIGHTS, ImmutableSet.copyOf(rightStrings), String.class)); + .setSet(CassandraACLV2Table.RIGHTS, ImmutableSet.copyOf(rightStrings), String.class) + .setExecutionProfile(writeProfile)); case REMOVE: return executor.executeVoid(removeRights.bind() .setUuid(CassandraACLV2Table.ID, cassandraId.asUuid()) .setString(CassandraACLV2Table.KEY, command.getEntryKey().serialize()) - .setSet(CassandraACLV2Table.RIGHTS, ImmutableSet.copyOf(rightStrings), String.class)); + .setSet(CassandraACLV2Table.RIGHTS, ImmutableSet.copyOf(rightStrings), String.class) + .setExecutionProfile(writeProfile)); case REPLACE: return executor.executeVoid(replaceRights.bind() .setUuid(CassandraACLV2Table.ID, cassandraId.asUuid()) .setString(CassandraACLV2Table.KEY, command.getEntryKey().serialize()) - .setSet(CassandraACLV2Table.RIGHTS, rightStrings, String.class)); + .setSet(CassandraACLV2Table.RIGHTS, rightStrings, String.class) + .setExecutionProfile(writeProfile)); default: throw new NotImplementedException(command.getEditMode() + "is not supported"); } diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java index 419652a9a9f..c5957d3274a 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java @@ -33,11 +33,13 @@ import jakarta.mail.Flags; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.cassandra.table.Flag; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import reactor.core.publisher.Mono; @@ -47,6 +49,8 @@ public class CassandraApplicableFlagDAO { private final PreparedStatement select; private final PreparedStatement update; private final PreparedStatement delete; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraApplicableFlagDAO(CqlSession session) { @@ -54,6 +58,8 @@ public CassandraApplicableFlagDAO(CqlSession session) { this.select = prepareSelect(session); this.delete = prepareDelete(session); this.update = prepareUpdate(session); + this.readProfile = ProfileLocator.READ.locateProfile(session, "APPLICABLE-FLAGS"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "APPLICABLE-FLAGS"); } private PreparedStatement prepareSelect(CqlSession session) { @@ -79,13 +85,15 @@ private PreparedStatement prepareUpdate(CqlSession session) { public Mono delete(CassandraId mailboxId) { return cassandraAsyncExecutor.executeVoid( delete.bind() - .setUuid(MAILBOX_ID, mailboxId.asUuid())); + .setUuid(MAILBOX_ID, mailboxId.asUuid()) + .setExecutionProfile(writeProfile)); } public Mono retrieveApplicableFlag(CassandraId mailboxId) { return cassandraAsyncExecutor.executeSingleRow( select.bind() - .setUuid(MAILBOX_ID, mailboxId.asUuid())) + .setUuid(MAILBOX_ID, mailboxId.asUuid()) + .setExecutionProfile(readProfile)) .map(FlagsExtractor::getApplicableFlags); } @@ -95,6 +103,7 @@ public Mono updateApplicableFlags(CassandraId cassandraId, Set toB } return cassandraAsyncExecutor.executeVoid(update.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setSet(USER_FLAGS, toBeAdded, String.class)); + .setSet(USER_FLAGS, toBeAdded, String.class) + .setExecutionProfile(writeProfile)); } } diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java index 2a1b9f0e27c..3ab32e82218 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java @@ -40,6 +40,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.blob.api.BlobId; import org.apache.james.mailbox.cassandra.ids.CassandraMessageId; import org.apache.james.mailbox.model.AttachmentId; @@ -52,6 +53,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; import com.google.common.base.Preconditions; @@ -153,6 +155,8 @@ private static DAOAttachment fromRow(Row row, BlobId.Factory blobIfFactory) { private final PreparedStatement selectStatement; private final PreparedStatement listBlobs; private final CqlSession session; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraAttachmentDAOV2(BlobId.Factory blobIdFactory, CqlSession session) { @@ -163,6 +167,9 @@ public CassandraAttachmentDAOV2(BlobId.Factory blobIdFactory, CqlSession session this.insertStatement = prepareInsert(); this.deleteStatement = prepareDelete(); this.listBlobs = prepareSelectBlobs(); + + this.readProfile = ProfileLocator.READ.locateProfile(session, "ATTACHMENTV2"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "ATTACHMENTV2"); } private PreparedStatement prepareSelectBlobs() { @@ -203,7 +210,8 @@ public Mono getAttachment(AttachmentId attachmentId) { Preconditions.checkArgument(attachmentId != null); return cassandraAsyncExecutor.executeSingleRow( selectStatement.bind() - .setUuid(ID_AS_UUID, attachmentId.asUUID())) + .setUuid(ID_AS_UUID, attachmentId.asUUID()) + .setExecutionProfile(readProfile)) .map(row -> CassandraAttachmentDAOV2.fromRow(row, blobIdFactory)); } @@ -216,13 +224,15 @@ public Mono storeAttachment(DAOAttachment attachment) { .setLong(SIZE, attachment.getSize()) .setUuid(MESSAGE_ID, messageId.get()) .setString(TYPE, attachment.getType().asString()) - .setString(BLOB_ID, attachment.getBlobId().asString())); + .setString(BLOB_ID, attachment.getBlobId().asString()) + .setExecutionProfile(writeProfile)); } public Mono delete(AttachmentId attachmentId) { return cassandraAsyncExecutor.executeVoid( deleteStatement.bind() - .setUuid(ID_AS_UUID, attachmentId.asUUID())); + .setUuid(ID_AS_UUID, attachmentId.asUUID()) + .setExecutionProfile(writeProfile)); } public Flux listBlobs() { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java index f440596c523..4316df72ec4 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java @@ -34,6 +34,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.model.MessageRange; @@ -45,6 +46,7 @@ import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.google.common.collect.Lists; @@ -66,6 +68,8 @@ public class CassandraDeletedMessageDAO { private final PreparedStatement selectBetweenUidStatement; private final PreparedStatement selectFromUidStatement; private final ProtocolVersion protocolVersion; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraDeletedMessageDAO(CqlSession session) { @@ -78,6 +82,8 @@ public CassandraDeletedMessageDAO(CqlSession session) { this.selectBetweenUidStatement = prepareBetweenUidStatement(session); this.selectFromUidStatement = prepareFromUidStatement(session); this.protocolVersion = session.getContext().getProtocolVersion(); + this.readProfile = ProfileLocator.READ.locateProfile(session, "MARKED_AS_DELETED"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "MARKED_AS_DELETED"); } private PreparedStatement prepareAllUidStatement(CqlSession session) { @@ -136,7 +142,8 @@ public Mono addDeleted(CassandraId cassandraId, MessageUid uid) { return cassandraAsyncExecutor.executeVoid( addStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uid.asLong())); + .setLong(UID, uid.asLong()) + .setExecutionProfile(writeProfile)); } public Mono addDeleted(CassandraId cassandraId, List uids) { @@ -144,7 +151,8 @@ public Mono addDeleted(CassandraId cassandraId, List uids) { return cassandraAsyncExecutor.executeVoid( addStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uids.iterator().next().asLong())); + .setLong(UID, uids.iterator().next().asLong()) + .setExecutionProfile(writeProfile)); } else { Stream batches = Lists.partition(uids, BATCH_STATEMENT_WINDOW) .stream() @@ -164,14 +172,16 @@ public Mono addDeleted(CassandraId cassandraId, List uids) { public Mono removeDeleted(CassandraId cassandraId, MessageUid uid) { return cassandraAsyncExecutor.executeVoid(deleteStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uid.asLong())); + .setLong(UID, uid.asLong()) + .setExecutionProfile(writeProfile)); } public Mono removeDeleted(CassandraId cassandraId, List uids) { if (uids.size() == 1) { return cassandraAsyncExecutor.executeVoid(deleteStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uids.iterator().next().asLong())); + .setLong(UID, uids.iterator().next().asLong()) + .setExecutionProfile(writeProfile)); } else { Stream batches = Lists.partition(uids, BATCH_STATEMENT_WINDOW) .stream() @@ -179,7 +189,8 @@ public Mono removeDeleted(CassandraId cassandraId, List uids) BatchStatementBuilder batch = new BatchStatementBuilder(BatchType.UNLOGGED); uidBatch.forEach(uid -> batch.addStatement(deleteStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uid.asLong()))); + .setLong(UID, uid.asLong())) + .setExecutionProfile(writeProfile)); return batch.build(); }); return Flux.fromStream(batches) @@ -190,7 +201,8 @@ public Mono removeDeleted(CassandraId cassandraId, List uids) public Mono removeAll(CassandraId cassandraId) { return cassandraAsyncExecutor.executeVoid(deleteAllStatement.bind() - .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID)); + .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(writeProfile)); } public Flux retrieveDeletedMessage(CassandraId cassandraId, MessageRange range) { @@ -216,14 +228,16 @@ private Flux retrieveResultSetOfDeletedMessage(CassandraId cassandraId, Mes private Flux retrieveAllDeleted(CassandraId cassandraId) { return cassandraAsyncExecutor.executeRows( selectAllUidStatement.bind() - .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID)); + .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)); } private Flux retrieveOneDeleted(CassandraId cassandraId, MessageUid uid) { return cassandraAsyncExecutor.executeRows( selectOneUidStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uid.asLong())); + .setLong(UID, uid.asLong()) + .setExecutionProfile(readProfile)); } private Flux retrieveDeletedBetween(CassandraId cassandraId, MessageUid from, MessageUid to) { @@ -231,14 +245,16 @@ private Flux retrieveDeletedBetween(CassandraId cassandraId, MessageUid fro selectBetweenUidStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) .setLong(UID_FROM, from.asLong()) - .setLong(UID_TO, to.asLong())); + .setLong(UID_TO, to.asLong()) + .setExecutionProfile(readProfile)); } private Flux retrieveDeletedAfter(CassandraId cassandraId, MessageUid from) { return cassandraAsyncExecutor.executeRows( selectFromUidStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID_FROM, from.asLong())); + .setLong(UID_FROM, from.asLong()) + .setExecutionProfile(readProfile)); } private MessageUid asMessageUid(Row row) { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java index 934c60b9d70..4bc51c71cf7 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java @@ -34,6 +34,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.model.MessageRange; @@ -45,6 +46,7 @@ import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metadata.schema.ClusteringOrder; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.google.common.collect.Lists; @@ -69,6 +71,8 @@ public class CassandraFirstUnseenDAO { private final PreparedStatement selectBetweenUidStatement; private final PreparedStatement selectFromUidStatement; private final ProtocolVersion protocolVersion; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraFirstUnseenDAO(CqlSession session) { @@ -82,6 +86,8 @@ public CassandraFirstUnseenDAO(CqlSession session) { this.selectOneUidStatement = prepareOneUidStatement(session); this.selectBetweenUidStatement = prepareBetweenUidStatement(session); this.selectFromUidStatement = prepareFromUidStatement(session); + this.readProfile = ProfileLocator.READ.locateProfile(session, "FIRST_UNSEEN"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "FIRST_UNSEEN"); } private PreparedStatement prepareOneUidStatement(CqlSession session) { @@ -150,7 +156,8 @@ public Mono addUnread(CassandraId cassandraId, MessageUid uid) { return cassandraAsyncExecutor.executeVoid( addStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uid.asLong())); + .setLong(UID, uid.asLong()) + .setExecutionProfile(writeProfile)); } public Mono addUnread(CassandraId mailboxId, List uids) { @@ -158,7 +165,8 @@ public Mono addUnread(CassandraId mailboxId, List uids) { return cassandraAsyncExecutor.executeVoid( addStatement.bind() .setUuid(MAILBOX_ID, mailboxId.asUuid()) - .setLong(UID, uids.iterator().next().asLong())); + .setLong(UID, uids.iterator().next().asLong()) + .setExecutionProfile(writeProfile)); } else { Stream batches = Lists.partition(uids, BATCH_STATEMENT_WINDOW) .stream() @@ -178,14 +186,16 @@ public Mono addUnread(CassandraId mailboxId, List uids) { public Mono removeUnread(CassandraId cassandraId, MessageUid uid) { return cassandraAsyncExecutor.executeVoid(deleteStatement.bind() .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setLong(UID, uid.asLong())); + .setLong(UID, uid.asLong()) + .setExecutionProfile(writeProfile)); } public Mono removeUnread(CassandraId mailboxId, List uids) { if (uids.size() == 1) { return cassandraAsyncExecutor.executeVoid(deleteStatement.bind() .setUuid(MAILBOX_ID, mailboxId.asUuid()) - .setLong(UID, uids.iterator().next().asLong())); + .setLong(UID, uids.iterator().next().asLong()) + .setExecutionProfile(writeProfile)); } else { Stream batches = Lists.partition(uids, BATCH_STATEMENT_WINDOW) .stream() @@ -193,7 +203,8 @@ public Mono removeUnread(CassandraId mailboxId, List uids) { BatchStatementBuilder batch = new BatchStatementBuilder(BatchType.UNLOGGED); uidBatch.forEach(uid -> batch.addStatement(deleteStatement.bind() .setUuid(MAILBOX_ID, mailboxId.asUuid()) - .setLong(UID, uid.asLong()))); + .setLong(UID, uid.asLong())) + .setExecutionProfile(writeProfile)); return batch.build(); }); return Flux.fromStream(batches) @@ -204,20 +215,23 @@ public Mono removeUnread(CassandraId mailboxId, List uids) { public Mono removeAll(CassandraId cassandraId) { return cassandraAsyncExecutor.executeVoid(deleteAllStatement.bind() - .setUuid(MAILBOX_ID, cassandraId.asUuid())); + .setUuid(MAILBOX_ID, cassandraId.asUuid()) + .setExecutionProfile(writeProfile)); } public Mono retrieveFirstUnread(CassandraId cassandraId) { return cassandraAsyncExecutor.executeSingleRow( readStatement.bind() - .setUuid(MAILBOX_ID, cassandraId.asUuid())) + .setUuid(MAILBOX_ID, cassandraId.asUuid()) + .setExecutionProfile(readProfile)) .map(this::asMessageUid); } public Flux listUnseen(CassandraId cassandraId) { return cassandraAsyncExecutor.executeRows( listStatement.bind() - .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID)) + .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .map(this::asMessageUid); } @@ -229,20 +243,23 @@ public Flux listUnseen(CassandraId cassandraId, MessageRange range) return cassandraAsyncExecutor.executeRows( selectFromUidStatement.bind() .setLong(UID_FROM, range.getUidFrom().asLong()) - .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID)) + .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .map(this::asMessageUid); case RANGE: return cassandraAsyncExecutor.executeRows( selectBetweenUidStatement.bind() .setLong(UID_FROM, range.getUidFrom().asLong()) .setLong(UID_TO, range.getUidTo().asLong()) - .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID)) + .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .map(this::asMessageUid); case ONE: return cassandraAsyncExecutor.executeRows( selectOneUidStatement.bind() .setLong(UID, range.getUidFrom().asLong()) - .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID)) + .set(MAILBOX_ID, cassandraId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .map(this::asMessageUid); default: throw new RuntimeException("Unsupported range type " + range.getType()); diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java index 16aec0233b9..9bf196e9822 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java @@ -34,6 +34,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.model.Mailbox; import org.apache.james.mailbox.model.MailboxCounters; @@ -41,6 +42,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.querybuilder.update.Assignment; @@ -59,6 +61,8 @@ public class CassandraMailboxCounterDAO { private final PreparedStatement incrementUnseenAndCountStatement; private final PreparedStatement decrementUnseenAndCountStatement; private final PreparedStatement deleteStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraMailboxCounterDAO(CqlSession session) { @@ -97,6 +101,8 @@ public CassandraMailboxCounterDAO(CqlSession session) { deleteStatement = session.prepare(deleteFrom(TABLE_NAME) .where(column(MAILBOX_ID).isEqualTo(bindMarker(MAILBOX_ID))) .build()); + readProfile = ProfileLocator.READ.locateProfile(session, "COUNTERS"); + writeProfile = ProfileLocator.WRITE.locateProfile(session, "COUNTERS"); } private PreparedStatement createReadStatement(CqlSession session) { @@ -116,11 +122,11 @@ private PreparedStatement updateMailboxStatement(CqlSession session, Assignment } public Mono delete(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, deleteStatement)); + return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, deleteStatement).setExecutionProfile(writeProfile)); } public Mono retrieveMailboxCounters(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement)) + return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement).setExecutionProfile(readProfile)) .map(row -> MailboxCounters.builder() .mailboxId(mailboxId) .count(row.getLong(COUNT)) @@ -147,7 +153,8 @@ public Mono add(MailboxCounters counters) { return cassandraAsyncExecutor.executeVoid( bindWithMailbox(mailboxId, addToCounters) .setLong(COUNT, counters.getCount()) - .setLong(UNSEEN, counters.getUnseen())); + .setLong(UNSEEN, counters.getUnseen()) + .setExecutionProfile(writeProfile)); } public Mono remove(MailboxCounters counters) { @@ -155,7 +162,8 @@ public Mono remove(MailboxCounters counters) { return cassandraAsyncExecutor.executeVoid( bindWithMailbox(mailboxId, removeToCounters) .setLong(COUNT, counters.getCount()) - .setLong(UNSEEN, counters.getUnseen())); + .setLong(UNSEEN, counters.getUnseen()) + .setExecutionProfile(writeProfile)); } public Mono countMessagesInMailbox(Mailbox mailbox) { @@ -165,46 +173,39 @@ public Mono countMessagesInMailbox(Mailbox mailbox) { } public Mono countMessagesInMailbox(CassandraId cassandraId) { - return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(cassandraId, readStatement)) + return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(cassandraId, readStatement).setExecutionProfile(readProfile)) .map(row -> row.getLong(COUNT)); } public Mono countUnseenMessagesInMailbox(Mailbox mailbox) { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); - return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement)) + return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement).setExecutionProfile(readProfile)) .map(row -> row.getLong(UNSEEN)); } public Mono decrementCount(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementMessageCountStatement)); + return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementMessageCountStatement).setExecutionProfile(writeProfile)); } public Mono incrementCount(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementMessageCountStatement)); + return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementMessageCountStatement).setExecutionProfile(writeProfile)); } public Mono decrementUnseen(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementUnseenCountStatement)); + return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementUnseenCountStatement).setExecutionProfile(writeProfile)); } public Mono incrementUnseen(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementUnseenCountStatement)); + return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementUnseenCountStatement).setExecutionProfile(writeProfile)); } public Mono decrementUnseenAndCount(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementUnseenAndCountStatement)); + return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementUnseenAndCountStatement).setExecutionProfile(writeProfile)); } public Mono incrementUnseenAndCount(CassandraId mailboxId) { - return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementUnseenAndCountStatement)); - } - - public Mono incrementUnseenAndCount(CassandraId mailboxId, long count, long unseen) { - return cassandraAsyncExecutor.executeVoid( - bindWithMailbox(mailboxId, addToCounters) - .setLong(COUNT, count) - .setLong(UNSEEN, unseen)); + return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementUnseenAndCountStatement).setExecutionProfile(writeProfile)); } private BoundStatement bindWithMailbox(CassandraId mailboxId, PreparedStatement statement) { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java index 940cecacb82..34ed01d4d26 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java @@ -38,6 +38,7 @@ import org.apache.james.backends.cassandra.init.CassandraTypesProvider; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Username; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.cassandra.mail.utils.MailboxBaseTupleUtil; @@ -49,6 +50,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; @@ -68,6 +70,8 @@ public class CassandraMailboxDAO { private final PreparedStatement updateUidValidityStatement; private final CqlSession session; private final TypeCodec mailboxBaseTypeCodec; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraMailboxDAO(CqlSession session, CassandraTypesProvider typesProvider) { @@ -82,6 +86,8 @@ public CassandraMailboxDAO(CqlSession session, CassandraTypesProvider typesProvi this.readStatement = prepareRead(); this.mailboxBaseTypeCodec = CodecRegistry.DEFAULT.codecFor(typesProvider.getDefinedUserType(MAILBOX_BASE.asCql(true))); + this.readProfile = ProfileLocator.READ.locateProfile(session, "MAILBOX"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "MAILBOX"); } private PreparedStatement prepareInsert() { @@ -133,24 +139,28 @@ public Mono save(Mailbox mailbox) { .setUuid(ID, cassandraId.asUuid()) .setString(NAME, mailbox.getName()) .setLong(UIDVALIDITY, mailbox.getUidValidity().asLong()) - .setUdtValue(MAILBOX_BASE, mailboxBaseTupleUtil.createMailboxBaseUDT(mailbox.getNamespace(), mailbox.getUser()))); + .setUdtValue(MAILBOX_BASE, mailboxBaseTupleUtil.createMailboxBaseUDT(mailbox.getNamespace(), mailbox.getUser())) + .setExecutionProfile(writeProfile)); } public Mono updatePath(CassandraId mailboxId, MailboxPath mailboxPath) { return executor.executeVoid(updateStatement.bind() .setUuid(ID, mailboxId.asUuid()) .setString(NAME, mailboxPath.getName()) - .setUdtValue(MAILBOX_BASE, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser()))); + .setUdtValue(MAILBOX_BASE, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser())) + .setExecutionProfile(writeProfile)); } public Mono delete(CassandraId mailboxId) { return executor.executeVoid(deleteStatement.bind() - .setUuid(ID, mailboxId.asUuid())); + .setUuid(ID, mailboxId.asUuid()) + .setExecutionProfile(writeProfile)); } public Mono retrieveMailbox(CassandraId mailboxId) { return executor.executeSingleRow(readStatement.bind() - .set(ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID)) + .set(ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .flatMap(row -> mailboxFromRow(row, mailboxId)); } @@ -185,7 +195,8 @@ private Mono sanitizeUidValidity(CassandraId cassandraId, long uidV private Mono updateUidValidity(CassandraId cassandraId, UidValidity uidValidity) { return executor.executeVoid(updateUidValidityStatement.bind() .setUuid(ID, cassandraId.asUuid()) - .setLong(UIDVALIDITY, uidValidity.asLong())); + .setLong(UIDVALIDITY, uidValidity.asLong()) + .setExecutionProfile(writeProfile)); } public Flux retrieveAllMailboxes() { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV3DAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV3DAO.java index 22c0f31c596..d6b4217ee9f 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV3DAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV3DAO.java @@ -38,6 +38,7 @@ import org.apache.james.backends.cassandra.init.configuration.JamesExecutionProfiles; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Username; import org.apache.james.mailbox.cassandra.GhostMailbox; import org.apache.james.mailbox.cassandra.ids.CassandraId; @@ -67,6 +68,8 @@ public class CassandraMailboxPathV3DAO { private final PreparedStatement selectAll; private final CqlSession session; private final DriverExecutionProfile lwtProfile; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraMailboxPathV3DAO(CqlSession session) { @@ -78,6 +81,8 @@ public CassandraMailboxPathV3DAO(CqlSession session) { this.selectUser = prepareSelectUser(); this.selectAll = prepareSelectAll(); this.lwtProfile = JamesExecutionProfiles.getLWTProfile(session); + this.readProfile = ProfileLocator.READ.locateProfile(session, "MAILBOXPATHV3"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "MAILBOXPATHV3"); } private PreparedStatement prepareDelete() { @@ -146,6 +151,8 @@ public Flux listUserMailboxes(String namespace, Username user, JamesExe if (consistencyChoice.equals(STRONG)) { statementBuilder.setExecutionProfile(lwtProfile); + } else { + statementBuilder.setExecutionProfile(readProfile); } return cassandraAsyncExecutor.executeRows(statementBuilder.build()) @@ -240,7 +247,7 @@ private BoundStatement setExecutionProfileIfNeeded(BoundStatement statement, Jam if (consistencyChoice.equals(STRONG)) { return statement.setExecutionProfile(lwtProfile); } else { - return statement; + return statement.setExecutionProfile(readProfile); } } } diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java index 80de0e5d9b5..6b75783699f 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java @@ -31,6 +31,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.cassandra.table.CassandraMailboxRecentsTable; @@ -43,6 +44,7 @@ import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.google.common.collect.Lists; @@ -59,6 +61,8 @@ public class CassandraMailboxRecentsDAO { private final PreparedStatement deleteAllStatement; private final PreparedStatement addStatement; private final ProtocolVersion protocolVersion; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraMailboxRecentsDAO(CqlSession session) { @@ -68,6 +72,8 @@ public CassandraMailboxRecentsDAO(CqlSession session) { deleteAllStatement = createDeleteAllStatement(session); addStatement = createAddStatement(session); protocolVersion = session.getContext().getProtocolVersion(); + this.readProfile = ProfileLocator.READ.locateProfile(session, "RECENTS"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "RECENTS"); } private PreparedStatement createReadStatement(CqlSession session) { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java index a9221f0c5f4..5c666dbd39e 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java @@ -65,7 +65,10 @@ import org.apache.commons.io.IOUtils; import org.apache.james.backends.cassandra.init.CassandraTypesProvider; +import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration; +import org.apache.james.backends.cassandra.init.configuration.JamesExecutionProfiles; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.blob.api.BlobId; import org.apache.james.blob.api.BlobStore; import org.apache.james.mailbox.cassandra.ids.CassandraMessageId; @@ -88,6 +91,7 @@ import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; @@ -114,13 +118,17 @@ public class CassandraMessageDAOV3 { private final PreparedStatement delete; private final PreparedStatement select; private final PreparedStatement listBlobs; + private final CassandraConfiguration configuration; private final Cid.CidParser cidParser; private final UserDefinedType attachmentsType; private final TypeCodec> attachmentCodec; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; + private final DriverExecutionProfile optimisticConsistencyLevelProfile; @Inject public CassandraMessageDAOV3(CqlSession session, CassandraTypesProvider typesProvider, BlobStore blobStore, - BlobId.Factory blobIdFactory) { + BlobId.Factory blobIdFactory, CassandraConfiguration cassandraConfiguration) { this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session); this.blobStore = blobStore; this.blobIdFactory = blobIdFactory; @@ -129,9 +137,14 @@ public CassandraMessageDAOV3(CqlSession session, CassandraTypesProvider typesPro this.delete = prepareDelete(session); this.select = prepareSelect(session); this.listBlobs = prepareSelectBlobs(session); + this.configuration = cassandraConfiguration; this.cidParser = Cid.parser().relaxed(); this.attachmentsType = typesProvider.getDefinedUserType(ATTACHMENTS.asCql(true)); this.attachmentCodec = CodecRegistry.DEFAULT.codecFor(listOf(attachmentsType)); + + this.readProfile = ProfileLocator.READ.locateProfile(session, "MESSAGEV3"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "MESSAGEV3"); + this.optimisticConsistencyLevelProfile = JamesExecutionProfiles.getOptimisticConsistencyLevelProfile(session); } private PreparedStatement prepareSelect(CqlSession session) { @@ -262,7 +275,8 @@ private BoundStatement boundWriteStatement(MailboxMessage message, Tuple2 retrieveMessage(ComposedMessageIdWithMetaData } public Mono retrieveMessage(CassandraMessageId cassandraMessageId, FetchType fetchType) { - return retrieveRow(cassandraMessageId) + if (configuration.isOptimisticConsistencyLevel()) { + return retrieveRow(cassandraMessageId, optimisticConsistencyLevelProfile) + .switchIfEmpty(Mono.defer(() -> retrieveRow(cassandraMessageId, readProfile))) + .flatMap(row -> message(row, cassandraMessageId, fetchType)); + } + return retrieveRow(cassandraMessageId, readProfile) .flatMap(row -> message(row, cassandraMessageId, fetchType)); } - private Mono retrieveRow(CassandraMessageId messageId) { + private Mono retrieveRow(CassandraMessageId messageId, DriverExecutionProfile driverExecutionProfile) { return cassandraAsyncExecutor.executeSingleRow(select .bind() - .set(MESSAGE_ID, messageId.get(), TypeCodecs.TIMEUUID)); + .set(MESSAGE_ID, messageId.get(), TypeCodecs.TIMEUUID) + .setExecutionProfile(driverExecutionProfile)); } private Mono message(Row row, CassandraMessageId cassandraMessageId, FetchType fetchType) { @@ -389,7 +409,8 @@ private MessageAttachmentRepresentation messageAttachmentByIdFrom(UdtValue udtVa public Mono delete(CassandraMessageId messageId) { return cassandraAsyncExecutor.executeVoid(delete.bind() - .setUuid(MESSAGE_ID, messageId.get())); + .setUuid(MESSAGE_ID, messageId.get()) + .setExecutionProfile(writeProfile)); } private Mono buildContentRetriever(FetchType fetchType, BlobId headerId, BlobId bodyId) { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java index 556f30038ab..499956432e7 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java @@ -59,6 +59,7 @@ import jakarta.mail.Flags.Flag; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.blob.api.BlobId; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.ModSeq; @@ -79,6 +80,7 @@ import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.metadata.schema.ClusteringOrder; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import com.google.common.annotations.VisibleForTesting; @@ -129,6 +131,9 @@ T get(Supplier initializer) { private final PreparedStatement update; private final PreparedStatement listStatement; private final ProtocolVersion protocolVersion; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile listUidProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraMessageIdDAO(CqlSession session, BlobId.Factory blobIdFactory) { @@ -151,6 +156,9 @@ public CassandraMessageIdDAO(CqlSession session, BlobId.Factory blobIdFactory) { this.listStatement = prepareList(session); this.selectMetadataRange = prepareSelectMetadataRange(session); this.selectNotDeletedRange = prepareSelectNotDeletedRange(session); + this.readProfile = ProfileLocator.READ.locateProfile(session, "MESSAGEID"); + this.listUidProfile = ProfileLocator.READ.locateProfile(session, "MESSAGEID-LIST-UID"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "MESSAGEID"); } private PreparedStatement prepareDelete(CqlSession session) { @@ -322,7 +330,8 @@ private PreparedStatement prepareSelectUidRangeLimited(CqlSession session) { public Mono delete(CassandraId mailboxId, MessageUid uid) { return cassandraAsyncExecutor.executeVoid(delete.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) - .setLong(IMAP_UID, uid.asLong())); + .setLong(IMAP_UID, uid.asLong()) + .setExecutionProfile(writeProfile)); } public Mono insert(CassandraMessageMetadata metadata) { @@ -356,6 +365,7 @@ public Mono insert(CassandraMessageMetadata metadata) { .setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get())) .setLong(FULL_CONTENT_OCTETS, metadata.getSize().get()) .setString(HEADER_CONTENT, metadata.getHeaderContent().get().asString()) + .setExecutionProfile(writeProfile) .build()); } @@ -420,6 +430,7 @@ private BoundStatement updateBoundStatement(ComposedMessageId id, UpdatedFlags u } else { statementBuilder.setSet(REMOVED_USERS_FLAGS, removedFlags, String.class); } + statementBuilder.setExecutionProfile(writeProfile); return statementBuilder.build(); } @@ -436,7 +447,8 @@ private Mono> asOptionalOfCassandraMessageId( private Mono selectOneRow(CassandraId mailboxId, MessageUid uid) { return cassandraAsyncExecutor.executeSingleRow(select.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) - .setLong(IMAP_UID, uid.asLong())); + .setLong(IMAP_UID, uid.asLong()) + .setExecutionProfile(readProfile)); } public Flux retrieveMessages(CassandraId mailboxId, MessageRange set, Limit limit) { @@ -447,7 +459,8 @@ public Flux retrieveMessages(CassandraId mailboxId, Me public Flux listUids(CassandraId mailboxId) { return cassandraAsyncExecutor.executeRows(selectAllUids.bind() - .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID)) + .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(listUidProfile)) .map(row -> MessageUid.of(TypeCodecs.BIGINT.decodePrimitive(row.getBytesUnsafe(0), protocolVersion))); } @@ -455,7 +468,8 @@ public Flux listMessagesMetadata(CassandraId mail return cassandraAsyncExecutor.executeRows(selectMetadataRange.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) .setLong(IMAP_UID_GTE, range.getUidFrom().asLong()) - .setLong(IMAP_UID_LTE, range.getUidTo().asLong())) + .setLong(IMAP_UID_LTE, range.getUidTo().asLong()) + .setExecutionProfile(readProfile)) .map(row -> { CassandraMessageId messageId = CassandraMessageId.Factory.of(row.get(MESSAGE_ID, TypeCodecs.TIMEUUID)); return ComposedMessageIdWithMetaData.builder() @@ -476,7 +490,8 @@ public Flux listNotDeletedUids(CassandraId mailboxId, MessageRange r return cassandraAsyncExecutor.executeRows(selectNotDeletedRange.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) .setLong(IMAP_UID_GTE, range.getUidFrom().asLong()) - .setLong(IMAP_UID_LTE, range.getUidTo().asLong())) + .setLong(IMAP_UID_LTE, range.getUidTo().asLong()) + .setExecutionProfile(listUidProfile)) .filter(row -> !TypeCodecs.BOOLEAN.decodePrimitive( row.getBytesUnsafe(deletedPosition.get(() -> row.getColumnDefinitions().firstIndexOf(DELETED))), protocolVersion)) .map(row -> MessageUid.of(TypeCodecs.BIGINT.decodePrimitive( @@ -487,7 +502,8 @@ private Flux doListUids(CassandraId mailboxId, MessageRange range) { return cassandraAsyncExecutor.executeRows(selectUidOnlyRange.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) .setLong(IMAP_UID_GTE, range.getUidFrom().asLong()) - .setLong(IMAP_UID_LTE, range.getUidTo().asLong())) + .setLong(IMAP_UID_LTE, range.getUidTo().asLong()) + .setExecutionProfile(listUidProfile)) .map(row -> MessageUid.of(TypeCodecs.BIGINT.decodePrimitive(row.getBytesUnsafe(0), protocolVersion))); } @@ -523,9 +539,11 @@ private Flux selectAll(CassandraId mailboxId, Limit limit) { return cassandraAsyncExecutor.executeRows(limit.getLimit() .map(limitAsInt -> selectAllLimited.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) - .setInt(LIMIT, limitAsInt)) + .setInt(LIMIT, limitAsInt) + .setExecutionProfile(readProfile)) .orElseGet(() -> selectAll.bind() - .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID))); + .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile))); } private Flux selectFrom(CassandraId mailboxId, MessageUid uid, Limit limit) { @@ -533,10 +551,12 @@ private Flux selectFrom(CassandraId mailboxId, MessageUid uid, Limit limit) .map(limitAsInt -> selectUidGteLimited.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) .setLong(IMAP_UID, uid.asLong()) - .setInt(LIMIT, limitAsInt)) + .setInt(LIMIT, limitAsInt) + .setExecutionProfile(readProfile)) .orElseGet(() -> selectUidGte.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) - .setLong(IMAP_UID, uid.asLong()))); + .setLong(IMAP_UID, uid.asLong()) + .setExecutionProfile(readProfile))); } private Flux selectRange(CassandraId mailboxId, MessageUid from, MessageUid to, Limit limit) { @@ -545,11 +565,13 @@ private Flux selectRange(CassandraId mailboxId, MessageUid from, MessageUid .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) .setLong(IMAP_UID_GTE, from.asLong()) .setLong(IMAP_UID_LTE, to.asLong()) - .setInt(LIMIT, limitAsInt)) + .setInt(LIMIT, limitAsInt) + .setExecutionProfile(readProfile)) .orElseGet(() -> selectUidRange.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID) .setLong(IMAP_UID_GTE, from.asLong()) - .setLong(IMAP_UID_LTE, to.asLong()))); + .setLong(IMAP_UID_LTE, to.asLong()) + .setExecutionProfile(readProfile))); } private Optional fromRowToComposedMessageIdWithFlags(Row row) { @@ -622,6 +644,7 @@ Mono insertNullInternalDateAndHeaderContent(CassandraMessageMetadata metad .setInt(BODY_START_OCTET, 0) .setLong(FULL_CONTENT_OCTETS, 0) .setString(HEADER_CONTENT, null) + .setExecutionProfile(writeProfile) .build()); } } diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java index ec58165fc68..6f793a0cef6 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java @@ -59,6 +59,7 @@ import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration; import org.apache.james.backends.cassandra.init.configuration.JamesExecutionProfiles; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.blob.api.BlobId; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.ModSeq; @@ -96,7 +97,6 @@ public class CassandraMessageIdToImapUidDAO { private final BlobId.Factory blobIdFactory; private final PreparedStatement delete; private final PreparedStatement insert; - private final PreparedStatement insertForced; private final PreparedStatement update; private final PreparedStatement selectAll; private final PreparedStatement select; @@ -104,6 +104,8 @@ public class CassandraMessageIdToImapUidDAO { private final CassandraConfiguration cassandraConfiguration; private final CqlSession session; private final DriverExecutionProfile lwtProfile; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraMessageIdToImapUidDAO(CqlSession session, BlobId.Factory blobIdFactory, @@ -114,12 +116,13 @@ public CassandraMessageIdToImapUidDAO(CqlSession session, BlobId.Factory blobIdF this.cassandraConfiguration = cassandraConfiguration; this.delete = prepareDelete(); this.insert = prepareInsert(); - this.insertForced = prepareInsertForced(); this.update = prepareUpdate(); this.selectAll = prepareSelectAll(); this.select = prepareSelect(); this.listStatement = prepareList(); this.lwtProfile = JamesExecutionProfiles.getLWTProfile(session); + this.readProfile = ProfileLocator.READ.locateProfile(session, "IMAP-UID-TABLE"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "IMAP-UID-TABLE"); } private PreparedStatement prepareDelete() { @@ -175,28 +178,6 @@ private PreparedStatement prepareInsert() { } } - private PreparedStatement prepareInsertForced() { - Insert insert = insertInto(TABLE_NAME) - .value(MESSAGE_ID, bindMarker(MESSAGE_ID)) - .value(MAILBOX_ID, bindMarker(MAILBOX_ID)) - .value(IMAP_UID, bindMarker(IMAP_UID)) - .value(MOD_SEQ, bindMarker(MOD_SEQ)) - .value(ANSWERED, bindMarker(ANSWERED)) - .value(DELETED, bindMarker(DELETED)) - .value(DRAFT, bindMarker(DRAFT)) - .value(FLAGGED, bindMarker(FLAGGED)) - .value(RECENT, bindMarker(RECENT)) - .value(SEEN, bindMarker(SEEN)) - .value(USER, bindMarker(USER)) - .value(USER_FLAGS, bindMarker(USER_FLAGS)) - .value(INTERNAL_DATE, bindMarker(INTERNAL_DATE)) - .value(SAVE_DATE, bindMarker(SAVE_DATE)) - .value(BODY_START_OCTET, bindMarker(BODY_START_OCTET)) - .value(FULL_CONTENT_OCTETS, bindMarker(FULL_CONTENT_OCTETS)) - .value(HEADER_CONTENT, bindMarker(HEADER_CONTENT)); - return session.prepare(insert.build()); - } - private PreparedStatement prepareUpdate() { Update update = QueryBuilder.update(TABLE_NAME) .set(setColumn(MOD_SEQ, bindMarker(MOD_SEQ)), @@ -242,7 +223,8 @@ private PreparedStatement prepareSelect() { public Mono delete(CassandraMessageId messageId, CassandraId mailboxId) { return cassandraAsyncExecutor.executeVoid(delete.bind() .setUuid(MESSAGE_ID, messageId.get()) - .setUuid(MAILBOX_ID, mailboxId.asUuid())); + .setUuid(MAILBOX_ID, mailboxId.asUuid()) + .setExecutionProfile(writeProfile)); } public Mono insert(CassandraMessageMetadata metadata) { @@ -275,32 +257,10 @@ public Mono insert(CassandraMessageMetadata metadata) { .setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get())) .setLong(FULL_CONTENT_OCTETS, metadata.getSize().get()) .setString(HEADER_CONTENT, metadata.getHeaderContent().get().asString()) + .setExecutionProfile(writeProfile) .build()); } - public Mono insertForce(CassandraMessageMetadata metadata) { - ComposedMessageId composedMessageId = metadata.getComposedMessageId().getComposedMessageId(); - Flags flags = metadata.getComposedMessageId().getFlags(); - return cassandraAsyncExecutor.executeVoid(insertForced.bind() - .set(MESSAGE_ID, ((CassandraMessageId) composedMessageId.getMessageId()).get(), TypeCodecs.TIMEUUID) - .set(MAILBOX_ID, ((CassandraId) composedMessageId.getMailboxId()).asUuid(), TypeCodecs.TIMEUUID) - .setLong(IMAP_UID, composedMessageId.getUid().asLong()) - .setLong(MOD_SEQ, metadata.getComposedMessageId().getModSeq().asLong()) - .setBoolean(ANSWERED, flags.contains(Flag.ANSWERED)) - .setBoolean(DELETED, flags.contains(Flag.DELETED)) - .setBoolean(DRAFT, flags.contains(Flag.DRAFT)) - .setBoolean(FLAGGED, flags.contains(Flag.FLAGGED)) - .setBoolean(RECENT, flags.contains(Flag.RECENT)) - .setBoolean(SEEN, flags.contains(Flag.SEEN)) - .setBoolean(USER, flags.contains(Flag.USER)) - .setSet(USER_FLAGS, ImmutableSet.copyOf(flags.getUserFlags()), String.class) - .setInstant(INTERNAL_DATE, metadata.getInternalDate().get().toInstant()) - .setInstant(SAVE_DATE, metadata.getSaveDate().map(Date::toInstant).orElse(null)) - .setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get())) - .setLong(FULL_CONTENT_OCTETS, metadata.getSize().get()) - .setString(HEADER_CONTENT, metadata.getHeaderContent().get().asString())); - } - public Mono updateMetadata(ComposedMessageId id, UpdatedFlags updatedFlags, ModSeq previousModeq) { if (cassandraConfiguration.isMessageWriteStrongConsistency()) { return cassandraAsyncExecutor.executeReturnApplied(updateBoundStatement(id, updatedFlags, previousModeq)); @@ -432,7 +392,7 @@ private BoundStatement setExecutionProfileIfNeeded(BoundStatement statement, Jam if (consistencyChoice.equals(STRONG)) { return statement.setExecutionProfile(lwtProfile); } else { - return statement; + return statement.setExecutionProfile(readProfile); } } @@ -466,6 +426,7 @@ Mono insertNullInternalDateAndHeaderContent(CassandraMessageMetadata metad .setInt(BODY_START_OCTET, 0) .setLong(FULL_CONTENT_OCTETS, 0) .setString(HEADER_CONTENT, null) + .setExecutionProfile(writeProfile) .build()); } } diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java index 92ce031e8bd..a5d0de7b4c2 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java @@ -39,6 +39,7 @@ import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration; import org.apache.james.backends.cassandra.init.configuration.JamesExecutionProfiles; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.ModSeq; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.exception.MailboxException; @@ -92,6 +93,7 @@ private static T unbox(Supplier supplier) throws MailboxException { private final RetryBackoffSpec retrySpec; private final DriverExecutionProfile lwtProfile; private final CassandraConfiguration cassandraConfiguration; + private final DriverExecutionProfile readProfile; @Inject public CassandraModSeqProvider(CqlSession session, CassandraConfiguration cassandraConfiguration) { @@ -104,6 +106,7 @@ public CassandraModSeqProvider(CqlSession session, CassandraConfiguration cassan this.retrySpec = Retry.backoff(cassandraConfiguration.getModSeqMaxRetry(), firstBackoff) .scheduler(Schedulers.parallel()); this.cassandraConfiguration = cassandraConfiguration; + this.readProfile = ProfileLocator.READ.locateProfile(session, "MODSEQ"); } private PreparedStatement prepareInsert(CqlSession session) { @@ -151,11 +154,17 @@ public ModSeq highestModSeq(Mailbox mailbox) throws MailboxException { @Override public ModSeq highestModSeq(MailboxId mailboxId) throws MailboxException { return unbox(() -> findHighestModSeq((CassandraId) mailboxId, - Optional.of(lwtProfile).filter(any -> cassandraConfiguration.isUidReadStrongConsistency())) + locateReadProfile()) .block().orElse(ModSeq.first())) .add(cassandraConfiguration.getUidModseqIncrement()); } + private Optional locateReadProfile() { + return Optional.of(lwtProfile) + .filter(any -> cassandraConfiguration.isUidReadStrongConsistency()) + .or(() -> Optional.of(readProfile)); + } + private Mono> findHighestModSeq(CassandraId mailboxId, Optional executionProfile) { BoundStatement statement = select.bind() .set(MAILBOX_ID, mailboxId.asUuid(), TypeCodecs.TIMEUUID); @@ -207,7 +216,7 @@ public Mono nextModSeqReactive(MailboxId mailboxId) { @Override public Mono highestModSeqReactive(Mailbox mailbox) { - return findHighestModSeq((CassandraId) mailbox.getMailboxId(), Optional.empty()) + return findHighestModSeq((CassandraId) mailbox.getMailboxId(), locateReadProfile()) .map(optional -> optional.orElse(ModSeq.first())) .map(modSeq -> modSeq.add(cassandraConfiguration.getUidModseqIncrement())); } diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java index da747b082de..da1b06f6ae2 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java @@ -39,6 +39,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Username; import org.apache.james.mailbox.cassandra.ids.CassandraMessageId; import org.apache.james.mailbox.model.MessageId; @@ -47,6 +48,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import reactor.core.publisher.Flux; @@ -56,6 +58,8 @@ public class CassandraThreadDAO { private final PreparedStatement insertOne; private final PreparedStatement selectOne; private final PreparedStatement deleteOne; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraThreadDAO(CqlSession session) { @@ -79,6 +83,10 @@ public CassandraThreadDAO(CqlSession session) { .where(column(USERNAME).isEqualTo(bindMarker(USERNAME)), column(MIME_MESSAGE_ID).isEqualTo(bindMarker(MIME_MESSAGE_ID))) .build()); + + + this.readProfile = ProfileLocator.READ.locateProfile(session, "THREAD"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "THREAD"); } public Flux insertSome(Username username, Set hashMimeMessageIds, MessageId messageId, ThreadId threadId, Optional hashBaseSubject) { @@ -88,7 +96,8 @@ public Flux insertSome(Username username, Set hashMimeMessageIds, .set(MIME_MESSAGE_ID, mimeMessageId, TypeCodecs.INT) .set(MESSAGE_ID, ((CassandraMessageId) messageId).get(), TypeCodecs.TIMEUUID) .set(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get(), TypeCodecs.TIMEUUID) - .set(BASE_SUBJECT, hashBaseSubject.orElse(null), TypeCodecs.INT)), DEFAULT_CONCURRENCY); + .set(BASE_SUBJECT, hashBaseSubject.orElse(null), TypeCodecs.INT) + .setExecutionProfile(writeProfile)), DEFAULT_CONCURRENCY); } public Flux, ThreadId>> selectSome(Username username, Set hashMimeMessageIds) { @@ -96,7 +105,8 @@ public Flux, ThreadId>> selectSome(Username username, Set .flatMap(mimeMessageId -> executor .executeSingleRow(selectOne.bind() .set(USERNAME, username.asString(), TypeCodecs.TEXT) - .set(MIME_MESSAGE_ID, mimeMessageId, TypeCodecs.INT)) + .set(MIME_MESSAGE_ID, mimeMessageId, TypeCodecs.INT) + .setExecutionProfile(readProfile)) .map(this::readRow), DEFAULT_CONCURRENCY) .distinct(); } @@ -105,7 +115,8 @@ public Flux deleteSome(Username username, Set hashMimeMessageIds) return Flux.fromIterable(hashMimeMessageIds) .flatMap(mimeMessageId -> executor.executeVoid(deleteOne.bind() .set(USERNAME, username.asString(), TypeCodecs.TEXT) - .set(MIME_MESSAGE_ID, mimeMessageId, TypeCodecs.INT))); + .set(MIME_MESSAGE_ID, mimeMessageId, TypeCodecs.INT) + .setExecutionProfile(writeProfile))); } public Pair, ThreadId> readRow(Row row) { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java index a3ba779a086..92959ee35d6 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java @@ -37,6 +37,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Username; import org.apache.james.mailbox.cassandra.ids.CassandraMessageId; import org.apache.james.mailbox.model.MessageId; @@ -45,6 +46,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; @@ -61,6 +63,8 @@ public class CassandraThreadLookupDAO { private final PreparedStatement select; private final PreparedStatement selectAll; private final PreparedStatement delete; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraThreadLookupDAO(CqlSession session) { @@ -88,6 +92,10 @@ public CassandraThreadLookupDAO(CqlSession session) { .where(column(MESSAGE_ID).isEqualTo(bindMarker(MESSAGE_ID)), column(THREAD_ID).isEqualTo(bindMarker(THREAD_ID))) .build()); + + + this.readProfile = ProfileLocator.READ.locateProfile(session, "THREAD-LOOKUP"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "THREAD-LOOKUP"); } public Mono insert(MessageId messageId, ThreadId threadId, Username username, Set hashMimeMessageIds) { @@ -95,13 +103,15 @@ public Mono insert(MessageId messageId, ThreadId threadId, Username userna .set(MESSAGE_ID, ((CassandraMessageId) messageId).get(), TypeCodecs.TIMEUUID) .set(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get(), TypeCodecs.TIMEUUID) .set(USERNAME, username.asString(), TypeCodecs.TEXT) - .set(MIME_MESSAGE_IDS, hashMimeMessageIds, SET_OF_INTS_CODEC)); + .set(MIME_MESSAGE_IDS, hashMimeMessageIds, SET_OF_INTS_CODEC) + .setExecutionProfile(writeProfile)); } public Flux selectAll(ThreadId threadId) { return executor.executeRows( selectAll.bind() - .set(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get(), TypeCodecs.TIMEUUID)) + .set(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .map(row -> CassandraMessageId.of(row.get(MESSAGE_ID, TypeCodecs.TIMEUUID))); } @@ -109,14 +119,16 @@ public Mono selectOneRow(ThreadId threadId, MessageId m return executor.executeSingleRow( select.bind() .set(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get(), TypeCodecs.TIMEUUID) - .set(MESSAGE_ID, ((CassandraMessageId) messageId).get(), TypeCodecs.TIMEUUID)) + .set(MESSAGE_ID, ((CassandraMessageId) messageId).get(), TypeCodecs.TIMEUUID) + .setExecutionProfile(readProfile)) .map(this::readRow); } public Mono deleteOneRow(ThreadId threadId, MessageId messageId) { return executor.executeVoid(delete.bind() .set(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get(), TypeCodecs.TIMEUUID) - .set(MESSAGE_ID, ((CassandraMessageId) messageId).get(), TypeCodecs.TIMEUUID)); + .set(MESSAGE_ID, ((CassandraMessageId) messageId).get(), TypeCodecs.TIMEUUID) + .setExecutionProfile(writeProfile)); } private ThreadTablePartitionKey readRow(Row row) { diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java index f8332a337f6..3a128456699 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java @@ -39,6 +39,7 @@ import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration; import org.apache.james.backends.cassandra.init.configuration.JamesExecutionProfiles; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.cassandra.ids.CassandraId; import org.apache.james.mailbox.exception.MailboxException; @@ -68,6 +69,7 @@ public class CassandraUidProvider implements UidProvider { private final DriverExecutionProfile lwtProfile; private final RetryBackoffSpec retrySpec; private final CassandraConfiguration cassandraConfiguration; + private final DriverExecutionProfile readProfile; @Inject public CassandraUidProvider(CqlSession session, CassandraConfiguration cassandraConfiguration) { @@ -80,6 +82,7 @@ public CassandraUidProvider(CqlSession session, CassandraConfiguration cassandra this.retrySpec = Retry.backoff(cassandraConfiguration.getUidMaxRetry(), firstBackoff) .scheduler(Schedulers.parallel()); this.cassandraConfiguration = cassandraConfiguration; + this.readProfile = ProfileLocator.READ.locateProfile(session, "UID"); } private PreparedStatement prepareSelect(CqlSession session) { @@ -157,14 +160,20 @@ private List range(MessageUid lowerExclusive, MessageUid higherInclu @Override public Optional lastUid(Mailbox mailbox) { - return findHighestUid((CassandraId) mailbox.getMailboxId(), Optional.of(lwtProfile).filter(any -> cassandraConfiguration.isUidReadStrongConsistency())) + return findHighestUid((CassandraId) mailbox.getMailboxId(), locateReadProfile()) .blockOptional() .map(uid -> uid.add(cassandraConfiguration.getUidModseqIncrement())); } + private Optional locateReadProfile() { + return Optional.of(lwtProfile) + .filter(any -> cassandraConfiguration.isUidReadStrongConsistency()) + .or(() -> Optional.of(readProfile)); + } + @Override public Mono> lastUidReactive(Mailbox mailbox) { - return findHighestUid((CassandraId) mailbox.getMailboxId(), Optional.of(lwtProfile).filter(any -> cassandraConfiguration.isUidReadStrongConsistency())) + return findHighestUid((CassandraId) mailbox.getMailboxId(), locateReadProfile()) .map(uid -> uid.add(cassandraConfiguration.getUidModseqIncrement())) .map(Optional::of) .switchIfEmpty(Mono.just(Optional.empty())); diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java index b9a961949aa..7d8390dea61 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java @@ -36,6 +36,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Username; import org.apache.james.mailbox.acl.ACLDiff; import org.apache.james.mailbox.acl.PositiveUserACLDiff; @@ -47,6 +48,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.github.fge.lambdas.Throwing; import reactor.core.publisher.Flux; @@ -59,6 +61,8 @@ public class CassandraUserMailboxRightsDAO { private final PreparedStatement insert; private final PreparedStatement select; private final PreparedStatement selectUser; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraUserMailboxRightsDAO(CqlSession session) { @@ -67,6 +71,9 @@ public CassandraUserMailboxRightsDAO(CqlSession session) { this.insert = prepareInsert(session); this.select = prepareSelect(session); this.selectUser = prepareSelectAllForUser(session); + + this.readProfile = ProfileLocator.READ.locateProfile(session, "USER_ACL"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "USER_ACL"); } private PreparedStatement prepareDelete(CqlSession session) { @@ -113,7 +120,8 @@ private Flux removeAll(CassandraId cassandraId, Stream r .flatMap(entry -> cassandraAsyncExecutor.executeVoid( delete.bind() .setString(USER_NAME, entry.getKey().getName()) - .setUuid(MAILBOX_ID, cassandraId.asUuid())), + .setUuid(MAILBOX_ID, cassandraId.asUuid()) + .setExecutionProfile(writeProfile)), DEFAULT_CONCURRENCY); } @@ -123,7 +131,8 @@ private Flux addAll(CassandraId cassandraId, Stream adde insert.bind() .setString(USER_NAME, entry.getKey().getName()) .setUuid(MAILBOX_ID, cassandraId.asUuid()) - .setString(RIGHTS, entry.getValue().serialize())), + .setString(RIGHTS, entry.getValue().serialize()) + .setExecutionProfile(writeProfile)), DEFAULT_CONCURRENCY); } @@ -131,7 +140,8 @@ public Mono> retrieve(Username userName, CassandraId mai return cassandraAsyncExecutor.executeSingleRowOptional( select.bind() .setString(USER_NAME, userName.asString()) - .setUuid(MAILBOX_ID, mailboxId.asUuid())) + .setUuid(MAILBOX_ID, mailboxId.asUuid()) + .setExecutionProfile(readProfile)) .map(rowOptional -> rowOptional.map(Throwing.function(row -> Rfc4314Rights.fromSerializedRfc4314Rights(row.getString(RIGHTS))))); } @@ -139,7 +149,8 @@ public Mono> retrieve(Username userName, CassandraId mai public Flux> listRightsForUser(Username userName) { return cassandraAsyncExecutor.executeRows( selectUser.bind() - .setString(USER_NAME, userName.asString())) + .setString(USER_NAME, userName.asString()) + .setExecutionProfile(readProfile)) .map(Throwing.function(this::toPair)); } diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java index 34972330f26..1a6ffab2f1e 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java @@ -832,7 +832,8 @@ private CassandraMessageDAOV3 messageDAO(CassandraCluster cassandraCluster) { cassandraCluster.getConf(), cassandraCluster.getTypesProvider(), mock(BlobStore.class), - new PlainBlobId.Factory()); + new PlainBlobId.Factory(), + CassandraConfiguration.DEFAULT_CONFIGURATION); } private CassandraThreadDAO threadDAO(CassandraCluster cassandraCluster) { diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java index 285f062113b..fd891c9271b 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java @@ -33,6 +33,7 @@ import org.apache.james.backends.cassandra.CassandraCluster; import org.apache.james.backends.cassandra.CassandraClusterExtension; import org.apache.james.backends.cassandra.components.CassandraDataDefinition; +import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration; import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDataDefinition; import org.apache.james.blob.api.BlobStore; import org.apache.james.blob.api.PlainBlobId; @@ -101,7 +102,8 @@ void setUp(CassandraCluster cassandra) { cassandra.getConf(), cassandra.getTypesProvider(), blobStore, - blobIdFactory); + blobIdFactory, + CassandraConfiguration.DEFAULT_CONFIGURATION); messageIdWithMetadata = ComposedMessageIdWithMetaData.builder() .composedMessageId(new ComposedMessageId(MAILBOX_ID, messageId, messageUid)) diff --git a/server/apps/distributed-app/sample-configuration/cassandra-driver.conf b/server/apps/distributed-app/sample-configuration/cassandra-driver.conf index af1ba360542..ac9816f9a1a 100644 --- a/server/apps/distributed-app/sample-configuration/cassandra-driver.conf +++ b/server/apps/distributed-app/sample-configuration/cassandra-driver.conf @@ -133,15 +133,19 @@ datastax-java-driver { } CACHING { basic.request.consistency = LOCAL_ONE - basic.request.serial-consistency = LOCAL_ONE basic.request.timeout = 100 milliseconds } OPTIMISTIC_CONSISTENCY_LEVEL { basic.request.consistency = LOCAL_ONE - basic.request.serial-consistency = LOCAL_ONE } BATCH { basic.request.timeout = 1 hour } + READ { + basic.request.consistency = QUORUM; + } + WRITE { + basic.request.consistency = QUORUM; + } } } diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java index 364ca65fb29..6f14d31d2b7 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java @@ -31,6 +31,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Domain; import org.apache.james.dnsservice.api.DNSService; import org.apache.james.domainlist.api.DomainListException; @@ -39,6 +40,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import reactor.core.publisher.Mono; @@ -49,6 +51,8 @@ public class CassandraDomainList extends AbstractDomainList { private final PreparedStatement readStatement; private final PreparedStatement insertStatement; private final PreparedStatement removeStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraDomainList(DNSService dnsService, CqlSession session) { @@ -72,11 +76,13 @@ public CassandraDomainList(DNSService dnsService, CqlSession session) { .whereColumn(DOMAIN).isEqualTo(bindMarker(DOMAIN)) .ifExists() .build()); + this.readProfile = ProfileLocator.READ.locateProfile(session, "DOMAIN"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "DOMAIN"); } @Override protected List getDomainListInternal() throws DomainListException { - return executor.executeRows(readAllStatement.bind()) + return executor.executeRows(readAllStatement.bind().setExecutionProfile(readProfile)) .map(row -> Domain.of(row.get(0, TypeCodecs.TEXT))) .collectList() .block(); @@ -85,7 +91,8 @@ protected List getDomainListInternal() throws DomainListException { @Override protected boolean containsDomainInternal(Domain domain) throws DomainListException { return executor.executeSingleRowOptional(readStatement.bind() - .set(DOMAIN, domain.asString(), TypeCodecs.TEXT)) + .set(DOMAIN, domain.asString(), TypeCodecs.TEXT) + .setExecutionProfile(readProfile)) .block() .isPresent(); } @@ -93,7 +100,8 @@ protected boolean containsDomainInternal(Domain domain) throws DomainListExcepti @Override public Mono containsDomainReactive(Domain domain) { return executor.executeSingleRowOptional(readStatement.bind() - .set(DOMAIN, domain.asString(), TypeCodecs.TEXT)) + .set(DOMAIN, domain.asString(), TypeCodecs.TEXT) + .setExecutionProfile(readProfile)) .handle(ReactorUtils.publishIfPresent()) .hasElement(); } @@ -101,7 +109,8 @@ public Mono containsDomainReactive(Domain domain) { @Override public void addDomain(Domain domain) throws DomainListException { boolean executed = executor.executeReturnApplied(insertStatement.bind() - .set(DOMAIN, domain.asString(), TypeCodecs.TEXT)) + .set(DOMAIN, domain.asString(), TypeCodecs.TEXT) + .setExecutionProfile(writeProfile)) .block(); if (!executed) { throw new DomainListException(domain.name() + " already exists."); @@ -111,11 +120,11 @@ public void addDomain(Domain domain) throws DomainListException { @Override public void doRemoveDomain(Domain domain) throws DomainListException { boolean executed = executor.executeReturnApplied(removeStatement.bind() - .set(DOMAIN, domain.asString(), TypeCodecs.TEXT)) + .set(DOMAIN, domain.asString(), TypeCodecs.TEXT) + .setExecutionProfile(writeProfile)) .block(); if (!executed) { throw new DomainListException(domain.name() + " was not found"); } } - } \ No newline at end of file diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java index 4c258881f21..edef498ddc9 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java @@ -32,11 +32,13 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.rrt.lib.Mapping; import org.apache.james.rrt.lib.MappingSource; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -47,6 +49,8 @@ public class CassandraMappingsSourcesDAO { private final PreparedStatement deleteStatement; private final PreparedStatement retrieveSourcesStatement; private final PreparedStatement truncateStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraMappingsSourcesDAO(CqlSession session) { @@ -70,26 +74,31 @@ public CassandraMappingsSourcesDAO(CqlSession session) { .build()); this.truncateStatement = session.prepare(truncate(TABLE_NAME).build()); + this.readProfile = ProfileLocator.READ.locateProfile(session, "RRT-SOURCE"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "RRT-SOURCE"); } public Mono addMapping(Mapping mapping, MappingSource source) { return executor.executeVoid(insertStatement.bind() .setString(MAPPING_TYPE, mapping.getType().asPrefix()) .setString(MAPPING_VALUE, mapping.getMappingValue()) - .setString(SOURCE, source.asMailAddressString())); + .setString(SOURCE, source.asMailAddressString()) + .setExecutionProfile(writeProfile)); } Mono removeMapping(Mapping mapping, MappingSource source) { return executor.executeVoid(deleteStatement.bind() .setString(MAPPING_TYPE, mapping.getType().asPrefix()) .setString(MAPPING_VALUE, mapping.getMappingValue()) - .setString(SOURCE, source.asMailAddressString())); + .setString(SOURCE, source.asMailAddressString()) + .setExecutionProfile(writeProfile)); } public Flux retrieveSources(Mapping mapping) { return executor.executeRows(retrieveSourcesStatement.bind() .setString(MAPPING_TYPE, mapping.getType().asPrefix()) - .setString(MAPPING_VALUE, mapping.getMappingValue())) + .setString(MAPPING_VALUE, mapping.getMappingValue()) + .setExecutionProfile(readProfile)) .map(row -> MappingSource.parse(row.getString(SOURCE))); } diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java index c157932ede2..6f2d15b6733 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java @@ -34,12 +34,14 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.rrt.lib.Mapping; import org.apache.james.rrt.lib.MappingSource; import org.apache.james.rrt.lib.MappingsImpl; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.google.common.collect.ImmutableList; import reactor.core.publisher.Flux; @@ -51,6 +53,8 @@ public class CassandraRecipientRewriteTableDAO { private final PreparedStatement deleteStatement; private final PreparedStatement retrieveMappingStatement; private final PreparedStatement retrieveAllMappingsStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraRecipientRewriteTableDAO(CqlSession session) { @@ -76,26 +80,31 @@ public CassandraRecipientRewriteTableDAO(CqlSession session) { .whereColumn(DOMAIN).isEqualTo(bindMarker(DOMAIN)) .whereColumn(MAPPING).isEqualTo(bindMarker(MAPPING)) .build()); + this.readProfile = ProfileLocator.READ.locateProfile(session, "RRT"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "RRT"); } public Mono addMapping(MappingSource source, Mapping mapping) { return executor.executeVoid(insertStatement.bind() .setString(USER, source.getFixedUser()) .setString(DOMAIN, source.getFixedDomain()) - .setString(MAPPING, mapping.asString())); + .setString(MAPPING, mapping.asString()) + .setExecutionProfile(writeProfile)); } Mono removeMapping(MappingSource source, Mapping mapping) { return executor.executeVoid(deleteStatement.bind() .setString(USER, source.getFixedUser()) .setString(DOMAIN, source.getFixedDomain()) - .setString(MAPPING, mapping.asString())); + .setString(MAPPING, mapping.asString()) + .setExecutionProfile(writeProfile)); } Mono retrieveMappings(MappingSource source) { return executor.executeRows(retrieveMappingStatement.bind() .setString(USER, source.getFixedUser()) - .setString(DOMAIN, source.getFixedDomain())) + .setString(DOMAIN, source.getFixedDomain()) + .setExecutionProfile(readProfile)) .mapNotNull(row -> row.getString(MAPPING)) .collect(ImmutableList.toImmutableList()) .map(MappingsImpl::fromCollection) diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java index 077a0fa4e00..6bb92d382fb 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java @@ -39,6 +39,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Username; import org.apache.james.user.api.AlreadyExistInUsersRepositoryException; import org.apache.james.user.api.UsersRepositoryException; @@ -53,6 +54,7 @@ import com.datastax.oss.driver.api.core.cql.BatchStatementBuilder; import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; @@ -78,6 +80,8 @@ public class CassandraUsersDAO implements UsersDAO { private final PreparedStatement getDelegatedToUsersStatement; private final PreparedStatement addDelegatedToUsersStatement; private final PreparedStatement removeDelegatedToUsersStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; private final Algorithm preferredAlgorithm; private final HashingMode fallbackHashingMode; @@ -156,6 +160,9 @@ public CassandraUsersDAO(CqlSession session, CassandraRepositoryConfiguration co .remove(DELEGATED_USERS, bindMarker(DELEGATED_USERS)) .whereColumn(NAME).isEqualTo(bindMarker(NAME)) .build()); + + this.readProfile = ProfileLocator.READ.locateProfile(session, "USER"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "USER"); } @VisibleForTesting @@ -172,7 +179,8 @@ public Optional getUserByName(Username name) { private Mono getUserByNameReactive(Username name) { return executor.executeSingleRow( getUserStatement.bind() - .setString(NAME, name.asString())) + .setString(NAME, name.asString()) + .setExecutionProfile(readProfile)) .filter(row -> row.getString(ALGORITHM) != null) .map(row -> new DefaultUser(Username.of(row.getString(NAME)), row.getString(PASSWORD), Algorithm.of(row.getString(ALGORITHM), fallbackHashingMode), preferredAlgorithm)); @@ -180,7 +188,8 @@ private Mono getUserByNameReactive(Username name) { public Mono exist(Username name) { return executor.executeReturnExists(getUserStatement.bind() - .setString(NAME, name.asString())); + .setString(NAME, name.asString()) + .setExecutionProfile(readProfile)); } @Override @@ -192,7 +201,8 @@ public void updateUser(User user) throws UsersRepositoryException { .setString(REALNAME, defaultUser.getUserName().asString()) .setString(PASSWORD, defaultUser.getHashedPassword()) .setString(ALGORITHM, defaultUser.getHashAlgorithm().asString()) - .setString(NAME, defaultUser.getUserName().asString())) + .setString(NAME, defaultUser.getUserName().asString()) + .setExecutionProfile(writeProfile)) .block(); if (!executed) { @@ -204,11 +214,13 @@ public Mono addAuthorizedUsers(Username baseUser, Username userWithAccess, BatchStatementBuilder batchBuilder = new BatchStatementBuilder(BatchType.LOGGED); batchBuilder.addStatement(addAuthorizedUsersStatement.bind() .setString(NAME, baseUser.asString()) - .setSet(AUTHORIZED_USERS, ImmutableSet.of(userWithAccess.asString()), String.class)); + .setSet(AUTHORIZED_USERS, ImmutableSet.of(userWithAccess.asString()), String.class) + .setExecutionProfile(writeProfile)); if (targetUserExists) { batchBuilder.addStatement(addDelegatedToUsersStatement.bind() .setString(NAME, userWithAccess.asString()) - .setSet(DELEGATED_USERS, ImmutableSet.of(baseUser.asString()), String.class)); + .setSet(DELEGATED_USERS, ImmutableSet.of(baseUser.asString()), String.class) + .setExecutionProfile(writeProfile)); } return executor.executeVoid(batchBuilder.build()); @@ -218,10 +230,12 @@ public Mono removeAuthorizedUser(Username baseUser, Username userWithAcces return executor.executeVoid(new BatchStatementBuilder(BatchType.LOGGED) .addStatement(removeAuthorizedUsersStatement.bind() .setString(NAME, baseUser.asString()) - .setSet(AUTHORIZED_USERS, ImmutableSet.of(userWithAccess.asString()), String.class)) + .setSet(AUTHORIZED_USERS, ImmutableSet.of(userWithAccess.asString()), String.class) + .setExecutionProfile(writeProfile)) .addStatement(removeDelegatedToUsersStatement.bind() .setString(NAME, userWithAccess.asString()) - .setSet(DELEGATED_USERS, ImmutableSet.of(baseUser.asString()), String.class)) + .setSet(DELEGATED_USERS, ImmutableSet.of(baseUser.asString()), String.class) + .setExecutionProfile(writeProfile)) .build()); } @@ -233,9 +247,11 @@ public Mono removeAllAuthorizedUsers(Username baseUser) { authorizedList.forEach(username -> batch.addStatement( removeDelegatedToUsersStatement.bind() .setString(NAME, username.asString()) - .setSet(DELEGATED_USERS, ImmutableSet.of(baseUser.asString()), String.class))); + .setSet(DELEGATED_USERS, ImmutableSet.of(baseUser.asString()), String.class)) + .setExecutionProfile(writeProfile)); batch.addStatement(removeAllAuthorizedUsersStatement.bind() - .setString(NAME, baseUser.asString())); + .setString(NAME, baseUser.asString()) + .setExecutionProfile(writeProfile)); return batch.build(); }) .flatMap(executor::executeVoid); @@ -244,7 +260,8 @@ public Mono removeAllAuthorizedUsers(Username baseUser) { public Flux getAuthorizedUsers(Username name) { return executor.executeSingleRow( getAuthorizedUsersStatement.bind() - .setString(NAME, name.asString())) + .setString(NAME, name.asString()) + .setExecutionProfile(readProfile)) .mapNotNull(row -> row.getSet(AUTHORIZED_USERS, String.class)) .flatMapIterable(set -> set) .map(Username::of); @@ -254,17 +271,20 @@ public Mono removeDelegatedToUser(Username baseUser, Username delegatedToU return executor.executeVoid(new BatchStatementBuilder(BatchType.LOGGED) .addStatement(removeAuthorizedUsersStatement.bind() .setString(NAME, delegatedToUser.asString()) - .setSet(AUTHORIZED_USERS, ImmutableSet.of(baseUser.asString()), String.class)) + .setSet(AUTHORIZED_USERS, ImmutableSet.of(baseUser.asString()), String.class) + .setExecutionProfile(writeProfile)) .addStatement(removeDelegatedToUsersStatement.bind() .setString(NAME, baseUser.asString()) - .setSet(DELEGATED_USERS, ImmutableSet.of(delegatedToUser.asString()), String.class)) + .setSet(DELEGATED_USERS, ImmutableSet.of(delegatedToUser.asString()), String.class) + .setExecutionProfile(writeProfile)) .build()); } public Flux getDelegatedToUsers(Username name) { return executor.executeSingleRow( getDelegatedToUsersStatement.bind() - .setString(NAME, name.asString())) + .setString(NAME, name.asString()) + .setExecutionProfile(readProfile)) .mapNotNull(row -> row.getSet(DELEGATED_USERS, String.class)) .flatMapIterable(set -> set) .map(Username::of); @@ -274,7 +294,8 @@ public Flux getDelegatedToUsers(Username name) { public void removeUser(Username name) throws UsersRepositoryException { boolean executed = executor.executeReturnApplied( removeUserStatement.bind() - .setString(NAME, name.asString())) + .setString(NAME, name.asString()) + .setExecutionProfile(writeProfile)) .block(); if (!executed) { @@ -294,7 +315,8 @@ public Publisher containsReactive(Username name) { @Override public int countUsers() { - return executor.executeSingleRow(countUserStatement.bind()) + return executor.executeSingleRow(countUserStatement.bind() + .setExecutionProfile(readProfile)) .map(row -> Ints.checkedCast(row.getLong(0))) .block(); } @@ -323,7 +345,8 @@ public void addUser(Username username, String password) throws UsersRepositoryEx .setString(NAME, user.getUserName().asString()) .setString(REALNAME, user.getUserName().asString()) .setString(PASSWORD, user.getHashedPassword()) - .setString(ALGORITHM, user.getHashAlgorithm().asString())) + .setString(ALGORITHM, user.getHashAlgorithm().asString()) + .setExecutionProfile(writeProfile)) .block(); if (!executed) { diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java index 3f6b8b80c8c..3556a2c00b1 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java @@ -30,12 +30,14 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.vacation.api.AccountId; import org.apache.james.vacation.api.RecipientId; import org.apache.james.vacation.cassandra.tables.CassandraNotificationTable; import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; import reactor.core.publisher.Mono; @@ -48,6 +50,8 @@ public class CassandraNotificationRegistryDAO { private final PreparedStatement registerWithTTLStatement; private final PreparedStatement isRegisteredStatement; private final PreparedStatement flushStatement; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraNotificationRegistryDAO(CqlSession session) { @@ -66,6 +70,8 @@ public CassandraNotificationRegistryDAO(CqlSession session) { this.flushStatement = session.prepare(deleteFrom(CassandraNotificationTable.TABLE_NAME) .whereColumn(CassandraNotificationTable.ACCOUNT_ID).isEqualTo(bindMarker(CassandraNotificationTable.ACCOUNT_ID)) .build()); + this.readProfile = ProfileLocator.READ.locateProfile(session, "VACATION-REGISTRY"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "VACATION-REGISTRY"); } private RegularInsert createInsert() { @@ -80,20 +86,23 @@ public Mono register(AccountId accountId, RecipientId recipientId, Optiona .map(value -> registerWithTTLStatement.bind().setInt(TTL, value)) .orElse(registerStatement.bind()) .setString(CassandraNotificationTable.ACCOUNT_ID, accountId.getIdentifier()) - .setString(CassandraNotificationTable.RECIPIENT_ID, recipientId.getAsString())); + .setString(CassandraNotificationTable.RECIPIENT_ID, recipientId.getAsString()) + .setExecutionProfile(writeProfile)); } public Mono isRegistered(AccountId accountId, RecipientId recipientId) { return cassandraAsyncExecutor.executeSingleRowOptional( isRegisteredStatement.bind() .setString(CassandraNotificationTable.ACCOUNT_ID, accountId.getIdentifier()) - .setString(CassandraNotificationTable.RECIPIENT_ID, recipientId.getAsString())) + .setString(CassandraNotificationTable.RECIPIENT_ID, recipientId.getAsString()) + .setExecutionProfile(readProfile)) .map(Optional::isPresent); } public Mono flush(AccountId accountId) { return cassandraAsyncExecutor.executeVoid( flushStatement.bind() - .setString(CassandraNotificationTable.ACCOUNT_ID, accountId.getIdentifier())); + .setString(CassandraNotificationTable.ACCOUNT_ID, accountId.getIdentifier()) + .setExecutionProfile(writeProfile)); } } diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java index 4255019406d..61b6e58cccf 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java @@ -35,6 +35,7 @@ import org.apache.james.backends.cassandra.init.CassandraTypesProvider; import org.apache.james.backends.cassandra.init.CassandraZonedDateTimeDataDefinition; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.util.ValuePatch; import org.apache.james.vacation.api.AccountId; import org.apache.james.vacation.api.Vacation; @@ -44,6 +45,7 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; import com.google.common.collect.ImmutableList; @@ -56,6 +58,8 @@ public class CassandraVacationDAO { private final PreparedStatement readStatement; private final UserDefinedType zonedDateTimeUserType; private final BiFunction insertGeneratorPipeline; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraVacationDAO(CqlSession session, CassandraTypesProvider cassandraTypesProvider) { @@ -77,6 +81,9 @@ public CassandraVacationDAO(CqlSession session, CassandraTypesProvider cassandra .stream() .reduce((vacation, insert) -> insert, (a, b) -> (vacation, insert) -> b.apply(vacation, a.apply(vacation, insert))); + + this.readProfile = ProfileLocator.READ.locateProfile(session, "VACATION"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "VACATION"); } public Mono modifyVacation(AccountId accountId, VacationPatch vacationPatch) { @@ -84,12 +91,14 @@ public Mono modifyVacation(AccountId accountId, VacationPatch vacationPatc createSpecificUpdate(vacationPatch, insertInto(CassandraVacationTable.TABLE_NAME) .value(CassandraVacationTable.ACCOUNT_ID, literal(accountId.getIdentifier()))) - .build()); + .build() + .setExecutionProfile(writeProfile)); } public Mono> retrieveVacation(AccountId accountId) { return cassandraAsyncExecutor.executeSingleRowOptional(readStatement.bind() - .setString(CassandraVacationTable.ACCOUNT_ID, accountId.getIdentifier())) + .setString(CassandraVacationTable.ACCOUNT_ID, accountId.getIdentifier()) + .setExecutionProfile(readProfile)) .map(optional -> optional.map(row -> Vacation.builder() .enabled(row.getBoolean(CassandraVacationTable.IS_ENABLED)) .fromDate(retrieveDate(row, CassandraVacationTable.FROM_DATE)) diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java index 4437a1bac37..df520c6a83e 100644 --- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java +++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java @@ -43,6 +43,7 @@ import jakarta.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.ProfileLocator; import org.apache.james.core.Username; import org.apache.james.jmap.api.change.TypeStateFactory; import org.apache.james.jmap.api.model.DeviceClientId; @@ -58,6 +59,7 @@ import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.google.common.collect.ImmutableSet; import reactor.core.publisher.Flux; @@ -74,6 +76,8 @@ public class CassandraPushSubscriptionDAO { private final PreparedStatement selectAll; private final PreparedStatement deleteOne; private final PreparedStatement deleteAll; + private final DriverExecutionProfile readProfile; + private final DriverExecutionProfile writeProfile; @Inject public CassandraPushSubscriptionDAO(CqlSession session, TypeStateFactory typeStateFactory) { @@ -106,6 +110,9 @@ public CassandraPushSubscriptionDAO(CqlSession session, TypeStateFactory typeSta .build()); this.typeStateFactory = typeStateFactory; + + this.readProfile = ProfileLocator.READ.locateProfile(session, "PUSH-SUBSCRIPTION"); + this.writeProfile = ProfileLocator.WRITE.locateProfile(session, "PUSH-SUBSCRIPTION"); } public Mono insert(Username username, PushSubscription subscription) { @@ -128,24 +135,26 @@ public Mono insert(Username username, PushSubscription subscri .ifPresent(keys -> insertSubscription.setString(ENCRYPT_PUBLIC_KEY, keys.p256dh()) .setString(ENCRYPT_AUTH_SECRET, keys.auth())); - return executor.executeVoid(insertSubscription.build()) + return executor.executeVoid(insertSubscription.build().setExecutionProfile(writeProfile)) .thenReturn(subscription); } public Flux selectAll(Username username) { - return executor.executeRows(selectAll.bind().setString(USER, username.asString())) + return executor.executeRows(selectAll.bind().setString(USER, username.asString()).setExecutionProfile(readProfile)) .map(this::toPushSubscription); } public Mono deleteOne(Username username, String deviceClientId) { return executor.executeVoid(deleteOne.bind() .setString(USER, username.asString()) - .setString(DEVICE_CLIENT_ID, deviceClientId)); + .setString(DEVICE_CLIENT_ID, deviceClientId) + .setExecutionProfile(writeProfile)); } public Mono deleteAll(Username username) { return executor.executeVoid(deleteAll.bind() - .setString(USER, username.asString())); + .setString(USER, username.asString()) + .setExecutionProfile(writeProfile)); } private PushSubscription toPushSubscription(Row row) { diff --git a/server/protocols/protocols-pop3-distributed/src/test/java/org/apache/james/pop3server/mailbox/task/MetaDataFixInconsistenciesServiceTest.java b/server/protocols/protocols-pop3-distributed/src/test/java/org/apache/james/pop3server/mailbox/task/MetaDataFixInconsistenciesServiceTest.java index 6a5af685869..1b0b611780e 100644 --- a/server/protocols/protocols-pop3-distributed/src/test/java/org/apache/james/pop3server/mailbox/task/MetaDataFixInconsistenciesServiceTest.java +++ b/server/protocols/protocols-pop3-distributed/src/test/java/org/apache/james/pop3server/mailbox/task/MetaDataFixInconsistenciesServiceTest.java @@ -169,7 +169,8 @@ void setUp(CassandraCluster cassandra) { cassandra.getTypesProvider(), CassandraBlobStoreFactory.forTesting(cassandra.getConf(), new RecordingMetricFactory()) .passthrough(), - new PlainBlobId.Factory()); + new PlainBlobId.Factory(), + CassandraConfiguration.DEFAULT_CONFIGURATION); testee = new MetaDataFixInconsistenciesService(imapUidDAO, pop3MetadataStore, cassandraMessageDAOV3); } diff --git a/server/protocols/webadmin/webadmin-pop3/src/test/java/org/apache/james/pop3/webadmin/Pop3MetaDataFixInconsistenciesRoutesTest.java b/server/protocols/webadmin/webadmin-pop3/src/test/java/org/apache/james/pop3/webadmin/Pop3MetaDataFixInconsistenciesRoutesTest.java index 76cef2dbdde..047765ec6e2 100644 --- a/server/protocols/webadmin/webadmin-pop3/src/test/java/org/apache/james/pop3/webadmin/Pop3MetaDataFixInconsistenciesRoutesTest.java +++ b/server/protocols/webadmin/webadmin-pop3/src/test/java/org/apache/james/pop3/webadmin/Pop3MetaDataFixInconsistenciesRoutesTest.java @@ -186,7 +186,8 @@ void setUp(CassandraCluster cassandra) { cassandra.getTypesProvider(), CassandraBlobStoreFactory.forTesting(cassandra.getConf(), new RecordingMetricFactory()) .passthrough(), - new PlainBlobId.Factory()); + new PlainBlobId.Factory(), + CassandraConfiguration.DEFAULT_CONFIGURATION); MetaDataFixInconsistenciesService fixInconsistenciesService = new MetaDataFixInconsistenciesService(imapUidDAO, pop3MetadataStore, cassandraMessageDAOV3); taskManager = new MemoryTaskManager(new Hostname("foo")); From b89ddc977095f1770924d5f6e70514286c6bfbd0 Mon Sep 17 00:00:00 2001 From: Benoit TELLIER Date: Wed, 25 Feb 2026 15:40:39 +0100 Subject: [PATCH 2/2] fixup! JAMES-4177 Finner grain management of Cassandra profiles --- .../cassandra/components/CassandraQuotaCurrentValueDao.java | 2 +- .../backends/cassandra/components/CassandraQuotaLimitDao.java | 2 +- .../apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java | 2 +- .../mailbox/cassandra/mail/CassandraApplicableFlagDAO.java | 2 +- .../james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java | 2 +- .../mailbox/cassandra/mail/CassandraDeletedMessageDAO.java | 2 +- .../james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java | 2 +- .../mailbox/cassandra/mail/CassandraMailboxCounterDAO.java | 2 +- .../james/mailbox/cassandra/mail/CassandraMailboxDAO.java | 2 +- .../mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java | 2 +- .../james/mailbox/cassandra/mail/CassandraMessageDAOV3.java | 2 +- .../james/mailbox/cassandra/mail/CassandraMessageIdDAO.java | 2 +- .../apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java | 2 +- .../james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java | 2 +- .../mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java | 2 +- .../apache/james/domainlist/cassandra/CassandraDomainList.java | 2 +- .../apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java | 2 +- .../james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java | 2 +- .../java/org/apache/james/user/cassandra/CassandraUsersDAO.java | 2 +- .../vacation/cassandra/CassandraNotificationRegistryDAO.java | 2 +- .../apache/james/vacation/cassandra/CassandraVacationDAO.java | 2 +- .../pushsubscription/CassandraPushSubscriptionDAO.java | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java index 21e7411ef6b..a835ecff112 100644 --- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java +++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaCurrentValueDao.java @@ -41,9 +41,9 @@ import org.slf4j.LoggerFactory; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.delete.Delete; import com.datastax.oss.driver.api.querybuilder.select.Select; import com.datastax.oss.driver.api.querybuilder.update.Update; diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java index d031f90bc2d..1d613f9555a 100644 --- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java +++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraQuotaLimitDao.java @@ -41,9 +41,9 @@ import org.apache.james.core.quota.QuotaType; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.delete.Delete; import com.datastax.oss.driver.api.querybuilder.insert.Insert; import com.datastax.oss.driver.api.querybuilder.select.Select; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java index 3522279dd38..b10dec93ebc 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java @@ -35,8 +35,8 @@ import org.apache.james.mailbox.model.MailboxACL; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.github.fge.lambdas.Throwing; import com.google.common.collect.ImmutableMap; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java index c5957d3274a..43a4ddfd181 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java @@ -38,8 +38,8 @@ import org.apache.james.mailbox.cassandra.table.Flag; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import reactor.core.publisher.Mono; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java index 3ab32e82218..995ba01bf94 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java @@ -51,9 +51,9 @@ import org.apache.james.util.DurationParser; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; import com.google.common.base.Preconditions; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java index 4316df72ec4..5c2bec77762 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java @@ -41,12 +41,12 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BatchStatement; import com.datastax.oss.driver.api.core.cql.BatchStatementBuilder; import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.google.common.collect.Lists; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java index 4bc51c71cf7..3024e8d552e 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java @@ -41,12 +41,12 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BatchStatement; import com.datastax.oss.driver.api.core.cql.BatchStatementBuilder; import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.metadata.schema.ClusteringOrder; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.google.common.collect.Lists; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java index 9bf196e9822..d0833a4f0fe 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java @@ -40,9 +40,9 @@ import org.apache.james.mailbox.model.MailboxCounters; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.PreparedStatement; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.querybuilder.update.Assignment; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java index 34ed01d4d26..6b92ed58faa 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java @@ -48,9 +48,9 @@ import org.apache.james.mailbox.model.UidValidity; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java index 6b75783699f..0ce0e36d9e7 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java @@ -39,12 +39,12 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BatchStatement; import com.datastax.oss.driver.api.core.cql.BatchStatementBuilder; import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.PreparedStatement; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.google.common.collect.Lists; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java index 5c666dbd39e..050cc18bf69 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3.java @@ -87,11 +87,11 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java index 499956432e7..f0ddb2eb2d8 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java @@ -75,12 +75,12 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.ProtocolVersion; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.metadata.schema.ClusteringOrder; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import com.google.common.annotations.VisibleForTesting; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java index da1b06f6ae2..6ea4ba3f49f 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java @@ -46,9 +46,9 @@ import org.apache.james.mailbox.model.ThreadId; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import reactor.core.publisher.Flux; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java index 92959ee35d6..2e4d9d13090 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadLookupDAO.java @@ -44,9 +44,9 @@ import org.apache.james.mailbox.model.ThreadId; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.codec.TypeCodec; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry; diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java index 7d8390dea61..8406e6ab96f 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java @@ -46,9 +46,9 @@ import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.github.fge.lambdas.Throwing; import reactor.core.publisher.Flux; diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java index 6f14d31d2b7..f3d7903e499 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java @@ -39,8 +39,8 @@ import org.apache.james.util.ReactorUtils; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.type.codec.TypeCodecs; import reactor.core.publisher.Mono; diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java index edef498ddc9..5415c06f950 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraMappingsSourcesDAO.java @@ -37,8 +37,8 @@ import org.apache.james.rrt.lib.MappingSource; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java index 6f2d15b6733..0663b08f076 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableDAO.java @@ -40,8 +40,8 @@ import org.apache.james.rrt.lib.MappingsImpl; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.google.common.collect.ImmutableList; import reactor.core.publisher.Flux; diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java index 6bb92d382fb..b448a426eae 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersDAO.java @@ -51,10 +51,10 @@ import org.reactivestreams.Publisher; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BatchStatementBuilder; import com.datastax.oss.driver.api.core.cql.BatchType; import com.datastax.oss.driver.api.core.cql.PreparedStatement; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java index 3556a2c00b1..8f75c9caa55 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraNotificationRegistryDAO.java @@ -36,8 +36,8 @@ import org.apache.james.vacation.cassandra.tables.CassandraNotificationTable; import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; import reactor.core.publisher.Mono; diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java index 61b6e58cccf..2e27907b36f 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/vacation/cassandra/CassandraVacationDAO.java @@ -43,9 +43,9 @@ import org.apache.james.vacation.cassandra.tables.CassandraVacationTable; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.type.UserDefinedType; import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; import com.google.common.collect.ImmutableList; diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java index df520c6a83e..0649c33e082 100644 --- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java +++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/pushsubscription/CassandraPushSubscriptionDAO.java @@ -56,10 +56,10 @@ import org.apache.james.jmap.api.model.VerificationCode; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; import com.google.common.collect.ImmutableSet; import reactor.core.publisher.Flux;