feat(dolt): add server mode support for multi-client access

- Add dolt_mode, dolt_server_host, dolt_server_port fields to configfile.Config
- Add IsDoltServerMode(), GetDoltServerHost(), GetDoltServerPort() helpers
- Update factory to read server mode config and set Options accordingly
- Skip bootstrap in server mode (database lives on server)
- Pass Database name to dolt.Config for USE statement after connecting
- Disable dolt stats collection to avoid lock issues in embedded mode

This enables bd to connect to a running dolt sql-server (started via
'gt dolt start') instead of using embedded mode, allowing multi-client
access without file locking conflicts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
mayor
2026-01-23 22:33:55 -08:00
committed by gastown/crew/george
parent db0c6fbd3f
commit 13c362e67e
4 changed files with 23 additions and 6 deletions

View File

@@ -838,6 +838,18 @@ var rootCmd = &cobra.Command{
if backend == configfile.BackendDolt {
// For Dolt, use the dolt subdirectory
doltPath := filepath.Join(beadsDir, "dolt")
// Check if server mode is configured in metadata.json
cfg, cfgErr := configfile.Load(beadsDir)
if cfgErr == nil && cfg != nil && cfg.IsDoltServerMode() {
opts.ServerMode = true
opts.ServerHost = cfg.GetDoltServerHost()
opts.ServerPort = cfg.GetDoltServerPort()
if cfg.Database != "" {
opts.Database = cfg.Database
}
}
store, err = factory.NewWithOptions(rootCtx, backend, doltPath, opts)
} else {
// SQLite backend

View File

@@ -23,7 +23,7 @@ type Config struct {
// This enables multi-writer access for multi-agent environments.
DoltMode string `json:"dolt_mode,omitempty"` // "embedded" (default) or "server"
DoltServerHost string `json:"dolt_server_host,omitempty"` // Server host (default: 127.0.0.1)
DoltServerPort int `json:"dolt_server_port,omitempty"` // Server port (default: 3306)
DoltServerPort int `json:"dolt_server_port,omitempty"` // Server port (default: 3307)
DoltServerUser string `json:"dolt_server_user,omitempty"` // MySQL user (default: root)
// Note: Password should be set via BEADS_DOLT_PASSWORD env var for security
@@ -222,13 +222,13 @@ const (
// Default Dolt server settings
const (
DefaultDoltServerHost = "127.0.0.1"
DefaultDoltServerPort = 3306
DefaultDoltServerPort = 3307 // Use 3307 to avoid conflict with MySQL on 3306
DefaultDoltServerUser = "root"
)
// IsDoltServerMode returns true if Dolt is configured for server mode.
func (c *Config) IsDoltServerMode() bool {
return c.GetBackend() == BackendDolt && c.DoltMode == DoltModeServer
return c.GetBackend() == BackendDolt && strings.ToLower(c.DoltMode) == DoltModeServer
}
// GetDoltMode returns the Dolt connection mode, defaulting to embedded.
@@ -247,9 +247,9 @@ func (c *Config) GetDoltServerHost() string {
return c.DoltServerHost
}
// GetDoltServerPort returns the Dolt server port, defaulting to 3306.
// GetDoltServerPort returns the Dolt server port, defaulting to 3307.
func (c *Config) GetDoltServerPort() int {
if c.DoltServerPort == 0 {
if c.DoltServerPort <= 0 {
return DefaultDoltServerPort
}
return c.DoltServerPort

View File

@@ -262,6 +262,11 @@ func openEmbeddedConnection(ctx context.Context, cfg *Config) (*sql.DB, string,
return nil, "", fmt.Errorf("failed to connect to Dolt database after %d retries: %w", cfg.LockRetries, lastErr)
}
// Disable statistics collection to avoid stats subdatabase lock issues
// The stats database can cause "cannot update manifest: database is read only"
// errors when multiple processes access the embedded Dolt database
_, _ = db.ExecContext(ctx, "SET @@dolt_stats_enabled = 0")
return db, connStr, nil
}

View File

@@ -30,7 +30,7 @@ type Options struct {
// Dolt server mode options (federation)
ServerMode bool // Connect to dolt sql-server instead of embedded
ServerHost string // Server host (default: 127.0.0.1)
ServerPort int // Server port (default: 3306)
ServerPort int // Server port (default: 3307)
ServerUser string // MySQL user (default: root)
Database string // Database name for Dolt server mode (default: beads)
}