0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-27 05:26:33 +02:00
gitea/modules/setting/database.go
silverwind 3223d919b0
test: fix flaky TestResourceIndex and reduce its runtime (#37847)
The modernc SQLite driver (default since
https://github.com/go-gitea/gitea/pull/37562) returns `SQLITE_BUSY` once
the busy timeout is reached, unlike mattn which waited indefinitely.
`TestResourceIndex` fires many concurrent `NewIssue` writers, but SQLite
serializes all writers, so they queue on a single `BEGIN IMMEDIATE`
write lock. Under `-race` (modernc is much slower) the goroutines at the
back of the queue exceeded the hardcoded 5s test timeout, producing
`database is locked (5) (SQLITE_BUSY)`.

Changes:
- Reduce the concurrent inserts from 25 to 10. Since SQLite serializes
writers, the extra goroutines only deepen the busy-lock queue without
adding coverage. 10 still exercises concurrent index allocation while
cutting the test's `-race` runtime ~3x (2.76s to 0.86s locally).
- Share the busy-timeout constant: export `DefaultSQLiteBusyTimeout`
(20s, the production default) and reference it from the test engine
instead of the hardcoded `5000`.

Observed flake:
https://github.com/go-gitea/gitea/actions/runs/26394082930/job/77690496092

---
This PR was written with the help of Claude Opus 4.7

---------

Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-05-26 05:06:54 +00:00

113 lines
3.5 KiB
Go

// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package setting
import (
"path/filepath"
"time"
)
const DefaultSQLiteBusyTimeout = 20 * 1000
var (
// SupportedDatabaseTypes includes all XORM supported databases type, sqlite3 maybe added by the tag-controlled drivers
SupportedDatabaseTypes = []string{"mysql", "postgres", "mssql"}
// DatabaseTypeNames contains the friendly names for all database types
DatabaseTypeNames = map[string]string{"mysql": "MySQL", "postgres": "PostgreSQL", "mssql": "MSSQL", DatabaseTypeSQLite3: "SQLite3"}
// Database holds the database settings
Database = struct {
Type DatabaseType
Host string
Name string
User string
Passwd string
Schema string
SSLMode string
Path string
SQLiteBusyTimeout int
SQLiteJournalMode string
LogSQL bool
CharsetCollation string
DBConnectRetries int
DBConnectBackoff time.Duration
MaxIdleConns int
MaxOpenConns int
ConnMaxLifetime time.Duration
IterateBufferSize int
AutoMigration bool
SlowQueryThreshold time.Duration
}{
IterateBufferSize: 50,
SlowQueryThreshold: 5 * time.Second,
}
)
// LoadDBSetting loads the database settings
func LoadDBSetting() {
loadDBSetting(CfgProvider)
}
func loadDBSetting(rootCfg ConfigProvider) {
sec := rootCfg.Section("database")
Database.Type = DatabaseType(sec.Key("DB_TYPE").String())
Database.Host = sec.Key("HOST").String()
Database.Name = sec.Key("NAME").String()
Database.User = sec.Key("USER").String()
Database.Passwd = sec.Key("PASSWD").String()
Database.Schema = sec.Key("SCHEMA").String()
Database.SSLMode = sec.Key("SSL_MODE").MustString("disable")
Database.CharsetCollation = sec.Key("CHARSET_COLLATION").String()
Database.Path = sec.Key("PATH").MustString(filepath.Join(AppDataPath, "gitea.db"))
Database.SQLiteBusyTimeout = sec.Key("SQLITE_TIMEOUT").MustInt(DefaultSQLiteBusyTimeout)
// mattn driver isn't really affected by this timeout, but other drivers are affected
// the default value was 500 (0.5s), to avoid breaking existing users, make sure the timeout is long enough (at least, 5 seconds)
if Database.SQLiteBusyTimeout < 5000 {
Database.SQLiteBusyTimeout = DefaultSQLiteBusyTimeout
}
Database.SQLiteJournalMode = sec.Key("SQLITE_JOURNAL_MODE").MustString("")
Database.MaxIdleConns = sec.Key("MAX_IDLE_CONNS").MustInt(2)
if Database.Type.IsMySQL() {
Database.ConnMaxLifetime = sec.Key("CONN_MAX_LIFETIME").MustDuration(3 * time.Second)
} else {
Database.ConnMaxLifetime = sec.Key("CONN_MAX_LIFETIME").MustDuration(0)
}
Database.MaxOpenConns = sec.Key("MAX_OPEN_CONNS").MustInt(0)
Database.IterateBufferSize = sec.Key("ITERATE_BUFFER_SIZE").MustInt(50)
Database.LogSQL = sec.Key("LOG_SQL").MustBool(false)
Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10)
Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second)
Database.AutoMigration = sec.Key("AUTO_MIGRATION").MustBool(true)
Database.SlowQueryThreshold = sec.Key("SLOW_QUERY_THRESHOLD").MustDuration(Database.SlowQueryThreshold)
}
// DatabaseType FIXME: it is also used directly with "schemas.DBType", so the names must be consistent
type DatabaseType string
const DatabaseTypeSQLite3 = "sqlite3"
func (t DatabaseType) IsSQLite3() bool {
return t == DatabaseTypeSQLite3
}
func (t DatabaseType) IsMySQL() bool {
return t == "mysql"
}
func (t DatabaseType) IsMSSQL() bool {
return t == "mssql"
}
func (t DatabaseType) IsPostgreSQL() bool {
return t == "postgres"
}