Skip to content

Commit 1252e2a

Browse files
fix(manager): keep skipped daemon records in the store
A missing config file does not prove the daemon behind the record is dead. Keep the record so a later restart can re-adopt the daemon once the config is restored; only drop the in-memory registration. Signed-off-by: Iaroslav Geraskin <iaroslav@reflection.ai>
1 parent 0b1ef10 commit 1252e2a

2 files changed

Lines changed: 17 additions & 21 deletions

File tree

pkg/manager/manager.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,9 @@ func (m *Manager) recoverDaemons(ctx context.Context,
314314
// Records whose on-disk artifacts are damaged — e.g. a daemon that was
315315
// persisted but whose config file never made it to disk. One damaged
316316
// record must not abort the whole walk: returning an error here fails
317-
// NewSnapshotter, and since the record is never pruned the snapshotter
318-
// crash-loops on every restart until the database is repaired by hand.
319-
var quarantined []*daemon.Daemon
317+
// NewSnapshotter, crash-looping the snapshotter on every restart until
318+
// the database is repaired by hand. The record itself is kept: restoring
319+
// the config file lets a later restart re-adopt the daemon.
320320
if err := m.store.WalkDaemons(ctx, func(s *daemon.ConfigState) error {
321321
if s.FsDriver != m.FsDriver {
322322
return nil
@@ -340,8 +340,8 @@ func (m *Manager) recoverDaemons(ctx context.Context,
340340
if d.States.FsDriver == config.FsDriverFusedev {
341341
cfg, err := daemonconfig.NewDaemonConfig(d.States.FsDriver, d.ConfigFile(""))
342342
if err != nil {
343-
log.L.Errorf("Quarantining daemon %s: failed to reload configuration %s, %s", d.ID(), d.ConfigFile(""), err)
344-
quarantined = append(quarantined, d)
343+
log.L.Errorf("Skipping recovery of daemon %s: failed to reload configuration %s, %s", d.ID(), d.ConfigFile(""), err)
344+
m.daemonCache.Remove(d)
345345
//nolint:nilerr
346346
return nil
347347
}
@@ -395,17 +395,5 @@ func (m *Manager) recoverDaemons(ctx context.Context,
395395
return errors.Wrapf(err, "walk daemons to reconnect")
396396
}
397397

398-
// Prune quarantined records outside the walk since the bucket must not be
399-
// mutated during ForEach. A daemon without its configuration cannot be
400-
// recovered or managed; dropping the record keeps the next restart from
401-
// tripping over it again, and orphan process cleanup is handled by the
402-
// regular vestige clearing.
403-
for _, d := range quarantined {
404-
m.daemonCache.Remove(d)
405-
if err := m.store.DeleteDaemon(d.ID()); err != nil {
406-
log.L.WithError(err).Warnf("failed to prune quarantined daemon record %s", d.ID())
407-
}
408-
}
409-
410398
return nil
411399
}

pkg/manager/manager_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"github.com/containerd/nydus-snapshotter/pkg/store"
1919
)
2020

21-
func TestRecoverDaemonsQuarantinesRecordsWithoutConfig(t *testing.T) {
21+
func TestRecoverDaemonsSkipsRecordsWithoutConfig(t *testing.T) {
2222
rootDir := t.TempDir()
2323
db, err := store.NewDatabase(rootDir)
2424
require.NoError(t, err)
@@ -69,14 +69,22 @@ func TestRecoverDaemonsQuarantinesRecordsWithoutConfig(t *testing.T) {
6969
assert.Empty(t, recovering)
7070
assert.Empty(t, live)
7171

72-
// The damaged records are pruned so the next restart does not trip over
73-
// them again; the unrelated record is untouched.
72+
// The damaged records stay in the store: a missing config file does not
73+
// prove the daemon is dead, and keeping the record lets a later restart
74+
// re-adopt the daemon once the file is restored.
7475
remaining := make(map[string]string)
7576
require.NoError(t, m.store.WalkDaemons(context.Background(), func(s *daemon.ConfigState) error {
7677
remaining[s.ID] = s.FsDriver
7778
return nil
7879
}))
79-
assert.Equal(t, map[string]string{other.ID(): config.FsDriverFscache}, remaining)
80+
expected := map[string]string{other.ID(): config.FsDriverFscache}
81+
for _, d := range poisoned {
82+
expected[d.ID()] = config.FsDriverFusedev
83+
}
84+
assert.Equal(t, expected, remaining)
85+
86+
// Only the in-memory registration is dropped, so no half-initialized
87+
// daemon without its configuration lingers in the cache.
8088
for _, d := range poisoned {
8189
assert.Nil(t, m.daemonCache.GetByDaemonID(d.ID(), nil))
8290
}

0 commit comments

Comments
 (0)