mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-01 19:41:57 +00:00
* fix(sqlite): enable WAL + working busy timeout + _txlock=immediate to stop concurrent write lockouts
65 lines
2.3 KiB
Go
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"
|