Skip to content

Commit c22eea1

Browse files
committed
Add checkpoint tests
1 parent f4d0559 commit c22eea1

File tree

2 files changed

+62
-16
lines changed

2 files changed

+62
-16
lines changed

db.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,12 @@ const (
3434

3535
// DB represents a managed instance of a SQLite database in the file system.
3636
type DB struct {
37-
mu sync.RWMutex
38-
path string // part to database
39-
db *sql.DB // target database
40-
rtx *sql.Tx // long running read transaction
41-
pageSize int // page size, in bytes
42-
notify chan struct{} // closes on WAL change
43-
lastCheckpointAt time.Time // last checkpoint time
37+
mu sync.RWMutex
38+
path string // part to database
39+
db *sql.DB // target database
40+
rtx *sql.Tx // long running read transaction
41+
pageSize int // page size, in bytes
42+
notify chan struct{} // closes on WAL change
4443

4544
ctx context.Context
4645
cancel func()
@@ -682,7 +681,7 @@ func (db *DB) Sync() (err error) {
682681
checkpoint = true
683682
} else if db.MaxCheckpointPageN > 0 && newWALSize >= calcWALSize(db.pageSize, db.MaxCheckpointPageN) {
684683
checkpoint, checkpointMode = true, CheckpointModeRestart
685-
} else if db.CheckpointInterval > 0 && !db.lastCheckpointAt.IsZero() && time.Since(db.lastCheckpointAt) > db.CheckpointInterval && newWALSize > calcWALSize(db.pageSize, 1) {
684+
} else if db.CheckpointInterval > 0 && !info.dbModTime.IsZero() && time.Since(info.dbModTime) > db.CheckpointInterval && newWALSize > calcWALSize(db.pageSize, 1) {
686685
checkpoint = true
687686
}
688687

@@ -750,6 +749,7 @@ func (db *DB) verify() (info syncInfo, err error) {
750749
if fi, err := os.Stat(db.Path()); err != nil {
751750
return info, err
752751
} else {
752+
info.dbModTime = fi.ModTime()
753753
db.dbSizeGauge.Set(float64(fi.Size()))
754754
}
755755

@@ -826,6 +826,7 @@ func (db *DB) verify() (info syncInfo, err error) {
826826

827827
type syncInfo struct {
828828
generation string // generation name
829+
dbModTime time.Time // last modified date of real DB file
829830
walSize int64 // size of real WAL file
830831
walModTime time.Time // last modified date of real WAL file
831832
shadowWALPath string // name of last shadow WAL file
@@ -1166,8 +1167,6 @@ func (db *DB) checkpoint(mode string) (err error) {
11661167
return fmt.Errorf("release read lock: %w", err)
11671168
}
11681169

1169-
db.lastCheckpointAt = time.Now()
1170-
11711170
return nil
11721171
}
11731172

db_test.go

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -519,17 +519,64 @@ func TestDB_Sync(t *testing.T) {
519519

520520
// Ensure DB checkpoints after minimum number of pages.
521521
t.Run("MinCheckpointPageN", func(t *testing.T) {
522-
t.Skip()
523-
})
522+
db, sqldb := MustOpenDBs(t)
523+
defer MustCloseDBs(t, db, sqldb)
524+
525+
// Execute a query to force a write to the WAL and then sync.
526+
if _, err := sqldb.Exec(`CREATE TABLE foo (bar TEXT);`); err != nil {
527+
t.Fatal(err)
528+
} else if err := db.Sync(); err != nil {
529+
t.Fatal(err)
530+
}
531+
532+
// Write at least minimum number of pages to trigger rollover.
533+
for i := 0; i < db.MinCheckpointPageN; i++ {
534+
if _, err := sqldb.Exec(`INSERT INTO foo (bar) VALUES ('baz');`); err != nil {
535+
t.Fatal(err)
536+
}
537+
}
524538

525-
// Ensure DB forces checkpoint after maximum number of pages.
526-
t.Run("MaxCheckpointPageN", func(t *testing.T) {
527-
t.Skip()
539+
// Sync to shadow WAL.
540+
if err := db.Sync(); err != nil {
541+
t.Fatal(err)
542+
}
543+
544+
// Ensure position is now on the second index.
545+
if pos, err := db.Pos(); err != nil {
546+
t.Fatal(err)
547+
} else if got, want := pos.Index, 1; got != want {
548+
t.Fatalf("Index=%v, want %v", got, want)
549+
}
528550
})
529551

530552
// Ensure DB checkpoints after interval.
531553
t.Run("CheckpointInterval", func(t *testing.T) {
532-
t.Skip()
554+
db, sqldb := MustOpenDBs(t)
555+
defer MustCloseDBs(t, db, sqldb)
556+
557+
// Execute a query to force a write to the WAL and then sync.
558+
if _, err := sqldb.Exec(`CREATE TABLE foo (bar TEXT);`); err != nil {
559+
t.Fatal(err)
560+
} else if err := db.Sync(); err != nil {
561+
t.Fatal(err)
562+
}
563+
564+
// Reduce checkpoint interval to ensure a rollover is triggered.
565+
db.CheckpointInterval = 1 * time.Nanosecond
566+
567+
// Write to WAL & sync.
568+
if _, err := sqldb.Exec(`INSERT INTO foo (bar) VALUES ('baz');`); err != nil {
569+
t.Fatal(err)
570+
} else if err := db.Sync(); err != nil {
571+
t.Fatal(err)
572+
}
573+
574+
// Ensure position is now on the second index.
575+
if pos, err := db.Pos(); err != nil {
576+
t.Fatal(err)
577+
} else if got, want := pos.Index, 1; got != want {
578+
t.Fatalf("Index=%v, want %v", got, want)
579+
}
533580
})
534581
}
535582

0 commit comments

Comments
 (0)