diff options
author | Koni Marti <koni.marti@gmail.com> | 2023-04-24 23:18:50 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2023-04-26 00:07:46 +0200 |
commit | 6ea0f18635a8be20b89e11af53333cc9fee5d04f (patch) | |
tree | 4a19506e34d2ae7bcd36bc7eec318a4b22098ca3 | |
parent | f04d83e80af70f9d29a1c515e93238eeb356ad2d (diff) | |
download | aerc-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.go | 43 |
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() +} |