refactor(store): use crawlkit sqlite opener

This commit is contained in:
Vincent Koc 2026-05-01 08:55:59 -07:00
parent 4e9b9bee86
commit 6202e6bf55
No known key found for this signature in database
2 changed files with 7 additions and 58 deletions

View File

@ -5,13 +5,10 @@ import (
"database/sql"
"fmt"
"hash/fnv"
"os"
"path/filepath"
"runtime"
"strconv"
"time"
_ "modernc.org/sqlite"
"github.com/vincentkoc/crawlkit/sqlitekit"
)
const (
@ -114,68 +111,19 @@ type ChannelRow struct {
}
func Open(ctx context.Context, path string) (*Store, error) {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return nil, fmt.Errorf("mkdir db dir: %w", err)
}
if err := ensureDBFile(path); err != nil {
return nil, err
}
dsn := fmt.Sprintf(
"file:%s?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=temp_store(MEMORY)&_pragma=mmap_size(268435456)&_pragma=busy_timeout(5000)",
path,
)
db, err := sql.Open("sqlite", dsn)
base, err := sqlitekit.Open(ctx, sqlitekit.Options{Path: path})
if err != nil {
return nil, fmt.Errorf("open sqlite: %w", err)
}
// SQLite is single-writer; keep one shared connection so concurrent callers queue
// instead of contending on separate writer connections.
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
if err := db.PingContext(ctx); err != nil {
_ = db.Close()
return nil, fmt.Errorf("ping sqlite: %w", err)
}
if err := tightenDBFilePerms(path); err != nil {
_ = db.Close()
return nil, err
}
db := base.DB()
store := &Store{db: db, path: path}
if err := store.migrate(ctx); err != nil {
_ = db.Close()
_ = base.Close()
return nil, err
}
return store, nil
}
func ensureDBFile(path string) error {
if _, err := os.Stat(path); err == nil {
return nil
} else if !os.IsNotExist(err) {
return fmt.Errorf("stat db file: %w", err)
}
file, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o600)
if err != nil && !os.IsExist(err) {
return fmt.Errorf("create db file: %w", err)
}
if file != nil {
if closeErr := file.Close(); closeErr != nil {
return fmt.Errorf("close db file: %w", closeErr)
}
}
return nil
}
func tightenDBFilePerms(path string) error {
if runtime.GOOS == "windows" {
return nil
}
if err := os.Chmod(path, 0o600); err != nil {
return fmt.Errorf("chmod db file: %w", err)
}
return nil
}
func (s *Store) Close() error {
if s == nil || s.db == nil {
return nil

View File

@ -149,8 +149,9 @@ func TestStoreMaintenanceHelpers(t *testing.T) {
require.NoError(t, err)
defer func() { _ = s.Close() }()
require.NoError(t, ensureDBFile(dbPath))
require.NoError(t, tightenDBFilePerms(dbPath))
info, err := os.Stat(dbPath)
require.NoError(t, err)
require.Equal(t, os.FileMode(0o600), info.Mode().Perm())
require.NoError(t, s.RebuildSearchIndexes(ctx))
version, err := s.schemaVersion(ctx)
require.NoError(t, err)