Update metadata interfaces for containers and leases
Add more thorough dirty checking across all types which may be deleted and hold references. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
@@ -75,10 +76,16 @@ type DB struct {
|
||||
// sweep phases without preventing read transactions.
|
||||
wlock sync.RWMutex
|
||||
|
||||
// dirty flags and lock keeps track of datastores which have had deletions
|
||||
// since the last garbage collection. These datastores will will be garbage
|
||||
// collected during the next garbage collection.
|
||||
dirtyL sync.Mutex
|
||||
// dirty flag indicates that refences have been removed which require
|
||||
// a garbage collection to ensure the database is clean. This tracks
|
||||
// the number of dirty operations. This should be updated and read
|
||||
// atomically if outside of wlock.Lock.
|
||||
dirty uint32
|
||||
|
||||
// dirtySS and dirtyCS flags keeps track of datastores which have had
|
||||
// deletions since the last garbage collection. These datastores will
|
||||
// be garbage collected during the next garbage collection. These
|
||||
// should only be updated inside of a write transaction or wlock.Lock.
|
||||
dirtySS map[string]struct{}
|
||||
dirtyCS bool
|
||||
|
||||
@@ -237,12 +244,10 @@ func (m *DB) Update(fn func(*bolt.Tx) error) error {
|
||||
defer m.wlock.RUnlock()
|
||||
err := m.db.Update(fn)
|
||||
if err == nil {
|
||||
m.dirtyL.Lock()
|
||||
dirty := m.dirtyCS || len(m.dirtySS) > 0
|
||||
dirty := atomic.LoadUint32(&m.dirty) > 0
|
||||
for _, fn := range m.mutationCallbacks {
|
||||
fn(dirty)
|
||||
}
|
||||
m.dirtyL.Unlock()
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -254,9 +259,9 @@ func (m *DB) Update(fn func(*bolt.Tx) error) error {
|
||||
// The callback function is an argument for whether a deletion has occurred
|
||||
// since the last garbage collection.
|
||||
func (m *DB) RegisterMutationCallback(fn func(bool)) {
|
||||
m.dirtyL.Lock()
|
||||
m.wlock.Lock()
|
||||
m.mutationCallbacks = append(m.mutationCallbacks, fn)
|
||||
m.dirtyL.Unlock()
|
||||
m.wlock.Unlock()
|
||||
}
|
||||
|
||||
// GCStats holds the duration for the different phases of the garbage collector
|
||||
@@ -282,8 +287,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.dirtyL.Lock()
|
||||
|
||||
if err := m.db.Update(func(tx *bolt.Tx) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
@@ -309,7 +312,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
m.dirtyL.Unlock()
|
||||
m.wlock.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
@@ -317,6 +319,9 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
var stats GCStats
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// reset dirty, no need for atomic inside of wlock.Lock
|
||||
m.dirty = 0
|
||||
|
||||
if len(m.dirtySS) > 0 {
|
||||
var sl sync.Mutex
|
||||
stats.SnapshotD = map[string]time.Duration{}
|
||||
@@ -349,8 +354,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
m.dirtyCS = false
|
||||
}
|
||||
|
||||
m.dirtyL.Unlock()
|
||||
|
||||
stats.MetaD = time.Since(t1)
|
||||
m.wlock.Unlock()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user