From 9a67852399279b4dcba9097c57ade93174e419f9 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Thu, 1 Oct 2026 13:17:22 +0200 Subject: [PATCH 1/2] db: share SQLite memory databases across connections --- pkg/db/common.go | 13 +++++++- pkg/db/common_test.go | 71 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 pkg/db/common_test.go diff --git a/pkg/db/common.go b/pkg/db/common.go index 20e4e672..fcae2875 100644 --- a/pkg/db/common.go +++ b/pkg/db/common.go @@ -3,6 +3,7 @@ package db import ( "embed" "fmt" + "strings" "sync" "time" @@ -88,7 +89,17 @@ func (db *Database) initSqlite(config *SqliteDatabaseConfig) error { db.logger.Infof("initializing sqlite connection to %v with %v/%v conn limit", config.File, config.MaxIdleConns, config.MaxOpenConns) - dbConn, err := sqlx.Open("sqlite", fmt.Sprintf("%s?_pragma=journal_mode(WAL)", config.File)) + dsn := config.File + if strings.HasPrefix(dsn, ":memory:?") { + dsn = "file:" + dsn + } + + separator := "?" + if strings.Contains(dsn, "?") { + separator = "&" + } + + dbConn, err := sqlx.Open("sqlite", fmt.Sprintf("%s%s_pragma=journal_mode(WAL)", dsn, separator)) if err != nil { return fmt.Errorf("error opening sqlite database: %v", err) } diff --git a/pkg/db/common_test.go b/pkg/db/common_test.go new file mode 100644 index 00000000..9a33d1ba --- /dev/null +++ b/pkg/db/common_test.go @@ -0,0 +1,71 @@ +package db + +import ( + "path/filepath" + "testing" + + "github.com/jmoiron/sqlx" + "github.com/sirupsen/logrus" +) + +func TestSqliteSharesDataAcrossConnections(t *testing.T) { + tests := []struct { + name string + file string + }{ + {name: "default memory", file: ":memory:?cache=shared"}, + {name: "memory URI", file: "file::memory:?cache=shared"}, + {name: "named memory URI", file: "file:assertoor-test?mode=memory&cache=shared"}, + {name: "file", file: filepath.Join(t.TempDir(), "assertoor.db")}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + database := NewDatabase(logrus.New()) + if err := database.InitDB(&DatabaseConfig{ + Engine: "sqlite", + Sqlite: &SqliteDatabaseConfig{File: test.file}, + }); err != nil { + t.Fatal(err) + } + + t.Cleanup(func() { + if err := database.CloseDB(); err != nil { + t.Error(err) + } + }) + + if err := database.ApplySchema(-2); err != nil { + t.Fatal(err) + } + + want := &TaskLog{RunID: 1, TaskID: 1, LogIndex: 1, LogMessage: "shared log"} + + if err := database.RunTransaction(func(tx *sqlx.Tx) error { + return database.InsertTaskLog(tx, want) + }); err != nil { + t.Fatal(err) + } + + conn, err := database.reader.Conn(t.Context()) + if err != nil { + t.Fatal(err) + } + + t.Cleanup(func() { + if closeErr := conn.Close(); closeErr != nil { + t.Error(closeErr) + } + }) + + logs, err := database.GetTaskLogs(want.RunID, want.TaskID, 0, 1) + if err != nil { + t.Fatalf("read task logs on a second connection: %v", err) + } + + if len(logs) != 1 || *logs[0] != *want { + t.Fatalf("task logs = %v, want %v", logs, want) + } + }) + } +} From ab8f4155a03e535bd8d4a213ca6802efb787f89e Mon Sep 17 00:00:00 2001 From: yperbasis Date: Thu, 1 Oct 2026 16:37:49 +0200 Subject: [PATCH 2/2] db: share bare in-memory SQLite databases --- pkg/db/common.go | 4 ++++ pkg/db/common_test.go | 1 + 2 files changed, 5 insertions(+) diff --git a/pkg/db/common.go b/pkg/db/common.go index fcae2875..47d4a60b 100644 --- a/pkg/db/common.go +++ b/pkg/db/common.go @@ -90,6 +90,10 @@ func (db *Database) initSqlite(config *SqliteDatabaseConfig) error { db.logger.Infof("initializing sqlite connection to %v with %v/%v conn limit", config.File, config.MaxIdleConns, config.MaxOpenConns) dsn := config.File + if dsn == ":memory:" { + dsn += "?cache=shared" + } + if strings.HasPrefix(dsn, ":memory:?") { dsn = "file:" + dsn } diff --git a/pkg/db/common_test.go b/pkg/db/common_test.go index 9a33d1ba..7169f7fe 100644 --- a/pkg/db/common_test.go +++ b/pkg/db/common_test.go @@ -13,6 +13,7 @@ func TestSqliteSharesDataAcrossConnections(t *testing.T) { name string file string }{ + {name: "bare memory", file: ":memory:"}, {name: "default memory", file: ":memory:?cache=shared"}, {name: "memory URI", file: "file::memory:?cache=shared"}, {name: "named memory URI", file: "file:assertoor-test?mode=memory&cache=shared"},