diff --git a/y/y.go b/y/y.go index 14122234f..5e6dd5b25 100644 --- a/y/y.go +++ b/y/y.go @@ -191,8 +191,9 @@ func FixedDuration(d time.Duration) string { // to tell the goroutine to shut down, and a WaitGroup with which to wait for it to finish shutting // down. type Closer struct { - closed chan struct{} - waiting sync.WaitGroup + closed chan struct{} + waiting sync.WaitGroup + closeOnce sync.Once } // NewCloser constructs a new Closer, with an initial count on the WaitGroup. @@ -209,7 +210,10 @@ func (lc *Closer) AddRunning(delta int) { // Signal signals the HasBeenClosed signal. func (lc *Closer) Signal() { - close(lc.closed) + // Todo(ibrahim): Change Signal to return error on next badger breaking change. + lc.closeOnce.Do(func() { + close(lc.closed) + }) } // HasBeenClosed gets signaled when Signal() is called. diff --git a/y/y_test.go b/y/y_test.go index d1b963184..fe14cf4c8 100644 --- a/y/y_test.go +++ b/y/y_test.go @@ -254,3 +254,20 @@ func TestPagebufferReader4(t *testing.T) { require.Equal(t, err, io.EOF, "should return EOF") require.Equal(t, n, 0) } + +func TestMulipleSignals(t *testing.T) { + closer := NewCloser(0) + require.NotPanics(t, func() { closer.Signal() }) + // Should not panic. + require.NotPanics(t, func() { closer.Signal() }) + require.NotPanics(t, func() { closer.SignalAndWait() }) + + // Attempt 2. + closer = NewCloser(1) + require.NotPanics(t, func() { closer.Done() }) + + require.NotPanics(t, func() { closer.SignalAndWait() }) + // Should not panic. + require.NotPanics(t, func() { closer.SignalAndWait() }) + require.NotPanics(t, func() { closer.Signal() }) +}