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/11/10 02:47:27 UTC
(james-project) branch master updated: JAMES-3960 Hints to ensure UID/ModSeq consistency in case of disaster
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
The following commit(s) were added to refs/heads/master by this push:
new 8d95aec8f4 JAMES-3960 Hints to ensure UID/ModSeq consistency in case of disaster
8d95aec8f4 is described below
commit 8d95aec8f4bf9448b819c14d94ffc706c5997bbc
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Wed Nov 8 18:08:19 2023 +0100
JAMES-3960 Hints to ensure UID/ModSeq consistency in case of disaster
---
.../init/configuration/CassandraConfiguration.java | 32 +++++++++++++++++++---
.../java/org/apache/james/mailbox/MessageUid.java | 4 +++
.../main/java/org/apache/james/mailbox/ModSeq.java | 4 +++
.../cassandra/mail/CassandraModSeqProvider.java | 9 ++++--
.../cassandra/mail/CassandraUidProvider.java | 8 ++++--
.../mail/CassandraModSeqProviderTest.java | 30 +++++++++++++++++++-
.../cassandra/mail/CassandraUidProviderTest.java | 32 +++++++++++++++++++---
.../sample-configuration/cassandra.properties | 6 +++-
.../modules/ROOT/pages/configure/cassandra.adoc | 4 +++
.../sample-configuration/cassandra.properties | 6 +++-
.../james/DistributedPOP3JamesServerMain.java | 1 -
src/site/xdoc/server/config-cassandra.xml | 3 ++
12 files changed, 122 insertions(+), 17 deletions(-)
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java
index b1a7fcc55e..9346821aaa 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java
@@ -83,6 +83,7 @@ public class CassandraConfiguration {
private static final String OPTIMISTIC_CONSISTENCY_LEVEL = "optimistic.consistency.level.enabled";
private static final String MAIL_REPOSITORY_STRONG_CONSISTENCY = "mailrepository.strong.consistency";
private static final String ACL_ENABLED = "acl.enabled";
+ private static final String UID_MODSEQ_INCREMENT = "uid.modseq.increment";
public static final CassandraConfiguration DEFAULT_CONFIGURATION = builder().build();
@@ -110,6 +111,7 @@ public class CassandraConfiguration {
private Optional<Boolean> optimisticConsistencyLevel = Optional.empty();
private Optional<Boolean> mailRepositoryStrongConsistency = Optional.empty();
private Optional<Boolean> aclEnabled = Optional.empty();
+ private Optional<Integer> uidModseqIncrement = Optional.empty();
public Builder mailboxReadStrongConsistency(boolean value) {
this.mailboxReadStrongConsistency = Optional.of(value);
@@ -162,6 +164,17 @@ public class CassandraConfiguration {
return this;
}
+ public Builder uidModseqIncrement(int value) {
+ Preconditions.checkArgument(value > 0, "uidModseqIncrement needs to be strictly positive");
+ this.uidModseqIncrement = Optional.of(value);
+ return this;
+ }
+
+ public Builder uidModseqIncrement(Optional<Integer> value) {
+ value.ifPresent(this::uidModseqIncrement);
+ return this;
+ }
+
public Builder flagsUpdateMessageIdMaxRetry(int value) {
Preconditions.checkArgument(value > 0, "flagsUpdateMessageIdMaxRetry needs to be strictly positive");
this.flagsUpdateMessageIdMaxRetry = Optional.of(value);
@@ -372,7 +385,8 @@ public class CassandraConfiguration {
mailRepositoryStrongConsistency.orElse(DEFAULT_MAIL_REPOSITORY_STRONG_CONSISTENCY),
uidReadStrongConsistency.orElse(DEFAULT_STRONG_CONSISTENCY),
modseqReadStrongConsistency.orElse(DEFAULT_STRONG_CONSISTENCY),
- aclEnabled.orElse(true));
+ aclEnabled.orElse(true),
+ uidModseqIncrement.orElse(0));
}
}
@@ -427,6 +441,7 @@ public class CassandraConfiguration {
.mailRepositoryStrongConsistency(Optional.ofNullable(
propertiesConfiguration.getBoolean(MAIL_REPOSITORY_STRONG_CONSISTENCY, null)))
.aclEnabled(Optional.ofNullable(propertiesConfiguration.getBoolean(ACL_ENABLED, null)))
+ .uidModseqIncrement(Optional.ofNullable(propertiesConfiguration.getInteger(UID_MODSEQ_INCREMENT, null)))
.build();
}
@@ -453,6 +468,7 @@ public class CassandraConfiguration {
private final boolean uidReadStrongConsistency;
private final boolean modseqReadStrongConsistency;
private final boolean aclEnabled;
+ private final int uidModseqIncrement;
@VisibleForTesting
CassandraConfiguration(int aclMaxRetry, int expungeChunkSize,
@@ -464,7 +480,8 @@ public class CassandraConfiguration {
float mailboxCountersReadRepairChanceOneHundred, boolean mailboxReadStrongConsistency,
boolean messageReadStrongConsistency, boolean messageWriteStrongConsistency,
boolean optimisticConsistencyLevel, boolean mailRepositoryStrongConsistency,
- boolean uidReadStrongConsistency, boolean modseqReadStrongConsistency, boolean aclEnabled) {
+ boolean uidReadStrongConsistency, boolean modseqReadStrongConsistency, boolean aclEnabled,
+ int uidModseqIncrement) {
this.aclMaxRetry = aclMaxRetry;
this.expungeChunkSize = expungeChunkSize;
this.flagsUpdateMessageIdMaxRetry = flagsUpdateMessageIdMaxRetry;
@@ -488,6 +505,7 @@ public class CassandraConfiguration {
this.uidReadStrongConsistency = uidReadStrongConsistency;
this.modseqReadStrongConsistency = modseqReadStrongConsistency;
this.aclEnabled = aclEnabled;
+ this.uidModseqIncrement = uidModseqIncrement;
}
public boolean isUidReadStrongConsistency() {
@@ -582,6 +600,10 @@ public class CassandraConfiguration {
return aclEnabled;
}
+ public int getUidModseqIncrement() {
+ return uidModseqIncrement;
+ }
+
@Override
public final boolean equals(Object o) {
if (o instanceof CassandraConfiguration) {
@@ -609,7 +631,8 @@ public class CassandraConfiguration {
&& Objects.equals(this.uidReadStrongConsistency, that.uidReadStrongConsistency)
&& Objects.equals(this.modseqReadStrongConsistency, that.modseqReadStrongConsistency)
&& Objects.equals(this.mailRepositoryStrongConsistency, that.mailRepositoryStrongConsistency)
- && Objects.equals(this.aclEnabled, that.aclEnabled);
+ && Objects.equals(this.aclEnabled, that.aclEnabled)
+ && Objects.equals(this.uidModseqIncrement, that.uidModseqIncrement);
}
return false;
}
@@ -623,7 +646,7 @@ public class CassandraConfiguration {
consistencyLevelRegular, consistencyLevelLightweightTransaction, mailboxReadRepair,
messageReadStrongConsistency, mailboxReadStrongConsistency, messageWriteStrongConsistency,
optimisticConsistencyLevel, mailRepositoryStrongConsistency, uidReadStrongConsistency,
- modseqReadStrongConsistency, aclEnabled);
+ modseqReadStrongConsistency, aclEnabled, uidModseqIncrement);
}
@Override
@@ -652,6 +675,7 @@ public class CassandraConfiguration {
.add("modseqReadStrongConsistency", modseqReadStrongConsistency)
.add("uidReadStrongConsistency", uidReadStrongConsistency)
.add("aclEnabled", aclEnabled)
+ .add("uidModseqIncrement", uidModseqIncrement)
.toString();
}
}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java
index c598dd21fa..daf210bc10 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java
@@ -50,6 +50,10 @@ public class MessageUid implements Comparable<MessageUid> {
public long asLong() {
return uid;
}
+
+ public MessageUid add(int offset) {
+ return MessageUid.of(uid + offset);
+ }
@Override
public int hashCode() {
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/ModSeq.java b/mailbox/api/src/main/java/org/apache/james/mailbox/ModSeq.java
index b4bd08613f..92020abdab 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/ModSeq.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/ModSeq.java
@@ -53,6 +53,10 @@ public class ModSeq implements Comparable<ModSeq> {
return this.equals(ModSeq.first());
}
+ public ModSeq add(int offset) {
+ return ModSeq.of(modSeq + offset);
+ }
+
@Override
public int compareTo(ModSeq o) {
return Long.compare(modSeq, o.modSeq);
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 4aeca8e044..7bcabe9b2f 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
@@ -152,7 +152,8 @@ public class CassandraModSeqProvider implements ModSeqProvider {
public ModSeq highestModSeq(MailboxId mailboxId) throws MailboxException {
return unbox(() -> findHighestModSeq((CassandraId) mailboxId,
Optional.of(lwtProfile).filter(any -> cassandraConfiguration.isUidReadStrongConsistency()))
- .block().orElse(ModSeq.first()));
+ .block().orElse(ModSeq.first()))
+ .add(cassandraConfiguration.getUidModseqIncrement());
}
private Mono<Optional<ModSeq>> findHighestModSeq(CassandraId mailboxId, Optional<DriverExecutionProfile> executionProfile) {
@@ -200,12 +201,14 @@ public class CassandraModSeqProvider implements ModSeqProvider {
.map(highestModSeq -> tryUpdateModSeq(cassandraId, highestModSeq))
.orElseGet(() -> tryInsertModSeq(cassandraId, ModSeq.first())))
.single()
- .retryWhen(retrySpec);
+ .retryWhen(retrySpec)
+ .map(modSeq -> modSeq.add(cassandraConfiguration.getUidModseqIncrement()));
}
@Override
public Mono<ModSeq> highestModSeqReactive(Mailbox mailbox) {
return findHighestModSeq((CassandraId) mailbox.getMailboxId(), Optional.empty())
- .map(optional -> optional.orElse(ModSeq.first()));
+ .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/CassandraUidProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
index 1a019d35fa..27586783fc 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
@@ -128,7 +128,8 @@ public class CassandraUidProvider implements UidProvider {
.switchIfEmpty(tryInsert(cassandraId))
.switchIfEmpty(updateUid)
.single()
- .retryWhen(retrySpec);
+ .retryWhen(retrySpec)
+ .map(uid -> uid.add(cassandraConfiguration.getUidModseqIncrement()));
}
@Override
@@ -150,18 +151,21 @@ public class CassandraUidProvider implements UidProvider {
private List<MessageUid> range(MessageUid lowerExclusive, MessageUid higherInclusive) {
return LongStream.range(lowerExclusive.asLong() + 1, higherInclusive.asLong() + 1)
.mapToObj(MessageUid::of)
+ .map(uid -> uid.add(cassandraConfiguration.getUidModseqIncrement()))
.collect(ImmutableList.toImmutableList());
}
@Override
public Optional<MessageUid> lastUid(Mailbox mailbox) {
return findHighestUid((CassandraId) mailbox.getMailboxId(), Optional.of(lwtProfile).filter(any -> cassandraConfiguration.isUidReadStrongConsistency()))
- .blockOptional();
+ .blockOptional()
+ .map(uid -> uid.add(cassandraConfiguration.getUidModseqIncrement()));
}
@Override
public Mono<Optional<MessageUid>> lastUidReactive(Mailbox mailbox) {
return findHighestUid((CassandraId) mailbox.getMailboxId(), Optional.of(lwtProfile).filter(any -> cassandraConfiguration.isUidReadStrongConsistency()))
+ .map(uid -> uid.add(cassandraConfiguration.getUidModseqIncrement()))
.map(Optional::of)
.switchIfEmpty(Mono.just(Optional.empty()));
}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java
index e89b30b321..326fbcfb64 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java
@@ -29,6 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import java.time.Duration;
+import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutionException;
@@ -40,6 +41,7 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.backends.cassandra.Scenario.Barrier;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
import org.apache.james.core.Username;
+import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
import org.apache.james.mailbox.cassandra.ids.CassandraId;
import org.apache.james.mailbox.cassandra.modules.CassandraModSeqModule;
@@ -47,6 +49,7 @@ import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.UidValidity;
import org.apache.james.util.concurrency.ConcurrentTestRunner;
+import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -64,7 +67,6 @@ class CassandraModSeqProviderTest {
private CassandraModSeqProvider modSeqProvider;
private Mailbox mailbox;
-
@BeforeEach
void setUp(CassandraCluster cassandra) {
modSeqProvider = new CassandraModSeqProvider(
@@ -155,4 +157,30 @@ class CassandraModSeqProviderTest {
assertThat(modSeqs).hasSize(100);
}
+
+ @Test
+ void shouldHandleOffset(CassandraCluster cassandra) throws Exception {
+ modSeqProvider = new CassandraModSeqProvider(cassandra.getConf(),
+ CassandraConfiguration.builder()
+ .uidModseqIncrement(10)
+ .build());
+
+ ModSeq modseq0 = modSeqProvider.highestModSeq(mailbox);
+ ModSeq modseq1 = modSeqProvider.nextModSeq(mailbox);
+ ModSeq modseq2 = modSeqProvider.nextModSeq(mailbox.getMailboxId());
+ ModSeq modseq3 = modSeqProvider.nextModSeqReactive(mailbox.getMailboxId()).block();
+ ModSeq modseq4 = modSeqProvider.highestModSeq(mailbox);
+ ModSeq modseq5 = modSeqProvider.highestModSeq(mailbox.getMailboxId());
+ ModSeq modseq6 = modSeqProvider.highestModSeqReactive(mailbox).block();
+
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(modseq0).isEqualTo(ModSeq.of(10));
+ softly.assertThat(modseq1).isEqualTo(ModSeq.of(11));
+ softly.assertThat(modseq2).isEqualTo(ModSeq.of(12));
+ softly.assertThat(modseq3).isEqualTo(ModSeq.of(13));
+ softly.assertThat(modseq4).isEqualTo(ModSeq.of(13));
+ softly.assertThat(modseq5).isEqualTo(ModSeq.of(13));
+ softly.assertThat(modseq6).isEqualTo(ModSeq.of(13));
+ });
+ }
}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java
index 0f0fab0f0c..e02ff3d80c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java
@@ -23,7 +23,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.concurrent.ExecutionException;
import java.util.stream.LongStream;
import org.apache.james.backends.cassandra.CassandraCluster;
@@ -37,6 +36,7 @@ import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.UidValidity;
import org.apache.james.util.concurrency.ConcurrentTestRunner;
+import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -62,7 +62,7 @@ class CassandraUidProviderTest {
}
@Test
- void lastUidShouldRetrieveValueStoredByNextUid() throws Exception {
+ void lastUidShouldRetrieveValueStoredByNextUid() {
int nbEntries = 100;
Optional<MessageUid> result = uidProvider.lastUid(mailbox);
assertThat(result).isEmpty();
@@ -85,7 +85,7 @@ class CassandraUidProviderTest {
}
@Test
- void nextUidShouldGenerateUniqueValuesWhenParallelCalls() throws ExecutionException, InterruptedException {
+ void nextUidShouldGenerateUniqueValuesWhenParallelCalls() throws Exception {
int threadCount = 10;
int nbEntries = 100;
@@ -100,7 +100,7 @@ class CassandraUidProviderTest {
}
@Test
- void nextUidsShouldGenerateUniqueValuesWhenParallelCalls() throws ExecutionException, InterruptedException {
+ void nextUidsShouldGenerateUniqueValuesWhenParallelCalls() throws Exception {
int threadCount = 10;
int nbOperations = 100;
@@ -113,4 +113,28 @@ class CassandraUidProviderTest {
assertThat(messageUids).hasSize(nbOperations * 10);
}
+
+ @Test
+ void shouldHandleOffset(CassandraCluster cassandra) throws Exception {
+ uidProvider = new CassandraUidProvider(cassandra.getConf(),
+ CassandraConfiguration.builder()
+ .uidModseqIncrement(10)
+ .build());
+
+ Optional<MessageUid> uid0 = uidProvider.lastUid(mailbox);
+ MessageUid uid1 = uidProvider.nextUid(mailbox);
+ MessageUid uid2 = uidProvider.nextUid(mailbox.getMailboxId());
+ MessageUid uid3 = uidProvider.nextUidReactive(mailbox.getMailboxId()).block();
+ Optional<MessageUid> uid4 = uidProvider.lastUid(mailbox);
+ Optional<MessageUid> uid5 = uidProvider.lastUidReactive(mailbox).block();
+
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(uid0).isEmpty();
+ softly.assertThat(uid1).isEqualTo(MessageUid.of(11));
+ softly.assertThat(uid2).isEqualTo(MessageUid.of(12));
+ softly.assertThat(uid3).isEqualTo(MessageUid.of(13));
+ softly.assertThat(uid4).contains(MessageUid.of(13));
+ softly.assertThat(uid5).contains(MessageUid.of(13));
+ });
+ }
}
diff --git a/server/apps/cassandra-app/sample-configuration/cassandra.properties b/server/apps/cassandra-app/sample-configuration/cassandra.properties
index 892dc8a358..591ac9f934 100644
--- a/server/apps/cassandra-app/sample-configuration/cassandra.properties
+++ b/server/apps/cassandra-app/sample-configuration/cassandra.properties
@@ -37,4 +37,8 @@ cassandra.retryConnection.minDelay=5000
# Optional. Allows not to use lightweight transactions in CassandraMailRepository.
# If disabled we implement an idempotent behaviour (duplicates are overridden, missing entries upon deletes are ignored).
# Defaults to true.
-# mailrepository.strong.consistency=true
\ No newline at end of file
+# mailrepository.strong.consistency=true
+
+# 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.
+# uid.modseq.increment=0
\ No newline at end of file
diff --git a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/cassandra.adoc b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/cassandra.adoc
index 0bdb101ace..38ba7b40df 100644
--- a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/cassandra.adoc
+++ b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/cassandra.adoc
@@ -158,4 +158,8 @@ features to your users, you can consider disabling them in order to improve perf
| mailbox.change.ttl
| Optional. Duration, default to 60 days. Cassandra Time-to-live for Mailbox change records. Setting time-to-live to zero means refusing to use time-to-live on mailbox changes.
+| uid.modseq.increment
+| 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
diff --git a/server/apps/distributed-app/sample-configuration/cassandra.properties b/server/apps/distributed-app/sample-configuration/cassandra.properties
index 892dc8a358..591ac9f934 100644
--- a/server/apps/distributed-app/sample-configuration/cassandra.properties
+++ b/server/apps/distributed-app/sample-configuration/cassandra.properties
@@ -37,4 +37,8 @@ cassandra.retryConnection.minDelay=5000
# Optional. Allows not to use lightweight transactions in CassandraMailRepository.
# If disabled we implement an idempotent behaviour (duplicates are overridden, missing entries upon deletes are ignored).
# Defaults to true.
-# mailrepository.strong.consistency=true
\ No newline at end of file
+# mailrepository.strong.consistency=true
+
+# 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.
+# uid.modseq.increment=0
\ No newline at end of file
diff --git a/server/apps/distributed-pop3-app/src/main/java/org/apache/james/DistributedPOP3JamesServerMain.java b/server/apps/distributed-pop3-app/src/main/java/org/apache/james/DistributedPOP3JamesServerMain.java
index 2350fba760..d094aaab94 100644
--- a/server/apps/distributed-pop3-app/src/main/java/org/apache/james/DistributedPOP3JamesServerMain.java
+++ b/server/apps/distributed-pop3-app/src/main/java/org/apache/james/DistributedPOP3JamesServerMain.java
@@ -133,7 +133,6 @@ public class DistributedPOP3JamesServerMain implements JamesServerMain {
new SMTPServerModule(),
WEBADMIN);
-
private static final Module BLOB_MODULE = new BlobExportMechanismModule();
private static final Module CASSANDRA_EVENT_STORE_JSON_SERIALIZATION_DEFAULT_MODULE = binder ->
diff --git a/src/site/xdoc/server/config-cassandra.xml b/src/site/xdoc/server/config-cassandra.xml
index ec509dd51b..660b5cff49 100644
--- a/src/site/xdoc/server/config-cassandra.xml
+++ b/src/site/xdoc/server/config-cassandra.xml
@@ -132,6 +132,9 @@
<dt><strong>mailbox.change.ttl</strong></dt>
<dd>Optional. Duration, default to 60 days. Cassandra Time-to-live for Mailbox change records.
Setting time-to-live to zero means refusing to use time-to-live on mailbox changes.</dd>
+ <dt><strong>uid.modseq.increment</strong></dt>
+ <dd>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.</dd>
</dl>
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org