This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit db67bdfc5623a09b88c4c8a9763a35174a420e86 Author: Matthieu Baechler <matth...@apache.org> AuthorDate: Tue Jun 16 17:42:30 2020 +0200 JAMES-3177 make use of a persistent datastructure to avoid most locking in UidMsnConverter Leveraging vavr here helps a lot but the caller is not ready yet to handle an immutable UidMsnConverter. Next step is to ensure locking when calling mutation method on UidMsnConverter and removing locks --- protocols/imap/pom.xml | 4 ++ .../james/imap/processor/base/UidMsnConverter.java | 83 ++++++++-------------- .../imap/processor/base/UidMsnConverterTest.java | 23 +++--- 3 files changed, 47 insertions(+), 63 deletions(-) diff --git a/protocols/imap/pom.xml b/protocols/imap/pom.xml index b6930eb..a8dc191 100644 --- a/protocols/imap/pom.xml +++ b/protocols/imap/pom.xml @@ -91,6 +91,10 @@ <artifactId>javax.mail</artifactId> </dependency> <dependency> + <groupId>io.vavr</groupId> + <artifactId>vavr</artifactId> + </dependency> + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java index fc7b114..1850db5 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java @@ -19,97 +19,70 @@ package org.apache.james.imap.processor.base; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Optional; -import java.util.TreeSet; +import java.util.function.Function; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.NullableMessageSequenceNumber; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; -public class UidMsnConverter { +import io.vavr.collection.TreeSet; - public static final int FIRST_MSN = 1; +public class UidMsnConverter { - @VisibleForTesting final ArrayList<MessageUid> uids; + @VisibleForTesting TreeSet<MessageUid> uids; public UidMsnConverter() { - this.uids = Lists.newArrayList(); + this.uids = TreeSet.empty(); } - public synchronized void addAll(List<MessageUid> addedUids) { - TreeSet<MessageUid> tmp = new TreeSet<>(); - tmp.addAll(uids); - tmp.addAll(addedUids); - uids.clear(); - uids.addAll(tmp); + public synchronized void addAll(java.util.List<MessageUid> addedUids) { + uids = uids.addAll(addedUids); } - public synchronized NullableMessageSequenceNumber getMsn(MessageUid uid) { - int position = Collections.binarySearch(uids, uid); - if (position < 0) { - return NullableMessageSequenceNumber.noMessage(); - } - return NullableMessageSequenceNumber.of(position + 1); + public NullableMessageSequenceNumber getMsn(MessageUid uid) { + return uids + .zipWithIndex() + .toMap(Function.identity()) + .get(uid) + .map(position -> NullableMessageSequenceNumber.of(position + 1)) + .getOrElse(NullableMessageSequenceNumber.noMessage()); } - public synchronized Optional<MessageUid> getUid(int msn) { - if (msn <= uids.size() && msn > 0) { - return Optional.of(uids.get(msn - 1)); - } - return Optional.empty(); + public Optional<MessageUid> getUid(int msn) { + return uids + .drop(msn - 1) + .headOption() + .toJavaOptional(); } - public synchronized Optional<MessageUid> getLastUid() { - if (uids.isEmpty()) { - return Optional.empty(); - } - return getUid(getLastMsn()); + public Optional<MessageUid> getLastUid() { + return uids.lastOption().toJavaOptional(); } - public synchronized Optional<MessageUid> getFirstUid() { - return getUid(FIRST_MSN); + public Optional<MessageUid> getFirstUid() { + return uids.headOption().toJavaOptional(); } - public synchronized int getNumMessage() { + public int getNumMessage() { return uids.size(); } public synchronized void remove(MessageUid uid) { - uids.remove(uid); + uids = uids.remove(uid); } - public synchronized boolean isEmpty() { + public boolean isEmpty() { return uids.isEmpty(); } public synchronized void clear() { - uids.clear(); + uids = TreeSet.empty(); } public synchronized void addUid(MessageUid uid) { - if (uids.contains(uid)) { - return; - } - if (isLastUid(uid)) { - uids.add(uid); - } else { - uids.add(uid); - Collections.sort(uids); - } + uids = uids.add(uid); } - private boolean isLastUid(MessageUid uid) { - Optional<MessageUid> lastUid = getLastUid(); - return !lastUid.isPresent() || - lastUid.get().compareTo(uid) < 0; - } - - private int getLastMsn() { - return getNumMessage(); - } } diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java index 438db40..78b8b3f 100644 --- a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java +++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java @@ -33,6 +33,8 @@ import org.junit.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import io.vavr.Tuple; + public class UidMsnConverterTest { private UidMsnConverter testee; private MessageUid messageUid1; @@ -62,11 +64,20 @@ public class UidMsnConverterTest { } @Test - public void getUidShouldTheCorrespondingUidIfItExist() { + public void getUidShouldReturnEmptyIfOutOfRange() { testee.addUid(messageUid1); + testee.addUid(messageUid2); - assertThat(testee.getUid(1)) - .contains(messageUid1); + assertThat(testee.getUid(50)) + .isEmpty(); + } + + @Test + public void getUidShouldReturnTheCorrespondingUidIfItExist() { + testee.addAll(ImmutableList.of(messageUid1, messageUid2)); + + assertThat(testee.getUid(2)) + .contains(messageUid2); } @Test @@ -447,11 +458,7 @@ public class UidMsnConverterTest { } private Map<Integer, MessageUid> mapTesteeInternalDataToMsnByUid() { - ImmutableMap.Builder<Integer, MessageUid> result = ImmutableMap.builder(); - for (int i = 0; i < testee.uids.size(); i++) { - result.put(i + 1, testee.uids.get(i)); - } - return result.build(); + return testee.uids.zipWithIndex().toMap(input -> Tuple.of(input._2 + 1, input._1)).toJavaMap(); } } \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org