mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-18 20:40:54 +02:00
fix: flush metadata log before closing filer store Serialize sealed-batch handoffs with shutdown, reject late appends, and wait for log-buffer workers before closing the filer metadata store. Cover queued writes, interval and explicit flushes, late-write rejection, and pending persistence with shutdown tests.
113 lines
2.9 KiB
Go
113 lines
2.9 KiB
Go
package log_buffer
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
"testing/synctest"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
|
)
|
|
|
|
func TestShutdownDrainsAcceptedRecords(t *testing.T) {
|
|
for _, seal := range []string{"append", "interval", "force"} {
|
|
t.Run(seal, func(t *testing.T) {
|
|
synctest.Test(t, func(t *testing.T) {
|
|
releaseFlush := make(chan struct{})
|
|
var persisted bytes.Buffer
|
|
lb := NewLogBuffer("shutdown", time.Hour, func(_ *LogBuffer, _, _ time.Time, data []byte, _, _ int64) {
|
|
<-releaseFlush
|
|
persisted.Write(data)
|
|
}, nil, nil)
|
|
|
|
// Fill the queue behind a blocked persistence call, leaving one
|
|
// record in the current window. Each append seals its predecessor.
|
|
var want []string
|
|
appendRecord := func() {
|
|
value := fmt.Sprint(len(want))
|
|
ts := time.Now().Add(time.Duration(len(want)) * 2 * time.Hour).UnixNano()
|
|
if err := lb.AddDataToBuffer(nil, []byte(value), ts); err != nil {
|
|
t.Error(err)
|
|
}
|
|
want = append(want, value)
|
|
}
|
|
for range flushQueueDepth + 2 {
|
|
appendRecord()
|
|
synctest.Wait()
|
|
}
|
|
switch seal {
|
|
case "append":
|
|
go appendRecord()
|
|
case "interval":
|
|
time.Sleep(time.Hour)
|
|
case "force":
|
|
go lb.ForceFlush()
|
|
}
|
|
synctest.Wait()
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
lb.ShutdownLogBuffer()
|
|
lb.WaitForShutdown()
|
|
close(done)
|
|
}()
|
|
<-lb.shutdownCh
|
|
select {
|
|
case <-done:
|
|
t.Error("shutdown completed while persistence was blocked")
|
|
default:
|
|
}
|
|
|
|
close(releaseFlush)
|
|
<-done
|
|
synctest.Wait()
|
|
var got []string
|
|
for persisted.Len() > 0 {
|
|
size := util.BytesToUint32(persisted.Next(4))
|
|
var entry filer_pb.LogEntry
|
|
if err := entry.UnmarshalVT(persisted.Next(int(size))); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got = append(got, string(entry.Data))
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("persisted records = %v, want %v", got, want)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShutdownRejectsNewRecords(t *testing.T) {
|
|
synctest.Test(t, func(t *testing.T) {
|
|
lb := NewLogBuffer("stopped", time.Hour, nil, nil, nil)
|
|
lb.ShutdownLogBuffer()
|
|
for _, appendRecord := range []func() error{
|
|
func() error { return lb.AddDataToBuffer(nil, []byte("late data"), 0) },
|
|
func() error { return lb.AddLogEntryToBuffer(&filer_pb.LogEntry{Data: []byte("late entry")}) },
|
|
} {
|
|
if err := appendRecord(); !errors.Is(err, ErrBufferStopped) {
|
|
t.Errorf("append after shutdown = %v, want ErrBufferStopped", err)
|
|
}
|
|
}
|
|
lb.ForceFlush()
|
|
lb.WaitForShutdown()
|
|
if lb.pos != 0 {
|
|
t.Errorf("stopped buffer retained %d bytes", lb.pos)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWaitForShutdownWithEmptyBuffer(t *testing.T) {
|
|
synctest.Test(t, func(t *testing.T) {
|
|
lb := NewLogBuffer("empty", time.Hour, nil, nil, nil)
|
|
lb.ShutdownLogBuffer()
|
|
lb.WaitForShutdown()
|
|
lb.WaitForShutdown()
|
|
})
|
|
}
|