Skip to content

Commit

Permalink
Use separate SQLite connection pools for reading and writing.
Browse files Browse the repository at this point in the history
By only allowing a single write connection, we can leverage database/sql's
auto-blocking behavior to avoid SQLITE_BUSY errors on multiple write requests.
  • Loading branch information
LTLA committed Sep 14, 2024
1 parent ae399f7 commit 9437787
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 11 deletions.
27 changes: 23 additions & 4 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,16 @@ func initializeDatabase(path string) (*sql.DB, error) {
accessible = true
}

db, err := sql.Open("sqlite", path)
if err != nil {
return nil, fmt.Errorf("failed to create SQLite file at %q; %w", path, err)
}
// This object's connections are intended for serial writing, so we set
// IMMEDIATE transactions to make debugging of locking issues easier.
db, err := sql.Open("sqlite", path + "?_txlock=immediate")
if err != nil {
return nil, fmt.Errorf("failed to open read/write SQLite handle; %w", err)
}

// Maxing out at one connection so that there can only be one write at any
// 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.
Expand Down Expand Up @@ -165,6 +171,19 @@ CREATE INDEX index_links ON links(tid, fid);
return db, nil
}

func initializeReadOnlyDatabase(path string) (*sql.DB, error) {
ro_db, err := sql.Open("sqlite", path + "?_pragma=query_only(1)")
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
}

/**********************************************************************/

// Pre-building the insertion statements for efficiency when iterating over and
Expand Down
20 changes: 13 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ func main() {

db, err := initializeDatabase(dbpath)
if err != nil {
log.Fatalf("failed to create the initial SQLite file at %q; %v", dbpath, err)
log.Fatalf("failed to initialize SQLite file at %q; %v", dbpath, err)
}
defer db.Close()

ro_db, err := initializeReadOnlyDatabase(dbpath)
if err != nil {
log.Fatalf("failed to create read-only connections to %q; %w", dbpath, err)

Check failure on line 32 in main.go

View workflow job for this annotation

GitHub Actions / test

log.Fatalf does not support error-wrapping directive %w
}
defer ro_db.Close()

tokenizer, err := newUnicodeTokenizer(false)
if err != nil {
log.Fatalf("failed to create the default tokenizer; %v", err)
Expand All @@ -49,14 +55,14 @@ func main() {
// Setting up the endpoints.
http.HandleFunc("POST " + prefix + "/register/start", newRegisterStartHandler(verifier))
http.HandleFunc("POST " + prefix + "/register/finish", newRegisterFinishHandler(db, verifier, tokenizer, timeout))
http.HandleFunc("POST " + prefix + "/deregister/start", newDeregisterStartHandler(db, verifier))
http.HandleFunc("POST " + prefix + "/deregister/start", newDeregisterStartHandler(ro_db, verifier))
http.HandleFunc("POST " + prefix + "/deregister/finish", newDeregisterFinishHandler(db, verifier, timeout))

http.HandleFunc(prefix + "/registered", newListRegisteredDirectoriesHandler(db))
http.HandleFunc(prefix + "/query", newQueryHandler(db, tokenizer, wild_tokenizer, "/query"))
http.HandleFunc(prefix + "/retrieve/metadata", newRetrieveMetadataHandler(db))
http.HandleFunc(prefix + "/retrieve/file", newRetrieveFileHandler(db))
http.HandleFunc(prefix + "/list", newListFilesHandler(db))
http.HandleFunc(prefix + "/registered", newListRegisteredDirectoriesHandler(ro_db))
http.HandleFunc(prefix + "/query", newQueryHandler(ro_db, tokenizer, wild_tokenizer, "/query"))
http.HandleFunc(prefix + "/retrieve/metadata", newRetrieveMetadataHandler(ro_db))
http.HandleFunc(prefix + "/retrieve/file", newRetrieveFileHandler(ro_db))
http.HandleFunc(prefix + "/list", newListFilesHandler(ro_db))

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

Expand Down

0 comments on commit 9437787

Please sign in to comment.