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 a6725a2cc4 JAMES-4194 Tiering: max threading window (#2987)
a6725a2cc4 is described below

commit a6725a2cc4eba483f98915ac42047e7af4c17838
Author: Rene Cordier <[email protected]>
AuthorDate: Wed Apr 1 09:20:08 2026 +0700

    JAMES-4194 Tiering: max threading window (#2987)
---
 .../pages/distributed/architecture/data-tiering.adoc    |  6 ++++++
 .../mailbox/cassandra/mail/CassandraThreadDAO.java      | 17 ++++++++++++++---
 .../distributed-app/sample-configuration/jvm.properties |  4 ++++
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git 
a/docs/modules/servers/pages/distributed/architecture/data-tiering.adoc 
b/docs/modules/servers/pages/distributed/architecture/data-tiering.adoc
index 267d5c3a41..17aaf4270c 100644
--- a/docs/modules/servers/pages/distributed/architecture/data-tiering.adoc
+++ b/docs/modules/servers/pages/distributed/architecture/data-tiering.adoc
@@ -26,6 +26,12 @@ This can also be set up for mail previews: In 
`jvm.properties`
 james.jmap.preview.ttl=60d
 ....
 
+This can also be set up for thread data. In `jvm.properties`:
+
+....
+james.thread.window=90d
+....
+
 For clearing the JMAP resynchronisation log: In `cassandra.properties`
 
 ....
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java
index 6ea4ba3f49..1d25e23161 100644
--- 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraThreadDAO.java
@@ -32,6 +32,7 @@ import static 
org.apache.james.mailbox.cassandra.table.CassandraThreadTable.TABL
 import static 
org.apache.james.mailbox.cassandra.table.CassandraThreadTable.USERNAME;
 import static org.apache.james.util.ReactorUtils.DEFAULT_CONCURRENCY;
 
+import java.time.Duration;
 import java.util.Optional;
 import java.util.Set;
 
@@ -44,16 +45,22 @@ import org.apache.james.core.Username;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.ThreadId;
+import org.apache.james.util.DurationParser;
 
 import com.datastax.oss.driver.api.core.CqlSession;
 import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
 import com.datastax.oss.driver.api.core.cql.PreparedStatement;
 import com.datastax.oss.driver.api.core.cql.Row;
 import com.datastax.oss.driver.api.core.type.codec.TypeCodecs;
+import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert;
 
 import reactor.core.publisher.Flux;
 
 public class CassandraThreadDAO {
+    private static final Optional<Duration> THREAD_TTL = Optional.ofNullable(
+            System.getProperty("james.thread.window", null))
+        .map(DurationParser::parse);
+
     private final CassandraAsyncExecutor executor;
     private final PreparedStatement insertOne;
     private final PreparedStatement selectOne;
@@ -65,13 +72,17 @@ public class CassandraThreadDAO {
     public CassandraThreadDAO(CqlSession session) {
         executor = new CassandraAsyncExecutor(session);
 
-        insertOne = session.prepare(insertInto(TABLE_NAME)
+        RegularInsert insert = insertInto(TABLE_NAME)
             .value(USERNAME, bindMarker(USERNAME))
             .value(MIME_MESSAGE_ID, bindMarker(MIME_MESSAGE_ID))
             .value(MESSAGE_ID, bindMarker(MESSAGE_ID))
             .value(THREAD_ID, bindMarker(THREAD_ID))
-            .value(BASE_SUBJECT, bindMarker(BASE_SUBJECT))
-            .build());
+            .value(BASE_SUBJECT, bindMarker(BASE_SUBJECT));
+
+        insertOne = session.prepare(
+            THREAD_TTL.map(ttl -> insert.usingTtl((int) ttl.toSeconds()))
+                .orElse(insert)
+                .build());
 
         selectOne = session.prepare(selectFrom(TABLE_NAME)
             .columns(BASE_SUBJECT, THREAD_ID)
diff --git a/server/apps/distributed-app/sample-configuration/jvm.properties 
b/server/apps/distributed-app/sample-configuration/jvm.properties
index 3131063572..4c1ce91297 100644
--- a/server/apps/distributed-app/sample-configuration/jvm.properties
+++ b/server/apps/distributed-app/sample-configuration/jvm.properties
@@ -116,6 +116,10 @@ jmx.remote.x.mlet.allow.getMBeansFromURL=false
 # setting an expiry for attachments, thus allowing trading read performance on 
older attachments for improved disk space.
 # james.jmap.attachment.ttl=30d
 
+# Thread data takes roughly 5% DB space and can grow larger over time. This 
property allows setting an optional
+# expiry for thread data entries. Defaults to no TTL (keep forever).
+# james.thread.window=90d
+
 # Configure the header to get the original JMAP client's IP address. This is 
useful when James is behind a reverse proxy.
 # Defaults to the `x-forwarded-for` header.
 # james.jmap.mdc.original.ip.header=x-real-ip


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to