Refactor: separate process/lock/PID concerns into process.go (bd-d33c)
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -7,7 +7,6 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -136,7 +135,7 @@ func (d *Daemon) runGlobalDaemon() error {
|
||||
d.log.log("Error: cannot get global beads directory: %v", err)
|
||||
return err
|
||||
}
|
||||
d.cfg.SocketPath = filepath.Join(globalDir, "bd.sock")
|
||||
d.cfg.SocketPath = getSocketPath(globalDir)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
d.cancel = cancel
|
||||
@@ -193,18 +192,8 @@ func (d *Daemon) setupLock() (io.Closer, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
myPID := os.Getpid()
|
||||
// #nosec G304 - controlled path from config
|
||||
if data, err := os.ReadFile(d.cfg.PIDFile); err == nil {
|
||||
if pid, err := strconv.Atoi(strings.TrimSpace(string(data))); err == nil && pid == myPID {
|
||||
// PID file is correct, continue
|
||||
} else {
|
||||
d.log.log("PID file has wrong PID (expected %d, got %d), overwriting", myPID, pid)
|
||||
_ = os.WriteFile(d.cfg.PIDFile, []byte(fmt.Sprintf("%d\n", myPID)), 0600)
|
||||
}
|
||||
} else {
|
||||
d.log.log("PID file missing after lock acquisition, creating")
|
||||
_ = os.WriteFile(d.cfg.PIDFile, []byte(fmt.Sprintf("%d\n", myPID)), 0600)
|
||||
if err := ensurePIDFileCorrect(d.cfg.PIDFile); err != nil {
|
||||
d.log.log("Warning: failed to verify PID file: %v", err)
|
||||
}
|
||||
|
||||
return lock, nil
|
||||
@@ -237,7 +226,7 @@ func (d *Daemon) determineDatabasePath() error {
|
||||
d.cfg.DBPath = foundDB
|
||||
d.cfg.BeadsDir = filepath.Dir(foundDB)
|
||||
d.cfg.WorkspacePath = filepath.Dir(d.cfg.BeadsDir)
|
||||
d.cfg.SocketPath = filepath.Join(d.cfg.BeadsDir, "bd.sock")
|
||||
d.cfg.SocketPath = getSocketPath(d.cfg.BeadsDir)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -293,7 +282,9 @@ func (d *Daemon) validateSchemaVersion() error {
|
||||
return fmt.Errorf("failed to read database version: %w", err)
|
||||
}
|
||||
|
||||
if dbVersion != "" && dbVersion != d.Version {
|
||||
mismatch, missing := checkVersionMismatch(dbVersion, d.Version)
|
||||
|
||||
if mismatch {
|
||||
d.log.log("Error: Database schema version mismatch")
|
||||
d.log.log(" Database version: %s", dbVersion)
|
||||
d.log.log(" Daemon version: %s", d.Version)
|
||||
@@ -311,8 +302,7 @@ func (d *Daemon) validateSchemaVersion() error {
|
||||
return fmt.Errorf("database version mismatch")
|
||||
}
|
||||
d.log.log("Warning: Proceeding despite version mismatch (BEADS_IGNORE_VERSION_MISMATCH=1)")
|
||||
} else if dbVersion == "" {
|
||||
// Old database without version metadata - set it now
|
||||
} else if missing {
|
||||
d.log.log("Warning: Database missing version metadata, setting to %s", d.Version)
|
||||
if err := d.store.SetMetadata(ctx, "bd_version", d.Version); err != nil {
|
||||
d.log.log("Error: failed to set database version: %v", err)
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -35,6 +37,55 @@ func (l *DaemonLock) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// getPIDFilePath returns the path to daemon.pid in the given beads directory
|
||||
func getPIDFilePath(beadsDir string) string {
|
||||
return filepath.Join(beadsDir, "daemon.pid")
|
||||
}
|
||||
|
||||
// getSocketPath returns the path to bd.sock in the given beads directory
|
||||
func getSocketPath(beadsDir string) string {
|
||||
return filepath.Join(beadsDir, "bd.sock")
|
||||
}
|
||||
|
||||
// readPIDFile reads the PID from daemon.pid
|
||||
func readPIDFile(pidFile string) (int, error) {
|
||||
// #nosec G304 - controlled path from config
|
||||
data, err := os.ReadFile(pidFile)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid PID in file: %w", err)
|
||||
}
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
// writePIDFile writes the current process PID to daemon.pid
|
||||
func writePIDFile(pidFile string) error {
|
||||
return os.WriteFile(pidFile, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0600)
|
||||
}
|
||||
|
||||
// ensurePIDFileCorrect verifies PID file has correct PID, fixes if wrong
|
||||
func ensurePIDFileCorrect(pidFile string) error {
|
||||
myPID := os.Getpid()
|
||||
if pid, err := readPIDFile(pidFile); err == nil && pid == myPID {
|
||||
return nil
|
||||
}
|
||||
return writePIDFile(pidFile)
|
||||
}
|
||||
|
||||
// checkVersionMismatch checks if database version matches daemon version
|
||||
func checkVersionMismatch(dbVersion, daemonVersion string) (mismatch bool, missing bool) {
|
||||
if dbVersion == "" {
|
||||
return false, true
|
||||
}
|
||||
if dbVersion != daemonVersion {
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
// acquireDaemonLock attempts to acquire an exclusive lock on daemon.lock
|
||||
func acquireDaemonLock(beadsDir string, dbPath string, version string) (*DaemonLock, error) {
|
||||
lockPath := filepath.Join(beadsDir, "daemon.lock")
|
||||
@@ -71,8 +122,8 @@ func acquireDaemonLock(beadsDir string, dbPath string, version string) (*DaemonL
|
||||
_ = f.Sync()
|
||||
|
||||
// Also write PID file for Windows compatibility
|
||||
pidFile := filepath.Join(beadsDir, "daemon.pid")
|
||||
_ = os.WriteFile(pidFile, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0600)
|
||||
pidFile := getPIDFilePath(beadsDir)
|
||||
_ = writePIDFile(pidFile)
|
||||
|
||||
return &DaemonLock{file: f, path: lockPath}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user