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 2021/05/17 02:21:47 UTC

[james-project] 04/11: [REFACTORING] Reactive StoreMessageIdManager::validateQuota

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 4f5d8c43f4ae83a1847476dea698428b8d8788fd
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu May 13 15:39:52 2021 +0700

    [REFACTORING] Reactive StoreMessageIdManager::validateQuota
    
    This ensures using StoreMessageIdManager::setInMailboxesReactive do
    not block for the purpose of quota validation for copy use cases.
---
 .../james/mailbox/store/StoreMessageIdManager.java | 60 +++++++++++++---------
 .../AbstractMessageIdManagerSideEffectTest.java    | 22 ++++----
 2 files changed, 49 insertions(+), 33 deletions(-)

diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java
index a7fa33b..b1ac262 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java
@@ -46,6 +46,7 @@ import org.apache.james.mailbox.RightManager;
 import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.exception.OverQuotaException;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.DeleteResult;
@@ -357,7 +358,7 @@ public class StoreMessageIdManager implements MessageIdManager {
                 .map(mailbox -> Pair.of(message, mailbox)))
             .collect(Guavate.toImmutableList());
 
-        return Mono.fromRunnable(Throwing.runnable(() -> validateQuota(messageMoves, mailboxMessage.get())).sneakyThrow())
+        return validateQuota(messageMoves, mailboxMessage.get())
             .then(Mono.fromRunnable(Throwing.runnable(() ->
                 addMessageToMailboxes(mailboxMessage.get(), messageMoves.addedMailboxes(), mailboxSession)).sneakyThrow()))
             .then(removeMessageFromMailboxes(mailboxMessage.get().getMessageId(), messagesToRemove, mailboxSession))
@@ -415,33 +416,44 @@ public class StoreMessageIdManager implements MessageIdManager {
         return Mono.empty();
     }
 
-    private void validateQuota(MessageMovesWithMailbox messageMoves, MailboxMessage mailboxMessage) throws MailboxException {
+    private Mono<Void> validateQuota(MessageMovesWithMailbox messageMoves, MailboxMessage mailboxMessage) {
         Map<QuotaRoot, Integer> messageCountByQuotaRoot = buildMapQuotaRoot(messageMoves);
-        for (Map.Entry<QuotaRoot, Integer> entry : messageCountByQuotaRoot.entrySet()) {
-            Integer additionalCopyCount = entry.getValue();
-            if (additionalCopyCount > 0) {
-                long additionalOccupiedSpace = additionalCopyCount * mailboxMessage.getFullContentOctets();
-                new QuotaChecker(quotaManager.getQuotas(entry.getKey()), entry.getKey())
-                    .tryAddition(additionalCopyCount, additionalOccupiedSpace);
-            }
-        }
+
+        return Flux.fromIterable(messageCountByQuotaRoot.entrySet())
+            .filter(entry -> entry.getValue() > 0)
+            .flatMap(entry -> Mono.from(quotaManager.getQuotasReactive(entry.getKey()))
+                .map(quotas -> new QuotaChecker(quotas, entry.getKey()))
+                .handle((quotaChecker, sink) -> {
+                    Integer additionalCopyCount = entry.getValue();
+                    long additionalOccupiedSpace = additionalCopyCount * mailboxMessage.getFullContentOctets();
+                    try {
+                        quotaChecker.tryAddition(additionalCopyCount, additionalOccupiedSpace);
+                    } catch (OverQuotaException e) {
+                        sink.error(e);
+                    }
+                }))
+            .then();
     }
 
-    private Map<QuotaRoot, Integer> buildMapQuotaRoot(MessageMovesWithMailbox messageMoves) throws MailboxException {
-        Map<QuotaRoot, Integer> messageCountByQuotaRoot = new HashMap<>();
-        for (Mailbox mailbox : messageMoves.addedMailboxes()) {
-            QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailbox);
-            int currentCount = Optional.ofNullable(messageCountByQuotaRoot.get(quotaRoot))
-                .orElse(0);
-            messageCountByQuotaRoot.put(quotaRoot, currentCount + 1);
-        }
-        for (Mailbox mailbox : messageMoves.removedMailboxes()) {
-            QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailbox);
-            int currentCount = Optional.ofNullable(messageCountByQuotaRoot.get(quotaRoot))
-                .orElse(0);
-            messageCountByQuotaRoot.put(quotaRoot, currentCount - 1);
+    private Map<QuotaRoot, Integer> buildMapQuotaRoot(MessageMovesWithMailbox messageMoves) {
+        try {
+            Map<QuotaRoot, Integer> messageCountByQuotaRoot = new HashMap<>();
+            for (Mailbox mailbox : messageMoves.addedMailboxes()) {
+                QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailbox);
+                int currentCount = Optional.ofNullable(messageCountByQuotaRoot.get(quotaRoot))
+                    .orElse(0);
+                messageCountByQuotaRoot.put(quotaRoot, currentCount + 1);
+            }
+            for (Mailbox mailbox : messageMoves.removedMailboxes()) {
+                QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailbox);
+                int currentCount = Optional.ofNullable(messageCountByQuotaRoot.get(quotaRoot))
+                    .orElse(0);
+                messageCountByQuotaRoot.put(quotaRoot, currentCount - 1);
+            }
+            return messageCountByQuotaRoot;
+        } catch (MailboxException e) {
+            throw new RuntimeException(e);
         }
-        return messageCountByQuotaRoot;
     }
 
     private void addMessageToMailboxes(MailboxMessage mailboxMessage, Set<Mailbox> mailboxes, MailboxSession mailboxSession) throws MailboxException {
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java
index a6011de..1c86c65 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java
@@ -56,7 +56,6 @@ import org.apache.james.mailbox.events.MailboxEvents.Expunged;
 import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
 import org.apache.james.mailbox.events.MailboxEvents.MailboxEvent;
 import org.apache.james.mailbox.events.MessageMoveEvent;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.OverQuotaException;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.fixture.MailboxFixture;
@@ -115,6 +114,11 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         eventCollector = new EventCollector();
         quotaManager = mock(QuotaManager.class);
 
+        when(quotaManager.getQuotasReactive(any(QuotaRoot.class)))
+            .thenReturn(Mono.just(new QuotaManager.Quotas(
+                Quota.<QuotaCountLimit, QuotaCountUsage>builder().used(QuotaCountUsage.count(102)).computedLimit(QuotaCountLimit.unlimited()).build(),
+                Quota.<QuotaSizeLimit, QuotaSizeUsage>builder().used(QuotaSizeUsage.size(2)).computedLimit(QuotaSizeLimit.unlimited()).build())));
+
         session = MailboxSessionUtil.create(ALICE);
         setupMockForPreDeletionHooks();
         testingData = createTestSystem(quotaManager, eventBus, ImmutableSet.of(preDeletionHook1, preDeletionHook2));
@@ -382,13 +386,13 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
     }
 
     @Test
-    void setInMailboxesShouldThrowExceptionWhenOverQuota() throws Exception {
+    void setInMailboxesShouldThrowExceptionWhenOverQuota() {
         MessageId messageId = testingData.persist(mailbox1.getMailboxId(), messageUid1, FLAGS, session);
 
-        when(quotaManager.getQuotas(any(QuotaRoot.class)))
-            .thenReturn(new QuotaManager.Quotas(
+        when(quotaManager.getQuotasReactive(any(QuotaRoot.class)))
+            .thenReturn(Mono.just(new QuotaManager.Quotas(
                 OVER_QUOTA,
-                Quota.<QuotaSizeLimit, QuotaSizeUsage>builder().used(QuotaSizeUsage.size(2)).computedLimit(QuotaSizeLimit.unlimited()).build()));
+                Quota.<QuotaSizeLimit, QuotaSizeUsage>builder().used(QuotaSizeUsage.size(2)).computedLimit(QuotaSizeLimit.unlimited()).build())));
 
         assertThatThrownBy(() -> messageIdManager.setInMailboxes(messageId,
                 ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()),
@@ -553,10 +557,10 @@ public abstract class AbstractMessageIdManagerSideEffectTest {
         assertThat(eventCollector.getEvents()).isEmpty();
     }
 
-    protected void givenUnlimitedQuota() throws MailboxException {
-        when(quotaManager.getQuotas(any(QuotaRoot.class)))
-            .thenReturn(new QuotaManager.Quotas(
+    protected void givenUnlimitedQuota() {
+        when(quotaManager.getQuotasReactive(any(QuotaRoot.class)))
+            .thenReturn(Mono.just(new QuotaManager.Quotas(
                 Quota.<QuotaCountLimit, QuotaCountUsage>builder().used(QuotaCountUsage.count(2)).computedLimit(QuotaCountLimit.unlimited()).build(),
-                Quota.<QuotaSizeLimit, QuotaSizeUsage>builder().used(QuotaSizeUsage.size(2)).computedLimit(QuotaSizeLimit.unlimited()).build()));
+                Quota.<QuotaSizeLimit, QuotaSizeUsage>builder().used(QuotaSizeUsage.size(2)).computedLimit(QuotaSizeLimit.unlimited()).build())));
     }
 }

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