Merge pull request #2178 from tonistiigi/metadata-lock

metadata: hold lock on storageitem update
v0.9
Tõnis Tiigi 2021-06-15 09:25:40 -07:00 committed by GitHub
commit 9f254e1836
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 21 additions and 14 deletions

View File

@ -205,10 +205,11 @@ func (s *Store) Close() error {
type StorageItem struct {
id string
vmu sync.RWMutex
values map[string]*Value
qmu sync.Mutex
queue []func(*bolt.Bucket) error
storage *Store
mu sync.RWMutex
}
func newStorageItem(id string, b *bolt.Bucket, s *Store) (*StorageItem, error) {
@ -242,10 +243,6 @@ func (s *StorageItem) ID() string {
return s.id
}
func (s *StorageItem) View(fn func(b *bolt.Bucket) error) error {
return s.storage.View(s.id, fn)
}
func (s *StorageItem) Update(fn func(b *bolt.Bucket) error) error {
return s.storage.Update(s.id, fn)
}
@ -255,17 +252,19 @@ func (s *StorageItem) Metadata() *StorageItem {
}
func (s *StorageItem) Keys() []string {
s.vmu.RLock()
keys := make([]string, 0, len(s.values))
for k := range s.values {
keys = append(keys, k)
}
s.vmu.RUnlock()
return keys
}
func (s *StorageItem) Get(k string) *Value {
s.mu.RLock()
s.vmu.RLock()
v := s.values[k]
s.mu.RUnlock()
s.vmu.RUnlock()
return v
}
@ -310,14 +309,14 @@ func (s *StorageItem) SetExternal(k string, dt []byte) error {
}
func (s *StorageItem) Queue(fn func(b *bolt.Bucket) error) {
s.mu.Lock()
defer s.mu.Unlock()
s.qmu.Lock()
defer s.qmu.Unlock()
s.queue = append(s.queue, fn)
}
func (s *StorageItem) Commit() error {
s.mu.Lock()
defer s.mu.Unlock()
s.qmu.Lock()
defer s.qmu.Unlock()
return errors.WithStack(s.Update(func(b *bolt.Bucket) error {
for _, fn := range s.queue {
if err := fn(b); err != nil {
@ -330,15 +329,23 @@ func (s *StorageItem) Commit() error {
}
func (s *StorageItem) Indexes() (out []string) {
s.vmu.RLock()
for _, v := range s.values {
if v.Index != "" {
out = append(out, v.Index)
}
}
s.vmu.RUnlock()
return
}
func (s *StorageItem) SetValue(b *bolt.Bucket, key string, v *Value) error {
s.vmu.Lock()
defer s.vmu.Unlock()
return s.setValue(b, key, v)
}
func (s *StorageItem) setValue(b *bolt.Bucket, key string, v *Value) error {
if v == nil {
if old, ok := s.values[key]; ok {
if old.Index != "" {
@ -378,16 +385,16 @@ func (s *StorageItem) SetValue(b *bolt.Bucket, key string, v *Value) error {
var ErrSkipSetValue = errors.New("skip setting metadata value")
func (s *StorageItem) GetAndSetValue(key string, fn func(*Value) (*Value, error)) error {
s.mu.Lock()
defer s.mu.Unlock()
return s.Update(func(b *bolt.Bucket) error {
s.vmu.Lock()
defer s.vmu.Unlock()
v, err := fn(s.values[key])
if errors.Is(err, ErrSkipSetValue) {
return nil
} else if err != nil {
return err
}
return s.SetValue(b, key, v)
return s.setValue(b, key, v)
})
}