Skip to content

Commit

Permalink
Periodically do manual checkpoints to sync the DB file with the WAL.
Browse files Browse the repository at this point in the history
This is more efficient as it allows idle connections to stick around, reducing
the overhead of sporadic queries. For example, opening the first new connection
will cause creation of new WAL files (and then their subsequent deletion when
all connections are closed); this work is avoided by just keeping it open.
  • Loading branch information
LTLA committed Sep 14, 2024
1 parent 3684da2 commit 2849b17
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 10 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,10 @@ Additional arguments can be passed to `./SewerRat` to control its behavior (chec
- `-update` controls the frequency of index updates.
This defaults to 24 hours.
- `-session` specifies the lifetime of a registration sesssion
(i.e., the maximum time between starting and finishing the registration, see below).
(i.e., the maximum time between starting and finishing the registration, see above).
This defaults to 10 minutes.
- `-checkpoint` specifies the frequency of SQLite checkpoints, to manually synchronize the write-ahead log with the SQLite database file.
This defaults to 60 minutes.
- `-finish` specifies the time spent polling for the verification code after a request has been made to `/register/finish` or `/deregister/finish`.
A non-zero value is often necessary on network filesystems where newly written files do not immediately synchronize.
This defaults to 30 seconds.
Expand Down
9 changes: 0 additions & 9 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ func initializeDatabase(path string) (*sql.DB, error) {
// time; everyone else will have to block on the connection availability.
db.SetMaxOpenConns(1)

// Make sure to eventually close all idle connections in the pool so that
// SQLite actually commits its WAL journal.
db.SetConnMaxIdleTime(1 * time.Minute)

if (!accessible) {
err := func () error {
atx, err := createTransaction(db)
Expand Down Expand Up @@ -176,11 +172,6 @@ func initializeReadOnlyDatabase(path string) (*sql.DB, error) {
if err != nil {
return nil, fmt.Errorf("failed to open read-only SQLite handle; %w", err)
}

// Make sure to eventually close all idle connections in the pool so that
// SQLite actually commits its WAL journal.
ro_db.SetConnMaxIdleTime(1 * time.Minute)

return ro_db, nil
}

Expand Down
14 changes: 14 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func main() {
timeout0 := flag.Int("finish", 30, "Maximum time spent polling for the verification code when finishing (de)registration, in seconds")
prefix0 := flag.String("prefix", "", "Prefix to add to each endpoint, after removing any leading or trailing slashes (default \"\")")
lifetime0 := flag.Int("session", 10, "Maximum lifetime of a (de)registration session from start to finish, in minutes")
checkpoint0 := flag.Int("checkpoint", 60, "Frequency of checkpoints to synchronise the WAL journal with the SQLite file, in minutes")
flag.Parse()

dbpath := *dbpath0
Expand Down Expand Up @@ -66,6 +67,19 @@ func main() {

http.HandleFunc(prefix + "/", newDefaultHandler())

// Adding an hourly job that does a full checkpoint.
{
lifetime := time.Duration(*checkpoint0) * time.Minute
ticker := time.NewTicker(lifetime)
defer ticker.Stop()
go func() {
for {
<-ticker.C
db.Exec("PRAGMA wal_checkpoint(PASSIVE)")
}
}()
}

// Adding a hour job that purges various old verification sessions.
{
lifetime := time.Duration(*lifetime0) * time.Minute
Expand Down

0 comments on commit 2849b17

Please sign in to comment.