cache: fix `fatal error: concurrent map writes` - fixes #2378

This commit is contained in:
Nick Craig-Wood 2019-06-04 17:18:23 +01:00
parent 4499b08afc
commit 08a3957880
1 changed files with 18 additions and 10 deletions

View File

@ -24,15 +24,16 @@ const (
type Object struct { type Object struct {
fs.Object `json:"-"` fs.Object `json:"-"`
ParentFs fs.Fs `json:"-"` // parent fs ParentFs fs.Fs `json:"-"` // parent fs
CacheFs *Fs `json:"-"` // cache fs CacheFs *Fs `json:"-"` // cache fs
Name string `json:"name"` // name of the directory Name string `json:"name"` // name of the directory
Dir string `json:"dir"` // abs path of the object Dir string `json:"dir"` // abs path of the object
CacheModTime int64 `json:"modTime"` // modification or creation time - IsZero for unknown CacheModTime int64 `json:"modTime"` // modification or creation time - IsZero for unknown
CacheSize int64 `json:"size"` // size of directory and contents or -1 if unknown CacheSize int64 `json:"size"` // size of directory and contents or -1 if unknown
CacheStorable bool `json:"storable"` // says whether this object can be stored CacheStorable bool `json:"storable"` // says whether this object can be stored
CacheType string `json:"cacheType"` CacheType string `json:"cacheType"`
CacheTs time.Time `json:"cacheTs"` CacheTs time.Time `json:"cacheTs"`
cacheHashesMu sync.Mutex
CacheHashes map[hash.Type]string // all supported hashes cached CacheHashes map[hash.Type]string // all supported hashes cached
refreshMutex sync.Mutex refreshMutex sync.Mutex
@ -103,7 +104,9 @@ func (o *Object) updateData(ctx context.Context, source fs.Object) {
o.CacheSize = source.Size() o.CacheSize = source.Size()
o.CacheStorable = source.Storable() o.CacheStorable = source.Storable()
o.CacheTs = time.Now() o.CacheTs = time.Now()
o.cacheHashesMu.Lock()
o.CacheHashes = make(map[hash.Type]string) o.CacheHashes = make(map[hash.Type]string)
o.cacheHashesMu.Unlock()
} }
// Fs returns its FS info // Fs returns its FS info
@ -268,7 +271,9 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
o.CacheModTime = src.ModTime(ctx).UnixNano() o.CacheModTime = src.ModTime(ctx).UnixNano()
o.CacheSize = src.Size() o.CacheSize = src.Size()
o.cacheHashesMu.Lock()
o.CacheHashes = make(map[hash.Type]string) o.CacheHashes = make(map[hash.Type]string)
o.cacheHashesMu.Unlock()
o.CacheTs = time.Now() o.CacheTs = time.Now()
o.persist() o.persist()
@ -309,11 +314,12 @@ func (o *Object) Remove(ctx context.Context) error {
// since it might or might not be called, this is lazy loaded // since it might or might not be called, this is lazy loaded
func (o *Object) Hash(ctx context.Context, ht hash.Type) (string, error) { func (o *Object) Hash(ctx context.Context, ht hash.Type) (string, error) {
_ = o.refresh(ctx) _ = o.refresh(ctx)
o.cacheHashesMu.Lock()
if o.CacheHashes == nil { if o.CacheHashes == nil {
o.CacheHashes = make(map[hash.Type]string) o.CacheHashes = make(map[hash.Type]string)
} }
cachedHash, found := o.CacheHashes[ht] cachedHash, found := o.CacheHashes[ht]
o.cacheHashesMu.Unlock()
if found { if found {
return cachedHash, nil return cachedHash, nil
} }
@ -324,7 +330,9 @@ func (o *Object) Hash(ctx context.Context, ht hash.Type) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
o.cacheHashesMu.Lock()
o.CacheHashes[ht] = liveHash o.CacheHashes[ht] = liveHash
o.cacheHashesMu.Unlock()
o.persist() o.persist()
fs.Debugf(o, "object hash cached: %v", liveHash) fs.Debugf(o, "object hash cached: %v", liveHash)