Merge pull request #380 from Random-Liu/fix-deadlock

Do not call `Usage` inside `Walk`.
This commit is contained in:
Lantao Liu 2017-11-01 22:04:10 +01:00 committed by GitHub
commit 8679d10733
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -18,6 +18,7 @@ package server
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
@ -68,14 +69,25 @@ func (s *snapshotsSyncer) start() {
// sync updates all snapshots stats. // sync updates all snapshots stats.
func (s *snapshotsSyncer) sync() error { func (s *snapshotsSyncer) sync() error {
start := time.Now().UnixNano() start := time.Now().UnixNano()
collect := func(ctx context.Context, info snapshot.Info) error { var snapshots []snapshot.Info
// Do not call `Usage` directly in collect function, because
// `Usage` takes time, we don't want `Walk` to hold read lock
// of snapshot metadata store for too long time.
// TODO(random-liu): Set timeout for the following 2 contexts.
if err := s.snapshotter.Walk(context.Background(), func(ctx context.Context, info snapshot.Info) error {
snapshots = append(snapshots, info)
return nil
}); err != nil {
return fmt.Errorf("walk all snapshots failed: %v", err)
}
for _, info := range snapshots {
sn, err := s.store.Get(info.Name) sn, err := s.store.Get(info.Name)
if err == nil { if err == nil {
// Only update timestamp for non-active snapshot. // Only update timestamp for non-active snapshot.
if sn.Kind == info.Kind && sn.Kind != snapshot.KindActive { if sn.Kind == info.Kind && sn.Kind != snapshot.KindActive {
sn.Timestamp = time.Now().UnixNano() sn.Timestamp = time.Now().UnixNano()
s.store.Add(sn) s.store.Add(sn)
return nil continue
} }
} }
// Get newest stats if the snapshot is new or active. // Get newest stats if the snapshot is new or active.
@ -84,20 +96,16 @@ func (s *snapshotsSyncer) sync() error {
Kind: info.Kind, Kind: info.Kind,
Timestamp: time.Now().UnixNano(), Timestamp: time.Now().UnixNano(),
} }
usage, err := s.snapshotter.Usage(ctx, info.Name) usage, err := s.snapshotter.Usage(context.Background(), info.Name)
if err != nil { if err != nil {
if errdefs.IsNotFound(err) { if !errdefs.IsNotFound(err) {
return nil glog.Errorf("Failed to get usage for snapshot %q: %v", info.Name, err)
} }
return err continue
} }
sn.Size = uint64(usage.Size) sn.Size = uint64(usage.Size)
sn.Inodes = uint64(usage.Inodes) sn.Inodes = uint64(usage.Inodes)
s.store.Add(sn) s.store.Add(sn)
return nil
}
if err := s.snapshotter.Walk(context.Background(), collect); err != nil {
return err
} }
for _, sn := range s.store.List() { for _, sn := range s.store.List() {
if sn.Timestamp >= start { if sn.Timestamp >= start {