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"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -136,7 +135,7 @@ func (d *Daemon) runGlobalDaemon() error {
|
|||||||
d.log.log("Error: cannot get global beads directory: %v", err)
|
d.log.log("Error: cannot get global beads directory: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.cfg.SocketPath = filepath.Join(globalDir, "bd.sock")
|
d.cfg.SocketPath = getSocketPath(globalDir)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
d.cancel = cancel
|
d.cancel = cancel
|
||||||
@@ -193,18 +192,8 @@ func (d *Daemon) setupLock() (io.Closer, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
myPID := os.Getpid()
|
if err := ensurePIDFileCorrect(d.cfg.PIDFile); err != nil {
|
||||||
// #nosec G304 - controlled path from config
|
d.log.log("Warning: failed to verify PID file: %v", err)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lock, nil
|
return lock, nil
|
||||||
@@ -237,7 +226,7 @@ func (d *Daemon) determineDatabasePath() error {
|
|||||||
d.cfg.DBPath = foundDB
|
d.cfg.DBPath = foundDB
|
||||||
d.cfg.BeadsDir = filepath.Dir(foundDB)
|
d.cfg.BeadsDir = filepath.Dir(foundDB)
|
||||||
d.cfg.WorkspacePath = filepath.Dir(d.cfg.BeadsDir)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +282,9 @@ func (d *Daemon) validateSchemaVersion() error {
|
|||||||
return fmt.Errorf("failed to read database version: %w", err)
|
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("Error: Database schema version mismatch")
|
||||||
d.log.log(" Database version: %s", dbVersion)
|
d.log.log(" Database version: %s", dbVersion)
|
||||||
d.log.log(" Daemon version: %s", d.Version)
|
d.log.log(" Daemon version: %s", d.Version)
|
||||||
@@ -311,8 +302,7 @@ func (d *Daemon) validateSchemaVersion() error {
|
|||||||
return fmt.Errorf("database version mismatch")
|
return fmt.Errorf("database version mismatch")
|
||||||
}
|
}
|
||||||
d.log.log("Warning: Proceeding despite version mismatch (BEADS_IGNORE_VERSION_MISMATCH=1)")
|
d.log.log("Warning: Proceeding despite version mismatch (BEADS_IGNORE_VERSION_MISMATCH=1)")
|
||||||
} else if dbVersion == "" {
|
} else if missing {
|
||||||
// Old database without version metadata - set it now
|
|
||||||
d.log.log("Warning: Database missing version metadata, setting to %s", d.Version)
|
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 {
|
if err := d.store.SetMetadata(ctx, "bd_version", d.Version); err != nil {
|
||||||
d.log.log("Error: failed to set database version: %v", err)
|
d.log.log("Error: failed to set database version: %v", err)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,6 +37,55 @@ func (l *DaemonLock) Close() error {
|
|||||||
return err
|
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
|
// acquireDaemonLock attempts to acquire an exclusive lock on daemon.lock
|
||||||
func acquireDaemonLock(beadsDir string, dbPath string, version string) (*DaemonLock, error) {
|
func acquireDaemonLock(beadsDir string, dbPath string, version string) (*DaemonLock, error) {
|
||||||
lockPath := filepath.Join(beadsDir, "daemon.lock")
|
lockPath := filepath.Join(beadsDir, "daemon.lock")
|
||||||
@@ -71,8 +122,8 @@ func acquireDaemonLock(beadsDir string, dbPath string, version string) (*DaemonL
|
|||||||
_ = f.Sync()
|
_ = f.Sync()
|
||||||
|
|
||||||
// Also write PID file for Windows compatibility
|
// Also write PID file for Windows compatibility
|
||||||
pidFile := filepath.Join(beadsDir, "daemon.pid")
|
pidFile := getPIDFilePath(beadsDir)
|
||||||
_ = os.WriteFile(pidFile, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0600)
|
_ = writePIDFile(pidFile)
|
||||||
|
|
||||||
return &DaemonLock{file: f, path: lockPath}, nil
|
return &DaemonLock{file: f, path: lockPath}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user