From 34d4962b7a4dbd51893a32898d5a2a74329cc207 Mon Sep 17 00:00:00 2001 From: sawka Date: Sun, 12 Mar 2023 14:42:18 -0700 Subject: [PATCH] more logging, backup db on migration, fix issue with dbmapper (writing byte arrays) --- cmd/main-server.go | 4 ++- pkg/sstore/map.go | 4 ++- pkg/sstore/migrate.go | 58 ++++++++++++++++++++++++++++++++++++++----- pkg/sstore/sstore.go | 10 ++++++-- 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/cmd/main-server.go b/cmd/main-server.go index b582908e..1d3a1caf 100644 --- a/cmd/main-server.go +++ b/cmd/main-server.go @@ -449,9 +449,10 @@ func stdinReadWatch() { for { _, err := os.Stdin.Read(buf) if err != nil { - log.Printf("stdin closed/error, shutting down: %v\n", err) + log.Printf("[prompt] stdin closed/error, shutting down: %v\n", err) sendTelemetryWrapper() time.Sleep(1 * time.Second) + log.Printf("[prompt] *** shutting down local server\n") syscall.Kill(syscall.Getpid(), syscall.SIGINT) break } @@ -473,6 +474,7 @@ func main() { } scHomeDir := scbase.GetPromptHomeDir() + log.Printf("[prompt] *** starting local server\n") log.Printf("[prompt] local server version %s+%s\n", scbase.PromptVersion, scbase.BuildTime) log.Printf("[prompt] homedir = %q\n", scHomeDir) diff --git a/pkg/sstore/map.go b/pkg/sstore/map.go index 136445dc..6f97600e 100644 --- a/pkg/sstore/map.go +++ b/pkg/sstore/map.go @@ -143,7 +143,9 @@ func ToDBMap(v DBMappable) map[string]interface{} { if dbName == "-" { continue } - if field.Type.Kind() == reflect.Slice { + if isByteArrayType(field.Type) { + m[dbName] = fieldVal.Interface() + } else if field.Type.Kind() == reflect.Slice { m[dbName] = quickJsonArr(fieldVal.Interface()) } else if isStructType(field.Type) { m[dbName] = quickJson(fieldVal.Interface()) diff --git a/pkg/sstore/migrate.go b/pkg/sstore/migrate.go index 5dcff1c1..1326b90f 100644 --- a/pkg/sstore/migrate.go +++ b/pkg/sstore/migrate.go @@ -2,7 +2,9 @@ package sstore import ( "fmt" + "io" "log" + "os" "strconv" "time" @@ -15,27 +17,71 @@ import ( "github.com/golang-migrate/migrate/v4" ) +const MaxMigration = 8 +const MigratePrimaryScreenVersion = 9 + func MakeMigrate() (*migrate.Migrate, error) { fsVar, err := iofs.New(sh2db.MigrationFS, "migrations") if err != nil { return nil, fmt.Errorf("opening iofs: %w", err) } // migrationPathUrl := fmt.Sprintf("file://%s", path.Join(wd, "db", "migrations")) - dbUrl := fmt.Sprintf("sqlite3://%s", GetSessionDBName()) + dbUrl := fmt.Sprintf("sqlite3://%s", GetDBName()) m, err := migrate.NewWithSourceInstance("iofs", fsVar, dbUrl) // m, err := migrate.New(migrationPathUrl, dbUrl) if err != nil { - return nil, fmt.Errorf("making migration db[%s]: %w", GetSessionDBName(), err) + return nil, fmt.Errorf("making migration db[%s]: %w", GetDBName(), err) } return m, nil } +func copyFile(srcFile string, dstFile string) error { + if srcFile == dstFile { + return fmt.Errorf("cannot copy %s to itself", srcFile) + } + srcFd, err := os.Open(srcFile) + if err != nil { + return fmt.Errorf("cannot open %s: %v", err) + } + defer srcFd.Close() + dstFd, err := os.OpenFile(dstFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return fmt.Errorf("cannot open destination file %s: %v", err) + } + _, err = io.Copy(dstFd, srcFd) + if err != nil { + dstFd.Close() + return fmt.Errorf("error copying file: %v", err) + } + return dstFd.Close() +} + func MigrateUp() error { m, err := MakeMigrate() if err != nil { return err } - err = m.Up() + curVersion, dirty, err := m.Version() + if err == migrate.ErrNilVersion { + curVersion = 0 + err = nil + } + if dirty { + return fmt.Errorf("cannot migrate up, database is dirty") + } + if err != nil { + return fmt.Errorf("cannot get current migration version: %v", err) + } + if curVersion >= MaxMigration { + return nil + } + log.Printf("[db] migrating from %d to %d\n", curVersion, MaxMigration) + log.Printf("[db] backing up database %s to %s\n", DBFileName, DBFileNameBackup) + err = copyFile(GetDBName(), GetDBBackupName()) + if err != nil { + return fmt.Errorf("error creating database backup: %v", err) + } + err = m.Migrate(MaxMigration) if err != nil { return err } @@ -100,17 +146,17 @@ func MigratePrintVersion() error { func MigrateCommandOpts(opts []string) error { var err error if opts[0] == "--migrate-up" { - fmt.Printf("migrate-up %v\n", GetSessionDBName()) + fmt.Printf("migrate-up %v\n", GetDBName()) time.Sleep(3 * time.Second) err = MigrateUp() } else if opts[0] == "--migrate-down" { - fmt.Printf("migrate-down %v\n", GetSessionDBName()) + fmt.Printf("migrate-down %v\n", GetDBName()) time.Sleep(3 * time.Second) err = MigrateDown() } else if opts[0] == "--migrate-goto" { n, err := strconv.Atoi(opts[1]) if err == nil { - fmt.Printf("migrate-goto %v => %d\n", GetSessionDBName(), n) + fmt.Printf("migrate-goto %v => %d\n", GetDBName(), n) time.Sleep(3 * time.Second) err = MigrateGoto(uint(n)) } diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index 76d05663..7fa6633f 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -31,6 +31,7 @@ const LineTypeCmd = "cmd" const LineTypeText = "text" const LineNoHeight = -1 const DBFileName = "prompt.db" +const DBFileNameBackup = "backup.prompt.db" const DefaultSessionName = "default" const DefaultWindowName = "default" @@ -83,11 +84,16 @@ var globalDBLock = &sync.Mutex{} var globalDB *sqlx.DB var globalDBErr error -func GetSessionDBName() string { +func GetDBName() string { scHome := scbase.GetPromptHomeDir() return path.Join(scHome, DBFileName) } +func GetDBBackupName() string { + scHome := scbase.GetPromptHomeDir() + return path.Join(scHome, DBFileNameBackup) +} + func IsValidConnectMode(mode string) bool { return mode == ConnectModeStartup || mode == ConnectModeAuto || mode == ConnectModeManual } @@ -99,7 +105,7 @@ func GetDB(ctx context.Context) (*sqlx.DB, error) { globalDBLock.Lock() defer globalDBLock.Unlock() if globalDB == nil && globalDBErr == nil { - dbName := GetSessionDBName() + dbName := GetDBName() globalDB, globalDBErr = sqlx.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&mode=rwc&_journal_mode=WAL&_busy_timeout=5000", dbName)) if globalDBErr != nil { globalDBErr = fmt.Errorf("opening db[%s]: %w", dbName, globalDBErr)