From 8f3a9f1e2f0c9e066d2e3894b9fc2d054d2f148e Mon Sep 17 00:00:00 2001 From: René 'Necoro' Neumann Date: Sat, 22 Aug 2020 14:26:29 +0200 Subject: Lock cache --- internal/feed/cache.go | 68 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 11 deletions(-) (limited to 'internal/feed/cache.go') diff --git a/internal/feed/cache.go b/internal/feed/cache.go index 45cefd0..2d8f9aa 100644 --- a/internal/feed/cache.go +++ b/internal/feed/cache.go @@ -8,6 +8,8 @@ import ( "os" "time" + "github.com/nightlyone/lockfile" + "github.com/Necoro/feed2imap-go/pkg/log" ) @@ -17,12 +19,18 @@ const ( currentVersion Version = 1 ) -type Cache interface { +type CacheImpl interface { findItem(*Feed) CachedFeed Version() Version Info() string SpecificInfo(interface{}) string - transformToCurrent() (Cache, error) + transformToCurrent() (CacheImpl, error) +} + +type Cache struct { + CacheImpl + lock lockfile.Lockfile + locked bool } type CachedFeed interface { @@ -34,7 +42,7 @@ type CachedFeed interface { Commit() } -func cacheForVersion(version Version) (Cache, error) { +func cacheForVersion(version Version) (CacheImpl, error) { switch version { case v1Version: return newV1Cache(), nil @@ -43,8 +51,29 @@ func cacheForVersion(version Version) (Cache, error) { } } +func lockName(fileName string) string { + return fileName + ".lck" +} + +func lock(fileName string) (lock lockfile.Lockfile, err error) { + lockFile := lockName(fileName) + log.Debugf("Handling lock file '%s'", lockFile) + + if lock, err = lockfile.New(lockFile); err != nil { + err = fmt.Errorf("Creating lock file: %w", err) + return + } + + if err = lock.TryLock(); err != nil { + err = fmt.Errorf("Locking: %w", err) + return + } + + return +} + func storeCache(cache Cache, fileName string) error { - if cache == nil { + if cache.CacheImpl == nil { return fmt.Errorf("trying to store nil cache") } if cache.Version() != currentVersion { @@ -70,11 +99,23 @@ func storeCache(cache Cache, fileName string) error { writer.Flush() log.Printf("Stored cache to '%s'.", fileName) + if cache.locked { + if err = cache.lock.Unlock(); err != nil { + return fmt.Errorf("Unlocking cache: %w", err) + } + } return nil } func newCache() (Cache, error) { - return cacheForVersion(currentVersion) + cache, err := cacheForVersion(currentVersion) + if err != nil { + return Cache{}, err + } + return Cache{ + CacheImpl: cache, + locked: false, + }, nil } func LoadCache(fileName string) (Cache, error) { @@ -84,33 +125,38 @@ func LoadCache(fileName string) (Cache, error) { // no cache there yet -- make new return newCache() } - return nil, fmt.Errorf("opening cache at '%s': %w", fileName, err) + return Cache{}, fmt.Errorf("opening cache at '%s': %w", fileName, err) } defer f.Close() + lock, err := lock(fileName) + if err != nil { + return Cache{}, err + } + log.Printf("Loading cache from '%s'", fileName) reader := bufio.NewReader(f) version, err := reader.ReadByte() if err != nil { - return nil, fmt.Errorf("reading from '%s': %w", fileName, err) + return Cache{}, fmt.Errorf("reading from '%s': %w", fileName, err) } cache, err := cacheForVersion(Version(version)) if err != nil { - return nil, err + return Cache{}, err } decoder := gob.NewDecoder(reader) if err = decoder.Decode(cache); err != nil { - return nil, fmt.Errorf("decoding for version '%d' from '%s': %w", version, fileName, err) + return Cache{}, fmt.Errorf("decoding for version '%d' from '%s': %w", version, fileName, err) } if cache, err = cache.transformToCurrent(); err != nil { - return nil, fmt.Errorf("cannot transform from version %d to %d: %w", version, currentVersion, err) + return Cache{}, fmt.Errorf("cannot transform from version %d to %d: %w", version, currentVersion, err) } log.Printf("Loaded cache (version %d), transformed to version %d.", version, currentVersion) - return cache, nil + return Cache{cache, lock, true}, nil } -- cgit v1.2.3-54-g00ecf