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:
parent
b37faa06bd
commit
a68a9d8a48
4 changed files with 36 additions and 29 deletions
2
ctl.go
2
ctl.go
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -1695,7 +1695,7 @@
|
|||
},
|
||||
{
|
||||
"Name": "HaveCounts",
|
||||
"Docs": "Whether MailboxCounts have been initialized.",
|
||||
"Docs": "Deprecated. Covered by Upgrade.MailboxCounts. No longer read.",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue