mirror of
https://github.com/containers/podman.git
synced 2025-06-20 00:51:16 +08:00
@ -29,6 +29,30 @@ type SQLiteState struct {
|
|||||||
runtime *Runtime
|
runtime *Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Deal with timezone automatically.
|
||||||
|
sqliteOptionLocation = "_loc=auto"
|
||||||
|
// Set the journal mode (https://www.sqlite.org/pragma.html#pragma_journal_mode).
|
||||||
|
sqliteOptionJournal = "&_journal=WAL"
|
||||||
|
// Force WAL mode to fsync after each transaction (https://www.sqlite.org/pragma.html#pragma_synchronous).
|
||||||
|
sqliteOptionSynchronous = "&_sync=FULL"
|
||||||
|
// Allow foreign keys (https://www.sqlite.org/pragma.html#pragma_foreign_keys).
|
||||||
|
sqliteOptionForeignKeys = "&_foreign_keys=1"
|
||||||
|
// Enable cache sharing for threads within a process
|
||||||
|
sqliteOptionSharedCache = "&cache=shared"
|
||||||
|
// Make sure that transactions happen exclusively.
|
||||||
|
sqliteOptionTXLock = "&_txlock=exclusive"
|
||||||
|
|
||||||
|
// Assembled sqlite options used when opening the database.
|
||||||
|
sqliteOptions = "db.sql?" +
|
||||||
|
sqliteOptionLocation +
|
||||||
|
sqliteOptionJournal +
|
||||||
|
sqliteOptionSynchronous +
|
||||||
|
sqliteOptionForeignKeys +
|
||||||
|
sqliteOptionSharedCache +
|
||||||
|
sqliteOptionTXLock
|
||||||
|
)
|
||||||
|
|
||||||
// NewSqliteState creates a new SQLite-backed state database.
|
// NewSqliteState creates a new SQLite-backed state database.
|
||||||
func NewSqliteState(runtime *Runtime) (_ State, defErr error) {
|
func NewSqliteState(runtime *Runtime) (_ State, defErr error) {
|
||||||
state := new(SQLiteState)
|
state := new(SQLiteState)
|
||||||
@ -45,7 +69,7 @@ func NewSqliteState(runtime *Runtime) (_ State, defErr error) {
|
|||||||
return nil, fmt.Errorf("creating root directory: %w", err)
|
return nil, fmt.Errorf("creating root directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := sql.Open("sqlite3", filepath.Join(basePath, "db.sql?_loc=auto"))
|
conn, err := sql.Open("sqlite3", filepath.Join(basePath, sqliteOptions))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("initializing sqlite database: %w", err)
|
return nil, fmt.Errorf("initializing sqlite database: %w", err)
|
||||||
}
|
}
|
||||||
@ -63,18 +87,9 @@ func NewSqliteState(runtime *Runtime) (_ State, defErr error) {
|
|||||||
return nil, fmt.Errorf("cannot connect to database: %w", err)
|
return nil, fmt.Errorf("cannot connect to database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable foreign keys constraints, which we use extensively in our
|
// Migrate schema (if necessary)
|
||||||
// tables.
|
if err := state.migrateSchemaIfNecessary(); err != nil {
|
||||||
if _, err := state.conn.Exec("PRAGMA foreign_keys = ON;"); err != nil {
|
return nil, err
|
||||||
return nil, fmt.Errorf("enabling foreign key support in database: %w", err)
|
|
||||||
}
|
|
||||||
// Enable WAL mode for performance - https://www.sqlite.org/wal.html
|
|
||||||
if _, err := state.conn.Exec("PRAGMA journal_mode = WAL;"); err != nil {
|
|
||||||
return nil, fmt.Errorf("switching journal to WAL mode: %w", err)
|
|
||||||
}
|
|
||||||
// Force WAL mode to fsync after every transaction, for reboot safety.
|
|
||||||
if _, err := state.conn.Exec("PRAGMA synchronous = FULL;"); err != nil {
|
|
||||||
return nil, fmt.Errorf("setting full fsync mode in db: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up tables
|
// Set up tables
|
||||||
@ -82,10 +97,6 @@ func NewSqliteState(runtime *Runtime) (_ State, defErr error) {
|
|||||||
return nil, fmt.Errorf("creating tables: %w", err)
|
return nil, fmt.Errorf("creating tables: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := state.migrateSchemaIfNecessary(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
state.valid = true
|
state.valid = true
|
||||||
state.runtime = runtime
|
state.runtime = runtime
|
||||||
|
|
||||||
|
@ -16,6 +16,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *SQLiteState) migrateSchemaIfNecessary() (defErr error) {
|
func (s *SQLiteState) migrateSchemaIfNecessary() (defErr error) {
|
||||||
|
// First, check if the DBConfig table exists
|
||||||
|
checkRow := s.conn.QueryRow("SELECT 1 FROM sqlite_master WHERE type='table' AND name='DBConfig';")
|
||||||
|
var check int
|
||||||
|
if err := checkRow.Scan(&check); err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("checking if DB config table exists: %w", err)
|
||||||
|
}
|
||||||
|
if check != 1 {
|
||||||
|
// Table does not exist, fresh database, no need to migrate.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
row := s.conn.QueryRow("SELECT SchemaVersion FROM DBConfig;")
|
row := s.conn.QueryRow("SELECT SchemaVersion FROM DBConfig;")
|
||||||
var schemaVer int
|
var schemaVer int
|
||||||
if err := row.Scan(&schemaVer); err != nil {
|
if err := row.Scan(&schemaVer); err != nil {
|
||||||
@ -24,6 +38,7 @@ func (s *SQLiteState) migrateSchemaIfNecessary() (defErr error) {
|
|||||||
// Schema was just created, so it has to be the latest.
|
// Schema was just created, so it has to be the latest.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return fmt.Errorf("scanning schema version from DB config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the schema version 0 or less, it's invalid
|
// If the schema version 0 or less, it's invalid
|
||||||
|
Reference in New Issue
Block a user