1
1
Fork 0
mirror of https://github.com/mjl-/mox.git synced 2025-04-21 21:40:01 +03:00

check whether mailboxes have message/etc counts through an "upgrade" boolean flag

Instead of using the per-mailbox flag, and going through all mailboxes when
opening an account.
This commit is contained in:
Mechiel Lukkien 2025-03-23 12:45:21 +01:00
parent b37faa06bd
commit a68a9d8a48
No known key found for this signature in database
4 changed files with 36 additions and 29 deletions

2
ctl.go
View file

@ -1522,7 +1522,7 @@ func servectlcmd(ctx context.Context, ctl *ctl, cid int64, shutdown func()) {
}
totalSize += mc.Size
if !mb.HaveCounts || mc != mb.MailboxCounts {
if mc != mb.MailboxCounts {
_, err := fmt.Fprintf(w, "for %s setting new counts %s (was %s)\n", mb.Name, mc, mb.MailboxCounts)
ctl.xcheck(err, "write")
mb.HaveCounts = true

View file

@ -221,7 +221,7 @@ type Mailbox struct {
// lower case (for JMAP), sorted.
Keywords []string
HaveCounts bool // Whether MailboxCounts have been initialized.
HaveCounts bool // Deprecated. Covered by Upgrade.MailboxCounts. No longer read.
MailboxCounts // Statistics about messages, kept up to date whenever a change happens.
}
@ -949,6 +949,7 @@ type Upgrade struct {
Threads byte // 0: None, 1: Adding MessageID's completed, 2: Adding ThreadID's completed.
MailboxModSeq bool // Whether mailboxes have been assigned modseqs.
MailboxParentID bool // Setting ParentID on mailboxes.
MailboxCounts bool // Global flag about whether we have mailbox flags. Instead of previous per-mailbox boolean.
}
// upgradeInit is the value to for new account database, that don't need any upgrading.
@ -957,6 +958,7 @@ var upgradeInit = Upgrade{
Threads: 2,
MailboxModSeq: true,
MailboxParentID: true,
MailboxCounts: true,
}
// InitialUIDValidity returns a UIDValidity used for initializing an account.
@ -1143,11 +1145,10 @@ func OpenAccountDB(log mlog.Log, accountDir, accountName string) (a *Account, re
return acc, nil
}
// Ensure singletons are present. Mailbox counts and total message size, Settings.
// Ensure singletons are present, like DiskUsage and Settings.
// Process pending MessageErase records. Check that next the message ID assigned by
// the database does not already have a file on disk, or increase the sequence so
// it doesn't.
var mentioned bool
err = db.Write(context.TODO(), func(tx *bstore.Tx) error {
if tx.Get(&Settings{ID: 1}) == bstore.ErrAbsent {
if err := tx.Insert(&Settings{ID: 1, ShowAddressSecurity: true}); err != nil {
@ -1155,23 +1156,6 @@ func OpenAccountDB(log mlog.Log, accountDir, accountName string) (a *Account, re
}
}
err := bstore.QueryTx[Mailbox](tx).FilterEqual("HaveCounts", false).ForEach(func(mb Mailbox) error {
if !mentioned {
mentioned = true
log.Info("first calculation of mailbox counts for account", slog.String("account", accountName))
}
mc, err := mb.CalculateCounts(tx)
if err != nil {
return err
}
mb.HaveCounts = true
mb.MailboxCounts = mc
return tx.Update(&mb)
})
if err != nil {
return err
}
du := DiskUsage{ID: 1}
err = tx.Get(&du)
if err == bstore.ErrAbsent {
@ -1308,7 +1292,6 @@ func OpenAccountDB(log mlog.Log, accountDir, accountName string) (a *Account, re
return nil, fmt.Errorf("calculating counts for mailbox, inserting settings, expunging messages: %v", err)
}
// Start adding threading if needed.
up := Upgrade{ID: 1}
err = db.Write(context.TODO(), func(tx *bstore.Tx) error {
err := tx.Get(&up)
@ -1458,6 +1441,34 @@ func OpenAccountDB(log mlog.Log, accountDir, accountName string) (a *Account, re
}
}
if !up.MailboxCounts {
log.Debug("upgrade: ensuring all mailboxes have message counts")
err := acc.DB.Write(context.TODO(), func(tx *bstore.Tx) error {
err := bstore.QueryTx[Mailbox](tx).FilterEqual("HaveCounts", false).ForEach(func(mb Mailbox) error {
mc, err := mb.CalculateCounts(tx)
if err != nil {
return err
}
mb.HaveCounts = true
mb.MailboxCounts = mc
return tx.Update(&mb)
})
if err != nil {
return err
}
up.MailboxCounts = true
if err := tx.Update(&up); err != nil {
return fmt.Errorf("marking upgrade done: %w", err)
}
return nil
})
if err != nil {
return nil, fmt.Errorf("upgrade: ensuring message counts on all mailboxes")
}
}
if up.Threads == 2 {
close(acc.threadsCompleted)
return acc, nil
@ -1686,7 +1697,6 @@ func (a *Account) SetSkipMessageModSeqZeroCheck(skip bool) {
//
// - Missing or unexpected on-disk message files.
// - Mismatch between message size and length of MsgPrefix and on-disk file.
// - Missing HaveCounts.
// - Incorrect mailbox counts.
// - Incorrect total message size.
// - Message with UID >= mailbox uid next.
@ -1935,10 +1945,7 @@ func (a *Account) CheckConsistency() error {
var totalMailboxSize int64
for _, mb := range mailboxNames {
totalMailboxSize += mb.Size
if !mb.HaveCounts {
errmsg := fmt.Sprintf("mailbox %q (id %d) does not have counts, should be %#v", mb.Name, mb.ID, counts[mb.ID])
errmsgs = append(errmsgs, errmsg)
} else if mb.MailboxCounts != counts[mb.ID] {
if mb.MailboxCounts != counts[mb.ID] {
mbcounterr := fmt.Sprintf("mailbox %q (id %d) has wrong counts %s, should be %s", mb.Name, mb.ID, mb.MailboxCounts, counts[mb.ID])
errmsgs = append(errmsgs, mbcounterr)
}

View file

@ -1695,7 +1695,7 @@
},
{
"Name": "HaveCounts",
"Docs": "Whether MailboxCounts have been initialized.",
"Docs": "Deprecated. Covered by Upgrade.MailboxCounts. No longer read.",
"Typewords": [
"bool"
]

View file

@ -201,7 +201,7 @@ export interface Mailbox {
Sent: boolean
Trash: boolean
Keywords?: string[] | null // Keywords as used in messages. Storing a non-system keyword for a message automatically adds it to this list. Used in the IMAP FLAGS response. Only "atoms" are allowed (IMAP syntax), keywords are case-insensitive, only stored in lower case (for JMAP), sorted.
HaveCounts: boolean // Whether MailboxCounts have been initialized.
HaveCounts: boolean // Deprecated. Covered by Upgrade.MailboxCounts. No longer read.
Total: number // Total number of messages, excluding \Deleted. For JMAP.
Deleted: number // Number of messages with \Deleted flag. Used for IMAP message count that includes messages with \Deleted.
Unread: number // Messages without \Seen, excluding those with \Deleted, for JMAP.