This is an automated email from the ASF dual-hosted git repository. chibenwa pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit ac6030595d14d772b7c3787f2d50e7f1c2f582d3 Author: Benoit TELLIER <[email protected]> AuthorDate: Wed Jun 17 09:58:05 2026 +0200 [FIX] Cassandra folder rename: use SERIAL for initial picture Improve overall atomicity Please note that we do not address TOCTOU races. We also do not need serial for destination mailbix as it is gated by an idempotent DELETE...IF NOT EXIST --- .../james/mailbox/cassandra/CassandraMailboxManager.java | 13 +++++++++++++ .../mailbox/cassandra/mail/CassandraMailboxMapper.java | 13 +++++-------- .../org/apache/james/mailbox/store/StoreMailboxManager.java | 6 +++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java index fe1dac1827..51ee7225a9 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java @@ -24,24 +24,29 @@ import java.util.EnumSet; import jakarta.inject.Inject; +import org.apache.james.backends.cassandra.init.configuration.JamesExecutionProfiles; import org.apache.james.events.EventBus; import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.MailboxPathLocker; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.SessionProvider; +import org.apache.james.mailbox.cassandra.mail.CassandraMailboxMapper; import org.apache.james.mailbox.model.Mailbox; import org.apache.james.mailbox.model.MessageId; +import org.apache.james.mailbox.model.search.MailboxQuery; import org.apache.james.mailbox.store.MailboxManagerConfiguration; import org.apache.james.mailbox.store.PreDeletionHooks; import org.apache.james.mailbox.store.StoreMailboxAnnotationManager; import org.apache.james.mailbox.store.StoreMailboxManager; import org.apache.james.mailbox.store.StoreMessageManager; import org.apache.james.mailbox.store.StoreRightManager; +import org.apache.james.mailbox.store.mail.MailboxMapper; import org.apache.james.mailbox.store.mail.ThreadIdGuessingAlgorithm; import org.apache.james.mailbox.store.mail.model.impl.MessageParser; import org.apache.james.mailbox.store.quota.QuotaComponents; import org.apache.james.mailbox.store.search.MessageSearchIndex; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** @@ -118,4 +123,12 @@ public class CassandraMailboxManager extends StoreMailboxManager { public <T> Mono<T> manageProcessing(Mono<T> toBeWrapped, MailboxSession mailboxSession) { return toBeWrapped; } + + @Override + protected Flux<Mailbox> getMailboxWithPathLikeUponRename(MailboxMapper mapper, MailboxQuery.UserBound query) { + if (mapper instanceof CassandraMailboxMapper cassandraMailboxMapper) { + return cassandraMailboxMapper.findMailboxWithPathLike(query, JamesExecutionProfiles.ConsistencyChoice.STRONG); + } + return super.getMailboxWithPathLikeUponRename(mapper, query); + } } diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java index b5fd64291e..125d142781 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java @@ -192,18 +192,15 @@ public class CassandraMailboxMapper implements MailboxMapper { @Override public Flux<Mailbox> findMailboxWithPathLike(MailboxQuery.UserBound query) { - String fixedNamespace = query.getFixedNamespace(); - Username fixedUser = query.getFixedUser(); + return findMailboxWithPathLike(query, consistencyChoice()); + } - return performReadRepair(listMailboxes(fixedNamespace, fixedUser)) + public Flux<Mailbox> findMailboxWithPathLike(MailboxQuery.UserBound query, JamesExecutionProfiles.ConsistencyChoice consistencyChoice) { + return performReadRepair(mailboxPathV3DAO.listUserMailboxes(query.getFixedNamespace(), query.getFixedUser(), consistencyChoice)) .filter(mailbox -> query.isPathMatch(mailbox.generateAssociatedPath())) .flatMap(this::addAcl, CONCURRENCY); } - private Flux<Mailbox> listMailboxes(String fixedNamespace, Username fixedUser) { - return mailboxPathV3DAO.listUserMailboxes(fixedNamespace, fixedUser, consistencyChoice()); - } - @Override public Mono<Mailbox> create(MailboxPath mailboxPath, UidValidity uidValidity) { CassandraId cassandraId = CassandraId.timeBased(); @@ -254,7 +251,7 @@ public class CassandraMailboxMapper implements MailboxMapper { @Override public Mono<Boolean> hasChildren(Mailbox mailbox, char delimiter) { - return performReadRepair(listMailboxes(mailbox.getNamespace(), mailbox.getUser())) + return performReadRepair(mailboxPathV3DAO.listUserMailboxes(mailbox.getNamespace(), mailbox.getUser(), consistencyChoice())) .filter(idAndPath -> isPathChildOfMailbox(idAndPath, mailbox, delimiter)) .hasElements(); } diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java index 4f6912cb01..64a66db2de 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java @@ -633,7 +633,7 @@ public class StoreMailboxManager implements MailboxManager { .asUserBound(); return assertCanDeleteWhenRename(fromSession, from) - .then(mapper.findMailboxWithPathLike(query) + .then(getMailboxWithPathLikeUponRename(mapper, query) .filter(mailbox -> mailbox.generateAssociatedPath().getHierarchyLevels(fromSession.getPathDelimiter()).contains(from)) .sort(Comparator.comparing(mailbox -> mailbox.generateAssociatedPath().getHierarchyLevels(fromSession.getPathDelimiter()).size())) .collectList() @@ -646,6 +646,10 @@ public class StoreMailboxManager implements MailboxManager { })); } + protected Flux<Mailbox> getMailboxWithPathLikeUponRename(MailboxMapper mapper, MailboxQuery.UserBound query) { + return mapper.findMailboxWithPathLike(query); + } + private Mono<List<MailboxRenamedResult>> renameSubscriptionsIfNeeded(List<MailboxRenamedResult> renamedResults, RenameOption option, MailboxSession fromSession, MailboxSession toSession) { if (option == RenameOption.RENAME_SUBSCRIPTIONS) { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
