Skip to content

Commit 4b77ba1

Browse files
authored
Exit on WAL commit failure (#405)
1 parent a960f04 commit 4b77ba1

File tree

7 files changed

+244
-204
lines changed

7 files changed

+244
-204
lines changed

cmd/litefs/mount_linux.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ type MountCommand struct {
3535

3636
Config Config
3737

38-
OS litefs.OS
38+
OS litefs.OS
39+
Exit func(int)
40+
3941
Store *litefs.Store
4042
Leaser litefs.Leaser
4143
FileSystem *fuse.FileSystem
@@ -52,6 +54,7 @@ func NewMountCommand() *MountCommand {
5254
execCh: make(chan error),
5355
Config: NewConfig(),
5456
OS: &internal.SystemOS{},
57+
Exit: os.Exit,
5558
}
5659
}
5760

@@ -351,6 +354,7 @@ func (c *MountCommand) initConsul(ctx context.Context) (err error) {
351354
func (c *MountCommand) initStore(ctx context.Context) error {
352355
c.Store = litefs.NewStore(c.Config.Data.Dir, c.Config.Lease.Candidate)
353356
c.Store.OS = c.OS
357+
c.Store.Exit = c.Exit
354358
c.Store.StrictVerify = c.Config.StrictVerify
355359
c.Store.Compress = c.Config.Data.Compress
356360
c.Store.Retention = c.Config.Data.Retention

cmd/litefs/mount_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
main "github.com/superfly/litefs/cmd/litefs"
3131
"github.com/superfly/litefs/internal"
3232
"github.com/superfly/litefs/internal/testingutil"
33+
"github.com/superfly/litefs/mock"
3334
"github.com/superfly/ltx"
3435
"golang.org/x/exp/slog"
3536
"golang.org/x/net/http2"
@@ -328,6 +329,60 @@ func TestSingleNode_DropDB(t *testing.T) {
328329
}
329330
}
330331

332+
func TestSingleNode_ErrCommitWAL(t *testing.T) {
333+
if !testingutil.IsWALMode() {
334+
t.Skip("test failure only applies to WAL mode, skipping")
335+
}
336+
337+
mos := mock.NewOS()
338+
dir := t.TempDir()
339+
cmd0 := newMountCommand(t, dir, nil)
340+
cmd0.OS = mos
341+
runMountCommand(t, cmd0)
342+
db := testingutil.OpenSQLDB(t, filepath.Join(cmd0.Config.FUSE.Dir, "db"))
343+
344+
if _, err := db.Exec(`CREATE TABLE t (x)`); err != nil {
345+
t.Fatal(err)
346+
} else if _, err := db.Exec(`INSERT INTO t VALUES (100)`); err != nil {
347+
t.Fatal(err)
348+
}
349+
350+
var exitCode int
351+
cmd0.Store.Exit = func(code int) {
352+
exitCode = code
353+
}
354+
mos.OpenFunc = func(op, name string) (*os.File, error) {
355+
if op == "COMMITWAL:WAL" {
356+
return nil, fmt.Errorf("marker")
357+
}
358+
return os.Open(name)
359+
}
360+
if _, err := db.Exec(`INSERT INTO t VALUES (200)`); err != nil {
361+
t.Fatal(err)
362+
}
363+
364+
if got, want := exitCode, 99; got != want {
365+
t.Fatalf("exit=%d, want=%d", got, want)
366+
}
367+
if err := db.Close(); err != nil {
368+
t.Fatal(err)
369+
} else if err := cmd0.Close(); err != nil {
370+
t.Fatal(err)
371+
}
372+
373+
// Restart the mount command.
374+
cmd0 = runMountCommand(t, newMountCommand(t, dir, nil))
375+
db = testingutil.OpenSQLDB(t, filepath.Join(cmd0.Config.FUSE.Dir, "db"))
376+
377+
// Ensure the second insert was not processed.
378+
var x int
379+
if err := db.QueryRow(`SELECT SUM(x) FROM t`).Scan(&x); err != nil {
380+
t.Fatal(err)
381+
} else if got, want := x, 100; got != want {
382+
t.Fatalf("x=%d, want %d", got, want)
383+
}
384+
}
385+
331386
func TestSingleNode_BackupClient(t *testing.T) {
332387
t.Run("OK", func(t *testing.T) {
333388
cmd0 := newMountCommand(t, t.TempDir(), nil)

0 commit comments

Comments
 (0)