Optimalization of initAddress

This commit is contained in:
Michal Horejsek
2020-04-14 08:25:39 +02:00
parent 62ade99e37
commit cdfa6b6e49
3 changed files with 70 additions and 60 deletions

View File

@ -20,6 +20,7 @@ package store
import ( import (
"github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
bolt "go.etcd.io/bbolt"
) )
// Address holds mailboxes for IMAP user (login address). In combined mode // Address holds mailboxes for IMAP user (login address). In combined mode
@ -63,20 +64,23 @@ func (storeAddress *Address) init(foldersAndLabels []*pmapi.Label) (err error) {
storeAddress.mailboxes = make(map[string]*Mailbox) storeAddress.mailboxes = make(map[string]*Mailbox)
for _, label := range foldersAndLabels { err = storeAddress.store.db.Update(func(tx *bolt.Tx) error {
prefix := getLabelPrefix(label) for _, label := range foldersAndLabels {
prefix := getLabelPrefix(label)
var mailbox *Mailbox var mailbox *Mailbox
if mailbox, err = newMailbox(storeAddress, label.ID, prefix, label.Name, label.Color); err != nil { if mailbox, err = txNewMailbox(tx, storeAddress, label.ID, prefix, label.Name, label.Color); err != nil {
storeAddress.log. storeAddress.log.
WithError(err). WithError(err).
WithField("labelID", label.ID). WithField("labelID", label.ID).
Error("Could not init mailbox for folder or label") Error("Could not init mailbox for folder or label")
return return err
}
storeAddress.mailboxes[label.ID] = mailbox
} }
return nil
storeAddress.mailboxes[label.ID] = mailbox })
}
return return
} }

View File

