diff --git a/internal/database/database.go b/internal/database/database.go index c820da6..b8d8040 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -30,11 +30,6 @@ const ( ipv4Offset = 12 ipv4Bits = 32 maxIPv4 = 0xFFFFFFFF - - // Database connection pool settings - maxOpenConns = 10 - maxIdleConns = 5 - connMaxLifetime = 5 * time.Minute ) // Common errors @@ -78,10 +73,10 @@ func New(cfg *config.Config, logger *logger.Logger) (*Database, error) { } // Set connection pool parameters - // Allow multiple readers but single writer for SQLite WAL mode - db.SetMaxOpenConns(maxOpenConns) - db.SetMaxIdleConns(maxIdleConns) - db.SetConnMaxLifetime(connMaxLifetime) + // Single connection to avoid locking issues with SQLite + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) + db.SetConnMaxLifetime(0) database := &Database{db: db, logger: logger, path: dbPath} @@ -94,20 +89,21 @@ func New(cfg *config.Config, logger *logger.Logger) (*Database, error) { // Initialize creates the database schema if it doesn't exist. func (d *Database) Initialize() error { - // Set SQLite pragmas for better performance with safety + // Set SQLite pragmas for better performance pragmas := []string{ - "PRAGMA journal_mode=WAL", // Write-Ahead Logging - "PRAGMA synchronous=NORMAL", // Balance between safety and speed - "PRAGMA cache_size=-262144", // 256MB cache (negative = KB) - "PRAGMA temp_store=MEMORY", // Use memory for temp tables - "PRAGMA mmap_size=268435456", // 256MB memory-mapped I/O - "PRAGMA wal_autocheckpoint=1000", // Checkpoint every 1000 pages - "PRAGMA wal_checkpoint(PASSIVE)", // Checkpoint now - "PRAGMA page_size=4096", // Standard page size - "PRAGMA busy_timeout=30000", // 30 second busy timeout - "PRAGMA optimize", // Run optimizer - "PRAGMA locking_mode=NORMAL", // Allow multiple connections - "PRAGMA read_uncommitted=true", // Allow dirty reads for better concurrency + "PRAGMA journal_mode=WAL", // Write-Ahead Logging + "PRAGMA synchronous=OFF", // Don't wait for disk writes + "PRAGMA cache_size=-2097152", // 2GB cache (negative = KB) + "PRAGMA temp_store=MEMORY", // Use memory for temp tables + "PRAGMA mmap_size=536870912", // 512MB memory-mapped I/O + "PRAGMA wal_autocheckpoint=1000", // Checkpoint every 1000 pages (4MB with 4KB pages) + "PRAGMA wal_checkpoint(PASSIVE)", // Checkpoint now + "PRAGMA page_size=4096", // Standard page size + "PRAGMA busy_timeout=30000", // 30 second busy timeout + "PRAGMA locking_mode=NORMAL", // Allow multiple connections + "PRAGMA read_uncommitted=true", // Allow dirty reads for better concurrency + "PRAGMA journal_size_limit=67108864", // Limit WAL to 64MB + "PRAGMA analysis_limit=0", // Disable automatic ANALYZE } for _, pragma := range pragmas { @@ -117,8 +113,17 @@ func (d *Database) Initialize() error { } err := d.exec(dbSchema) + if err != nil { + return err + } - return err + // Run VACUUM on startup to optimize database + d.logger.Info("Running VACUUM to optimize database (this may take a moment)") + if err := d.exec("VACUUM"); err != nil { + d.logger.Warn("Failed to VACUUM database", "error", err) + } + + return nil } // Close closes the database connection.