You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2023/06/13 02:54:52 UTC

[james-project] 02/02: JAMES-3911 JPA: Prevent concurrent operations on the same EntityManager

This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 25db4645440f6e50c4b471a414e11cff6dcf9c1b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Jun 9 18:41:57 2023 +0700

    JAMES-3911 JPA: Prevent concurrent operations on the same EntityManager
---
 .../mailbox/jpa/openjpa/OpenJPAMessageManager.java | 37 +++++++++++++++++++++-
 .../james/mailbox/store/StoreMailboxManager.java   |  2 +-
 .../james/mailbox/store/StoreMessageManager.java   | 10 +++---
 3 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
index 567e8d5ac6..7226fb046a 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
@@ -20,14 +20,18 @@
 package org.apache.james.mailbox.jpa.openjpa;
 
 import java.time.Clock;
+import java.util.EnumSet;
 
 import javax.mail.Flags;
 
 import org.apache.james.events.EventBus;
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.Mailbox;
+import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.UidValidity;
 import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
 import org.apache.james.mailbox.store.BatchSizes;
@@ -37,23 +41,35 @@ import org.apache.james.mailbox.store.PreDeletionHooks;
 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.MessageMapper;
 import org.apache.james.mailbox.store.mail.ThreadIdGuessingAlgorithm;
 import org.apache.james.mailbox.store.search.MessageSearchIndex;
 
+import com.github.fge.lambdas.Throwing;
+
+import reactor.core.publisher.Mono;
+
 /**
  * OpenJPA implementation of Mailbox
  */
 public class OpenJPAMessageManager extends StoreMessageManager {
+    private final MailboxSessionMapperFactory mapperFactory;
+    private final StoreRightManager storeRightManager;
+    private final Mailbox mailbox;
 
     public OpenJPAMessageManager(MailboxSessionMapperFactory mapperFactory,
                                  MessageSearchIndex index, EventBus eventBus,
                                  MailboxPathLocker locker, Mailbox mailbox,
                                  QuotaManager quotaManager, QuotaRootResolver quotaRootResolver,
                                  MessageId.Factory messageIdFactory, BatchSizes batchSizes,
-                                 StoreRightManager storeRightManager, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, Clock clock) {
+                                 StoreRightManager storeRightManager, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm,
+                                 Clock clock) {
         super(StoreMailboxManager.DEFAULT_NO_MESSAGE_CAPABILITIES, mapperFactory, index, eventBus, locker, mailbox,
             quotaManager, quotaRootResolver, batchSizes, storeRightManager, PreDeletionHooks.NO_PRE_DELETION_HOOK,
             new MessageStorer.WithoutAttachment(mapperFactory, messageIdFactory, new OpenJPAMessageFactory(OpenJPAMessageFactory.AdvancedFeature.None), threadIdGuessingAlgorithm, clock));
+        this.storeRightManager = storeRightManager;
+        this.mapperFactory = mapperFactory;
+        this.mailbox = mailbox;
     }
 
     /**
@@ -65,4 +81,23 @@ public class OpenJPAMessageManager extends StoreMessageManager {
         flags.add(Flags.Flag.USER);
         return flags;
     }
+
+    public Mono<MailboxMetaData> getMetaDataReactive(MailboxMetaData.RecentMode recentMode, MailboxSession mailboxSession, EnumSet<MailboxMetaData.Item> items) throws MailboxException {
+        MailboxACL resolvedAcl = getResolvedAcl(mailboxSession);
+        if (!storeRightManager.hasRight(mailbox, MailboxACL.Right.Read, mailboxSession)) {
+            return Mono.just(MailboxMetaData.sensibleInformationFree(resolvedAcl, getMailboxEntity().getUidValidity(), isWriteable(mailboxSession)));
+        }
+        Flags permanentFlags = getPermanentFlags(mailboxSession);
+        UidValidity uidValidity = getMailboxEntity().getUidValidity();
+        MessageMapper messageMapper = mapperFactory.getMessageMapper(mailboxSession);
+
+        return messageMapper.executeReactive(
+            nextUid(messageMapper, items)
+                .flatMap(nextUid -> highestModSeq(messageMapper, items)
+                    .flatMap(highestModSeq -> firstUnseen(messageMapper, items)
+                        .flatMap(Throwing.function(firstUnseen -> recent(recentMode, mailboxSession)
+                            .flatMap(recents -> mailboxCounters(messageMapper, items)
+                                .map(counters -> new MailboxMetaData(recents, permanentFlags, uidValidity, nextUid, highestModSeq, counters.getCount(),
+                                    counters.getUnseen(), firstUnseen.orElse(null), isWriteable(mailboxSession), resolvedAcl))))))));
+    }
 }
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 5c530d907f..e1d272c5f8 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
@@ -658,7 +658,7 @@ public class StoreMailboxManager implements MailboxManager {
                 return mailboxId;
             })
             .then(Mono.from(locker.executeReactiveWithLockReactive(from, mapper.findMailboxWithPathLike(query)
-                    .flatMap(sub -> {
+                    .concatMap(sub -> {
                         String subOriginalName = sub.getName();
                         String subNewName = newMailboxPath.getName() + subOriginalName.substring(from.getName().length());
                         MailboxPath fromPath = new MailboxPath(from, subOriginalName);
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
index 8ef76f2931..a5fe322689 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
@@ -594,14 +594,14 @@ public class StoreMessageManager implements MessageManager {
                 t5.getT4().getUnseen(), t5.getT3().orElse(null), isWriteable(mailboxSession), resolvedAcl)));
     }
 
-    private Mono<ModSeq> highestModSeq(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
+    protected Mono<ModSeq> highestModSeq(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
         if (items.contains(MailboxMetaData.Item.HighestModSeq)) {
             return messageMapper.getHighestModSeqReactive(mailbox);
         }
         return Mono.just(ModSeq.first());
     }
 
-    private Mono<MessageUid> nextUid(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
+    protected Mono<MessageUid> nextUid(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
         if (items.contains(MailboxMetaData.Item.NextUid)) {
             return messageMapper.getLastUidReactive(mailbox)
                 .map(optional -> optional
@@ -611,14 +611,14 @@ public class StoreMessageManager implements MessageManager {
         return Mono.just(MessageUid.MIN_VALUE);
     }
 
-    private Mono<Optional<MessageUid>> firstUnseen(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
+    protected Mono<Optional<MessageUid>> firstUnseen(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
         if (items.contains(MailboxMetaData.Item.FirstUnseen)) {
             return messageMapper.findFirstUnseenMessageUidReactive(getMailboxEntity());
         }
         return Mono.just(Optional.empty());
     }
 
-    private Mono<MailboxCounters> mailboxCounters(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
+    protected Mono<MailboxCounters> mailboxCounters(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) {
         if (items.contains(MailboxMetaData.Item.MailboxCounters)) {
             return messageMapper.getMailboxCountersReactive(getMailboxEntity());
         }
@@ -777,7 +777,7 @@ public class StoreMessageManager implements MessageManager {
      * Return a List which holds all uids of recent messages and optional reset
      * the recent flag on the messages for the uids
      */
-    private Mono<List<MessageUid>> recent(RecentMode recentMode, MailboxSession mailboxSession) throws MailboxException {
+    protected Mono<List<MessageUid>> recent(RecentMode recentMode, MailboxSession mailboxSession) throws MailboxException {
         MessageMapper messageMapper = mapperFactory.getMessageMapper(mailboxSession);
 
         switch (recentMode) {


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org