This is an automated email from the ASF dual-hosted git repository. chibenwa pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 3fd59f7afed71a4902b8f295d41d4ec817d51649 Author: Benoit TELLIER <[email protected]> AuthorDate: Sat Sep 5 20:12:49 2026 +0200 JAMES-4225 Remove flagUser collumn --- .../cassandra/mail/CassandraMessageIdDAO.java | 11 ------ .../mail/CassandraMessageIdToImapUidDAO.java | 13 +------ .../modules/CassandraMessageDataDefinition.java | 2 - .../apache/james/mailbox/cassandra/table/Flag.java | 5 +-- .../cassandra/mail/CassandraMessageIdDAOTest.java | 8 ++-- .../mail/CassandraMessageIdToImapUidDAOTest.java | 8 ++-- upgrade-instructions.md | 43 +++++++++++++--------- 7 files changed, 38 insertions(+), 52 deletions(-) diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java index 3b7dc735f4..0d5401cc46 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java @@ -42,7 +42,6 @@ import static org.apache.james.mailbox.cassandra.table.Flag.DRAFT; import static org.apache.james.mailbox.cassandra.table.Flag.FLAGGED; import static org.apache.james.mailbox.cassandra.table.Flag.RECENT; import static org.apache.james.mailbox.cassandra.table.Flag.SEEN; -import static org.apache.james.mailbox.cassandra.table.Flag.USER; import static org.apache.james.mailbox.cassandra.table.Flag.USER_FLAGS; import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ; import static org.apache.james.util.ReactorUtils.publishIfPresent; @@ -181,7 +180,6 @@ public class CassandraMessageIdDAO { setColumn(FLAGGED, bindMarker(FLAGGED)), setColumn(RECENT, bindMarker(RECENT)), setColumn(SEEN, bindMarker(SEEN)), - setColumn(USER, bindMarker(USER)), setColumn(INTERNAL_DATE, bindMarker(INTERNAL_DATE)), setColumn(SAVE_DATE, bindMarker(SAVE_DATE)), setColumn(BODY_START_OCTET, bindMarker(BODY_START_OCTET)), @@ -213,7 +211,6 @@ public class CassandraMessageIdDAO { setColumn(FLAGGED, bindMarker(FLAGGED)), setColumn(RECENT, bindMarker(RECENT)), setColumn(SEEN, bindMarker(SEEN)), - setColumn(USER, bindMarker(USER)), append(USER_FLAGS, bindMarker(ADDED_USERS_FLAGS)), remove(USER_FLAGS, bindMarker(REMOVED_USERS_FLAGS))) .where(column(MAILBOX_ID).isEqualTo(bindMarker(MAILBOX_ID)), @@ -310,7 +307,6 @@ public class CassandraMessageIdDAO { RECENT, SEEN, FLAGGED, - USER, USER_FLAGS, MOD_SEQ) .where(column(MAILBOX_ID).isEqualTo(bindMarker(MAILBOX_ID)), @@ -372,7 +368,6 @@ public class CassandraMessageIdDAO { .setBoolean(FLAGGED, flags.contains(Flag.FLAGGED)) .setBoolean(RECENT, flags.contains(Flag.RECENT)) .setBoolean(SEEN, flags.contains(Flag.SEEN)) - .setBoolean(USER, flags.contains(Flag.USER)) .setInstant(INTERNAL_DATE, metadata.getInternalDate().get().toInstant()) .setInstant(SAVE_DATE, metadata.getSaveDate().map(Date::toInstant).orElse(null)) .setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get())) @@ -433,11 +428,6 @@ public class CassandraMessageIdDAO { } else { statementBuilder.unset(SEEN); } - if (updatedFlags.isChanged(Flag.USER)) { - statementBuilder.setBoolean(USER, updatedFlags.isModifiedToSet(Flag.USER)); - } else { - statementBuilder.unset(USER); - } Sets.SetView<String> removedFlags = Sets.difference( ImmutableSet.copyOf(updatedFlags.getOldFlags().getUserFlags()), ImmutableSet.copyOf(updatedFlags.getNewFlags().getUserFlags())); @@ -671,7 +661,6 @@ public class CassandraMessageIdDAO { .setBoolean(FLAGGED, flags.contains(Flag.FLAGGED)) .setBoolean(RECENT, flags.contains(Flag.RECENT)) .setBoolean(SEEN, flags.contains(Flag.SEEN)) - .setBoolean(USER, flags.contains(Flag.USER)) .setInstant(INTERNAL_DATE, null) .setInt(BODY_START_OCTET, 0) .setLong(FULL_CONTENT_OCTETS, 0) diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java index bfb7b7339e..a57973e133 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java @@ -40,7 +40,6 @@ import static org.apache.james.mailbox.cassandra.table.Flag.DRAFT; import static org.apache.james.mailbox.cassandra.table.Flag.FLAGGED; import static org.apache.james.mailbox.cassandra.table.Flag.RECENT; import static org.apache.james.mailbox.cassandra.table.Flag.SEEN; -import static org.apache.james.mailbox.cassandra.table.Flag.USER; import static org.apache.james.mailbox.cassandra.table.Flag.USER_FLAGS; import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ; import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.TABLE_NAME; @@ -149,7 +148,6 @@ public class CassandraMessageIdToImapUidDAO { .value(FLAGGED, bindMarker(FLAGGED)) .value(RECENT, bindMarker(RECENT)) .value(SEEN, bindMarker(SEEN)) - .value(USER, bindMarker(USER)) .value(USER_FLAGS, bindMarker(USER_FLAGS)) .value(INTERNAL_DATE, bindMarker(INTERNAL_DATE)) .value(SAVE_DATE, bindMarker(SAVE_DATE)) @@ -168,7 +166,6 @@ public class CassandraMessageIdToImapUidDAO { setColumn(FLAGGED, bindMarker(FLAGGED)), setColumn(RECENT, bindMarker(RECENT)), setColumn(SEEN, bindMarker(SEEN)), - setColumn(USER, bindMarker(USER)), setColumn(INTERNAL_DATE, bindMarker(INTERNAL_DATE)), setColumn(SAVE_DATE, bindMarker(SAVE_DATE)), setColumn(BODY_START_OCTET, bindMarker(BODY_START_OCTET)), @@ -202,8 +199,7 @@ public class CassandraMessageIdToImapUidDAO { setColumn(DRAFT, bindMarker(DRAFT)), setColumn(FLAGGED, bindMarker(FLAGGED)), setColumn(RECENT, bindMarker(RECENT)), - setColumn(SEEN, bindMarker(SEEN)), - setColumn(USER, bindMarker(USER))) + setColumn(SEEN, bindMarker(SEEN))) .append(USER_FLAGS, bindMarker(ADDED_USERS_FLAGS)) .remove(USER_FLAGS, bindMarker(REMOVED_USERS_FLAGS)) .where(column(MESSAGE_ID).isEqualTo(bindMarker(MESSAGE_ID)), @@ -267,7 +263,6 @@ public class CassandraMessageIdToImapUidDAO { .setBoolean(FLAGGED, flags.contains(Flag.FLAGGED)) .setBoolean(RECENT, flags.contains(Flag.RECENT)) .setBoolean(SEEN, flags.contains(Flag.SEEN)) - .setBoolean(USER, flags.contains(Flag.USER)) .setInstant(INTERNAL_DATE, metadata.getInternalDate().get().toInstant()) .setInstant(SAVE_DATE, metadata.getSaveDate().map(Date::toInstant).orElse(null)) .setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get())) @@ -334,11 +329,6 @@ public class CassandraMessageIdToImapUidDAO { } else { statementBuilder.unset(SEEN); } - if (updatedFlags.isChanged(Flag.USER)) { - statementBuilder.setBoolean(USER, updatedFlags.isModifiedToSet(Flag.USER)); - } else { - statementBuilder.unset(USER); - } Sets.SetView<String> removedFlags = Sets.difference( ImmutableSet.copyOf(updatedFlags.getOldFlags().getUserFlags()), ImmutableSet.copyOf(updatedFlags.getNewFlags().getUserFlags())); @@ -460,7 +450,6 @@ public class CassandraMessageIdToImapUidDAO { .setBoolean(FLAGGED, flags.contains(Flag.FLAGGED)) .setBoolean(RECENT, flags.contains(Flag.RECENT)) .setBoolean(SEEN, flags.contains(Flag.SEEN)) - .setBoolean(USER, flags.contains(Flag.USER)) .setInstant(INTERNAL_DATE, null) .setInt(BODY_START_OCTET, 0) .setLong(FULL_CONTENT_OCTETS, 0) diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageDataDefinition.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageDataDefinition.java index 10a6bfaaf4..92169be355 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageDataDefinition.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageDataDefinition.java @@ -61,7 +61,6 @@ public interface CassandraMessageDataDefinition { .withColumn(Flag.FLAGGED, BOOLEAN) .withColumn(Flag.RECENT, BOOLEAN) .withColumn(Flag.SEEN, BOOLEAN) - .withColumn(Flag.USER, BOOLEAN) .withColumn(Flag.USER_FLAGS, setOf(TEXT)) .withColumn(CassandraMessageV3Table.INTERNAL_DATE, TIMESTAMP) .withColumn(CassandraMessageIdTable.SAVE_DATE, TIMESTAMP) @@ -86,7 +85,6 @@ public interface CassandraMessageDataDefinition { .withColumn(Flag.FLAGGED, BOOLEAN) .withColumn(Flag.RECENT, BOOLEAN) .withColumn(Flag.SEEN, BOOLEAN) - .withColumn(Flag.USER, BOOLEAN) .withColumn(Flag.USER_FLAGS, setOf(TEXT)) .withColumn(CassandraMessageV3Table.INTERNAL_DATE, TIMESTAMP) .withColumn(CassandraMessageIdTable.SAVE_DATE, TIMESTAMP) diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/Flag.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/Flag.java index fdf367b5ac..ac6a5ac011 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/Flag.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/Flag.java @@ -30,7 +30,6 @@ public interface Flag { CqlIdentifier RECENT = CqlIdentifier.fromCql("flagRecent"); CqlIdentifier SEEN = CqlIdentifier.fromCql("flagSeen"); CqlIdentifier FLAGGED = CqlIdentifier.fromCql("flagFlagged"); - CqlIdentifier USER = CqlIdentifier.fromCql("flagUser"); CqlIdentifier USER_FLAGS = CqlIdentifier.fromCql("userFlags"); CqlIdentifier[] ALL_LOWERCASE = { @@ -39,8 +38,7 @@ public interface Flag { DRAFT, RECENT, SEEN, - FLAGGED, - USER + FLAGGED }; ImmutableMap<CqlIdentifier, Flags.Flag> JAVAX_MAIL_FLAG = ImmutableMap.<CqlIdentifier, Flags.Flag>builder() @@ -50,6 +48,5 @@ public interface Flag { .put(RECENT, Flags.Flag.RECENT) .put(SEEN, Flags.Flag.SEEN) .put(FLAGGED, Flags.Flag.FLAGGED) - .put(USER, Flags.Flag.USER) .build(); } \ No newline at end of file diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java index 3bb94fd39f..6aa9370f41 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java @@ -554,7 +554,7 @@ class CassandraMessageIdDAOTest { } @Test - void updateShouldUpdateUserFlag() { + void updateShouldNotPersistUserFlag() { CassandraMessageId messageId = messageIdFactory.generate(); CassandraId mailboxId = CassandraId.timeBased(); MessageUid messageUid = MessageUid.of(1); @@ -574,9 +574,11 @@ class CassandraMessageIdDAOTest { .build()) .block(); + // \* is IMAP PERMANENTFLAGS syntax, a mailbox capability rather than a flag of a message: no + // protocol lets a client set it on one, so it is not stored. ComposedMessageIdWithMetaData expectedComposedMessageId = ComposedMessageIdWithMetaData.builder() .composedMessageId(composedMessageId) - .flags(new Flags(Flags.Flag.USER)) + .flags(new Flags()) .modSeq(ModSeq.of(2)) .threadId(ThreadId.fromBaseMessageId(messageId)) .build(); @@ -585,7 +587,7 @@ class CassandraMessageIdDAOTest { .messageId(messageId) .modSeq(expectedComposedMessageId.getModSeq()) .oldFlags(new Flags()) - .newFlags(expectedComposedMessageId.getFlags()) + .newFlags(new Flags(Flags.Flag.USER)) .build(); testee.updateMetadata(expectedComposedMessageId.getComposedMessageId(), updatedFlags) diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java index c2cb662d7a..b420bc8c16 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java @@ -604,7 +604,7 @@ class CassandraMessageIdToImapUidDAOTest { } @Test - void updateShouldUpdateUserFlag() { + void updateShouldNotPersistUserFlag() { CassandraMessageId messageId = CassandraMessageId.Factory.of(Uuids.timeBased()); CassandraId mailboxId = CassandraId.timeBased(); MessageUid messageUid = MessageUid.of(1); @@ -624,9 +624,11 @@ class CassandraMessageIdToImapUidDAOTest { .build()) .block(); + // \* is IMAP PERMANENTFLAGS syntax, a mailbox capability rather than a flag of a message: no + // protocol lets a client set it on one, so it is not stored. ComposedMessageIdWithMetaData expectedComposedMessageId = ComposedMessageIdWithMetaData.builder() .composedMessageId(composedMessageId) - .flags(new Flags(Flags.Flag.USER)) + .flags(new Flags()) .modSeq(ModSeq.of(2)) .threadId(ThreadId.fromBaseMessageId(messageId)) .build(); @@ -635,7 +637,7 @@ class CassandraMessageIdToImapUidDAOTest { .messageId(messageId) .modSeq(ModSeq.of(2)) .oldFlags(new Flags()) - .newFlags(expectedComposedMessageId.getFlags()) + .newFlags(new Flags(Flags.Flag.USER)) .build(); testee.updateMetadata(expectedComposedMessageId.getComposedMessageId(), updatedFlags, ModSeq.of(1)).block(); diff --git a/upgrade-instructions.md b/upgrade-instructions.md index 8f63beb31a..4e84aba178 100644 --- a/upgrade-instructions.md +++ b/upgrade-instructions.md @@ -23,9 +23,34 @@ Change list: - [JAMES-4210 POP3 USER/PASS requires TLS by default](#james-4210-pop3-userpass-requires-tls-by-default) - [JAMES-4210 ManageSieve SASL adoption](#james-4210-managesieve-sasl-adoption) - [JAMES-4225 Blob ids default to 128 bits of entropy](#james-4225-blob-ids-default-to-128-bits-of-entropy) - - [Dropping the bodyOctets column of the Cassandra messagev3 table](#dropping-the-bodyoctets-column-of-the-cassandra-messagev3-table) + - [Dropping unneeded Cassandra schema columns](#dropping-unneeded-cassandra-schema-columns) - [Cassandra schema version 16: mandatory message denormalization migration](#cassandra-schema-version-16-mandatory-message-denormalization-migration) +### Dropping unneeded Cassandra schema columns + +Date: 05/09/2026 + +Concerned products: James products using Cassandra as mailbox storage + +Three columns held no information and are no longer written: + +- `messagev3.bodyOctets`, never read back, the body size being derived from `fullContentOctets` and +`bodyStartOctet`. +- `messageIdTable.flagUser` and `imapUidTable.flagUser`, persisting the JavaMail `Flags.Flag.USER`. That +flag is IMAP `PERMANENTFLAGS` syntax, `\*`, a property of a mailbox rather than of a message, that no +protocol lets a client set on one: the column only ever held `false`. + +New messages stop paying for them right away. Reclaiming the space taken by existing rows requires +dropping the columns manually, once the new version runs on every node: + +```sql +ALTER TABLE james_keyspace.messagev3 DROP bodyOctets; +ALTER TABLE james_keyspace.messageIdTable DROP flagUser; +ALTER TABLE james_keyspace.imapUidTable DROP flagUser; +``` + +Disk space comes back progressively, as SSTables get compacted. + ### Cassandra schema version 16: mandatory message denormalization migration Date: 05/09/2026 @@ -62,22 +87,6 @@ against its shorter counterpart until it is rewritten. To keep the previous beha james.blobid.entropy=256 ``` -### Dropping the bodyOctets column of the Cassandra messagev3 table - -Date: 05/09/2026 - -Concerned products: James products using Cassandra as mailbox storage - -The `messagev3.bodyOctets` column was written upon every message save but never read back: the body size -is derived from `fullContentOctets` and `bodyStartOctet`. James no longer writes it. - -New messages stop paying for the column right away. Reclaiming the space taken by existing rows requires -dropping the column manually, after upgrading all james servers: - -```sql -ALTER TABLE james_keyspace.messagev3 DROP bodyOctets; -``` - ### JAMES-4210 POP3 USER/PASS requires TLS by default Date: 16/07/2026 --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
