aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoni Marti <koni.marti@gmail.com>2023-04-24 23:18:50 +0200
committerRobin Jarry <robin@jarry.cc>2023-04-26 00:07:46 +0200
commit6ea0f18635a8be20b89e11af53333cc9fee5d04f (patch)
tree4a19506e34d2ae7bcd36bc7eec318a4b22098ca3
parentf04d83e80af70f9d29a1c515e93238eeb356ad2d (diff)
downloadaerc-6ea0f18635a8be20b89e11af53333cc9fee5d04f.tar.gz
imap: clear cache on tag mismatch
Tag the imap cache and clear it when the cache tag does not match the current tag in the code. This ensures that the cache structure is always consitent with our code base. Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
-rw-r--r--worker/imap/cache.go43
1 files changed, 41 insertions, 2 deletions
diff --git a/worker/imap/cache.go b/worker/imap/cache.go
index c5d3dcc0..cc97b922 100644
--- a/worker/imap/cache.go
+++ b/worker/imap/cache.go
@@ -4,9 +4,11 @@ import (
"bufio"
"bytes"
"encoding/gob"
+ "errors"
"fmt"
"os"
"path"
+ "reflect"
"time"
"git.sr.ht/~rjarry/aerc/lib/parse"
@@ -29,6 +31,14 @@ type CachedHeader struct {
Created time.Time
}
+var (
+ // cacheTag should be updated when changing the cache
+ // structure; this will ensure that the user's cache is cleared and
+ // reloaded when the underlying cache structure changes
+ cacheTag = []byte("0000")
+ cacheTagKey = []byte("cache.tag")
+)
+
// initCacheDb opens (or creates) the database for the cache. One database is
// created per account
func (w *IMAPWorker) initCacheDb(acct string) {
@@ -47,8 +57,26 @@ func (w *IMAPWorker) initCacheDb(acct string) {
}
w.cache = db
log.Debugf("cache db opened: %s", p)
- if w.config.cacheMaxAge.Hours() > 0 {
- go w.cleanCache(p)
+
+ tag, err := w.cache.Get(cacheTagKey, nil)
+ clearCache := errors.Is(err, leveldb.ErrNotFound) ||
+ !reflect.DeepEqual(tag, cacheTag)
+ switch {
+ case clearCache:
+ log.Infof("current cache tag is '%s' but found '%s'",
+ cacheTag, tag)
+ log.Warnf("tag mismatch: clear cache")
+ w.clearCache()
+ if err = w.cache.Put(cacheTagKey, cacheTag, nil); err != nil {
+ log.Errorf("could not set the current cache tag")
+ }
+ case err != nil:
+ log.Errorf("could not get the cache tag from db")
+ default:
+ log.Tracef("cache version match")
+ if w.config.cacheMaxAge.Hours() > 0 {
+ go w.cleanCache(p)
+ }
}
}
@@ -172,3 +200,14 @@ func (w *IMAPWorker) cleanCache(path string) {
log.Debugf("%s: removed %d/%d expired entries in %s",
path, removed, scanned, elapsed)
}
+
+// clearCache clears the entire cache
+func (w *IMAPWorker) clearCache() {
+ iter := w.cache.NewIterator(nil, nil)
+ for iter.Next() {
+ if err := w.cache.Delete(iter.Key(), nil); err != nil {
+ log.Errorf("error clearing cache: %v", err)
+ }
+ }
+ iter.Release()
+}