From 64518b0f7e74ad5f6d42f9a3b6ffc1f74b61c2f0 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Sat, 25 May 2019 16:00:32 +0200 Subject: [PATCH] lib/model: Close connections when model is stopped (#5733) --- lib/model/model.go | 20 ++++++++++++++++++++ lib/model/model_test.go | 17 ++--------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/model/model.go b/lib/model/model.go index d9b16e618..b3dd341d8 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -180,6 +180,7 @@ var ( // errors about why a connection is closed errIgnoredFolderRemoved = errors.New("folder no longer ignored") errReplacingConnection = errors.New("replacing connection") + errStopped = errors.New("Syncthing is being stopped") ) // NewModel creates and starts a new model. The model starts in read-only mode, @@ -225,6 +226,25 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio return m } +func (m *model) Stop() { + m.Supervisor.Stop() + devs := m.cfg.Devices() + ids := make([]protocol.DeviceID, 0, len(devs)) + for id := range devs { + ids = append(ids, id) + } + m.pmut.RLock() + closed := make([]chan struct{}, 0, len(m.closed)) + for _, c := range m.closed { + closed = append(closed, c) + } + m.pmut.RUnlock() + m.closeConns(ids, errStopped) + for _, c := range closed { + <-c + } +} + // StartDeadlockDetector starts a deadlock detector on the models locks which // causes panics in case the locks cannot be acquired in the given timeout // period. diff --git a/lib/model/model_test.go b/lib/model/model_test.go index f164b86d5..2ba864be6 100644 --- a/lib/model/model_test.go +++ b/lib/model/model_test.go @@ -862,15 +862,6 @@ func TestIssue5063(t *testing.T) { m := newState(defaultAutoAcceptCfg) defer cleanupModel(m) - m.pmut.Lock() - for _, c := range m.conn { - conn := c.(*fakeConnection) - conn.mut.Lock() - conn.closeFn = func(_ error) {} - conn.mut.Unlock() - } - m.pmut.Unlock() - wg := sync.WaitGroup{} addAndVerify := func(id string) { @@ -3267,12 +3258,7 @@ func TestSanitizePath(t *testing.T) { func TestConnCloseOnRestart(t *testing.T) { w, fcfg := tmpDefaultWrapper() m := setupModel(w) - defer func() { - m.Stop() - m.db.Close() - os.RemoveAll(fcfg.Filesystem().URI()) - os.Remove(w.ConfigPath()) - }() + defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI()) br := &testutils.BlockingRW{} nw := &testutils.NoopRW{} @@ -3291,6 +3277,7 @@ func TestConnCloseOnRestart(t *testing.T) { t.Fatal("Timed out before folder restart returned") } m.pmut.RLock() + defer m.pmut.RUnlock() if len(m.conn) != 0 { t.Errorf("Conn wasn't removed on restart (len(m.conn) == %v)", len(m.conn)) }