Files
Xayinn 1751f43ee0 fix(sqlite): enable WAL + working busy timeout + _txlock=immediate to stop concurrent write lockouts (#7030)
* fix(sqlite): enable WAL + working busy timeout + _txlock=immediate to stop concurrent write lockouts
2026-08-30 20:46:56 +08:00

65 lines
2.3 KiB
Go

package common
type DatabaseType string
const (
DatabaseTypeMySQL DatabaseType = "mysql"
DatabaseTypeSQLite DatabaseType = "sqlite"
DatabaseTypePostgreSQL DatabaseType = "postgres"
DatabaseTypeClickHouse DatabaseType = "clickhouse"
)
var mainDatabaseType = DatabaseTypeSQLite
var logDatabaseType = DatabaseTypeSQLite
func MainDatabaseType() DatabaseType {
return mainDatabaseType
}
func LogDatabaseType() DatabaseType {
return logDatabaseType
}
func SetMainDatabaseType(databaseType DatabaseType) {
mainDatabaseType = databaseType
}
func SetLogDatabaseType(databaseType DatabaseType) {
logDatabaseType = databaseType
}
func SetDatabaseTypes(mainType DatabaseType, logType DatabaseType) {
mainDatabaseType = mainType
logDatabaseType = logType
}
func UsingMainDatabase(databaseType DatabaseType) bool {
return mainDatabaseType == databaseType
}
func UsingLogDatabase(databaseType DatabaseType) bool {
return logDatabaseType == databaseType
}
// SQLitePath is the DSN for the default SQLite database. It uses WAL journal
// mode so readers are never blocked by the single writer, plus a 30s busy
// timeout for writers to queue.
//
// Two details are non-obvious and both are required for concurrent correctness:
//
// 1. The busy timeout must be passed as a `_pragma=busy_timeout(30000)` DSN
// parameter. The pure-Go driver (modernc.org/sqlite, used through
// github.com/glebarez/sqlite) silently ignores the plain `_busy_timeout=`
// form, so without this the effective timeout stays at SQLite's 5s default
// and concurrent writes surface as "database is locked" (see #6805).
//
// 2. `_txlock=immediate` (BEGIN IMMEDIATE) must be enabled. Without it, a
// transaction that first SELECTs (establishing a read snapshot) and then
// writes can hit SQLITE_BUSY_SNAPSHOT when another connection commits in
// between; the busy handler does not cover that case, so the write fails
// instantly no matter the timeout. BEGIN IMMEDIATE takes the write lock up
// front, so writers serialize through the busy timeout instead of dying on
// a stale snapshot. Autocommit SELECTs stay concurrent because WAL keeps
// readers unlocked.
var SQLitePath = "one-api.db?_pragma=busy_timeout(30000)&_pragma=journal_mode(WAL)&_txlock=immediate"