@ -41,10 +41,16 @@ type Mailbox struct {
} }
func newMailbox(storeAddress *Address, labelID, labelPrefix, labelName, color string) (mb *Mailbox, err error) { func newMailbox(storeAddress *Address, labelID, labelPrefix, labelName, color string) (mb *Mailbox, err error) {
l := log. _ = storeAddress.store.db.Update(func(tx *bolt.Tx) error {
WithField("addrID", storeAddress.addressID). mb, err = txNewMailbox(tx, storeAddress, labelID, labelPrefix, labelName, color)
WithField("lblID", labelID) return err
mb = &Mailbox{ })
return
}
func txNewMailbox(tx *bolt.Tx, storeAddress *Address, labelID, labelPrefix, labelName, color string) (*Mailbox, error) {
l := log.WithField("addrID", storeAddress.addressID).WithField("labelID", labelID)
mb := &Mailbox{
store: storeAddress.store, store: storeAddress.store,
storeAddress: storeAddress, storeAddress: storeAddress,
labelID: labelID, labelID: labelID,
@ -54,18 +60,17 @@ func newMailbox(storeAddress *Address, labelID, labelPrefix, labelName, color st
log: l, log: l,
} }
if err = mb.store.db.Update(func(tx *bolt.Tx) error { err := initMailboxBucket(tx, mb.getBucketName())
return initMailboxBucket(tx, mb.getBucketName()) if err != nil {
}); err != nil {
l.WithError(err).Error("Could not initialise mailbox buckets") l.WithError(err).Error("Could not initialise mailbox buckets")
} }
syncDraftsIfNecssary(mb) syncDraftsIfNecssary(tx, mb)
return return mb, err
} }
func syncDraftsIfNecssary(mb *Mailbox) { //nolint[funlen] func syncDraftsIfNecssary(tx *bolt.Tx, mb *Mailbox) { //nolint[funlen]
// We didn't support drafts before v1.2.6 and therefore if we now created // We didn't support drafts before v1.2.6 and therefore if we now created
// Drafts mailbox we need to check whether counts match (drafts are synced). // Drafts mailbox we need to check whether counts match (drafts are synced).
// If not, sync them from local metadata without need to do full resync, // If not, sync them from local metadata without need to do full resync,
@ -76,12 +81,12 @@ func syncDraftsIfNecssary(mb *Mailbox) { //nolint[funlen]
// If the drafts mailbox total is non-zero, it means it has already been used // If the drafts mailbox total is non-zero, it means it has already been used
// and there is no need to continue. Otherwise, we may need to do an initial sync. // and there is no need to continue. Otherwise, we may need to do an initial sync.
total, _, err := mb.GetCounts() total, _, err := mb.txGetCounts(tx)
if err != nil || total != 0 { if err != nil || total != 0 {
return return
} }
counts, err := mb.store.getOnAPICounts() counts, err := mb.store.txGetOnAPICounts(tx)
if err != nil { if err != nil {
return return
} }
@ -107,21 +112,19 @@ func syncDraftsIfNecssary(mb *Mailbox) { //nolint[funlen]
} }
if !foundCounts || doSync { if !foundCounts || doSync {
err := mb.store.db.Update(func(tx *bolt.Tx) error { err := tx.Bucket(metadataBucket).ForEach(func(k, v []byte) error {
return tx.Bucket(metadataBucket).ForEach(func(k, v []byte) error { msg := &pmapi.Message{}
msg := &pmapi.Message{} if err := json.Unmarshal(v, msg); err != nil {
if err := json.Unmarshal(v, msg); err != nil { return err
return err }
for _, msgLabelID := range msg.LabelIDs {
if msgLabelID == pmapi.DraftLabel {
log.WithField("id", msg.ID).Trace("Drafts mailbox created: syncing draft locally")
_ = mb.txCreateOrUpdateMessages(tx, []*pmapi.Message{msg})
break
} }
for _, msgLabelID := range msg.LabelIDs { }
if msgLabelID == pmapi.DraftLabel { return nil
log.WithField("id", msg.ID).Trace("Drafts mailbox created: syncing draft locally")
_ = mb.txCreateOrUpdateMessages(tx, []*pmapi.Message{msg})
break
}
}
return nil
})
}) })
log.WithError(err).Info("Drafts mailbox created: synced localy") log.WithError(err).Info("Drafts mailbox created: synced localy")
} }

View File

@ -185,31 +185,34 @@ func (store *Store) getLabelsFromLocalStorage() ([]*pmapi.Label, error) {
return labels, nil return labels, nil
} }
func (store *Store) getOnAPICounts() ([]*mailboxCounts, error) { func (store *Store) getOnAPICounts() (counts []*mailboxCounts, err error) {
err = store.db.View(func(tx *bolt.Tx) error {
counts, err = store.txGetOnAPICounts(tx)
return err
})
return
}
func (store *Store) txGetOnAPICounts(tx *bolt.Tx) ([]*mailboxCounts, error) {
counts := []*mailboxCounts{} counts := []*mailboxCounts{}
tx := func(tx *bolt.Tx) error { c := tx.Bucket(countsBucket).Cursor()
c := tx.Bucket(countsBucket).Cursor() for k, countsB := c.First(); k != nil; k, countsB = c.Next() {
for k, countsB := c.First(); k != nil; k, countsB = c.Next() { l := store.log.WithField("key", string(k))
l := store.log.WithField("key", string(k)) if countsB == nil {
if countsB == nil { err := errors.New("empty counts in DB")
err := errors.New("empty counts in DB") l.WithError(err).Error("While getting local labels")
l.WithError(err).Error("While getting local labels") return nil, err
return err
}
mbCounts := &mailboxCounts{}
if err := json.Unmarshal(countsB, mbCounts); err != nil {
l.WithError(err).Error("While unmarshaling local labels")
return err
}
counts = append(counts, mbCounts)
} }
return nil
}
err := store.db.View(tx)
return counts, err mbCounts := &mailboxCounts{}
if err := json.Unmarshal(countsB, mbCounts); err != nil {
l.WithError(err).Error("While unmarshaling local labels")
return nil, err
}
counts = append(counts, mbCounts)
}
return counts, nil
} }
// createOrUpdateOnAPICounts will change only on-API-counts. // createOrUpdateOnAPICounts will change only on-API-counts.