diff --git a/go/cmd/dolt/commands/dump.go b/go/cmd/dolt/commands/dump.go index b7b1b6e5ba..cb1b27d13f 100644 --- a/go/cmd/dolt/commands/dump.go +++ b/go/cmd/dolt/commands/dump.go @@ -812,7 +812,7 @@ func addCreateDatabaseHeader(dEnv *env.DoltEnv, fPath, dbName string) errhand.Ve // TODO: find a more elegant way to get database name, possibly implement a method in DoltEnv // getActiveDatabaseName returns the name of the current active database func getActiveDatabaseName(ctx context.Context, dEnv *env.DoltEnv) (string, errhand.VerboseError) { - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { return "", errhand.VerboseErrorFromError(err) } diff --git a/go/cmd/dolt/commands/engine/sqlengine.go b/go/cmd/dolt/commands/engine/sqlengine.go index b6983f84fe..138b19ae07 100644 --- a/go/cmd/dolt/commands/engine/sqlengine.go +++ b/go/cmd/dolt/commands/engine/sqlengine.go @@ -407,7 +407,7 @@ func doltSessionFactory(pro *dsqle.DoltDatabaseProvider, config config.ReadWrite // NewSqlEngineForEnv returns a SqlEngine configured for the environment provided, with a single root user. // Returns the new engine, the first database name, and any error that occurred. func NewSqlEngineForEnv(ctx context.Context, dEnv *env.DoltEnv) (*SqlEngine, string, error) { - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { return nil, "", err } diff --git a/go/cmd/dolt/commands/filter-branch.go b/go/cmd/dolt/commands/filter-branch.go index c8f3986e8b..6b722ebc46 100644 --- a/go/cmd/dolt/commands/filter-branch.go +++ b/go/cmd/dolt/commands/filter-branch.go @@ -104,9 +104,7 @@ func (cmd FilterBranchCmd) Exec(ctx context.Context, commandStr string, args []s return HandleVErrAndExitCode(verr, usage) } - if dEnv.IsLocked() { - return HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), help) - } + // TODO: Assert that dEnv.DoltDB.AccessMode() != ReadOnly queryString := apr.GetValueOrDefault(QueryFlag, "") verbose := apr.Contains(cli.VerboseFlag) @@ -281,7 +279,7 @@ func rebaseSqlEngine(ctx context.Context, dEnv *env.DoltEnv, cm *doltdb.Commit) return nil, nil, err } - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { return nil, nil, err } diff --git a/go/cmd/dolt/commands/gc.go b/go/cmd/dolt/commands/gc.go index 78e4a6b1c7..980e5be4de 100644 --- a/go/cmd/dolt/commands/gc.go +++ b/go/cmd/dolt/commands/gc.go @@ -88,9 +88,7 @@ func (cmd GarbageCollectionCmd) Exec(ctx context.Context, commandStr string, arg help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, gcDocs, ap)) apr := cli.ParseArgsOrDie(ap, args, help) - if dEnv.IsLocked() { - return HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), help) - } + // TODO: Assert that dEnv.DoltDB.AccessMode() != ReadOnly? var err error if apr.Contains(cli.ShallowFlag) { diff --git a/go/cmd/dolt/commands/indexcmds/rebuild.go b/go/cmd/dolt/commands/indexcmds/rebuild.go index 24df5505f0..6ff73b63c9 100644 --- a/go/cmd/dolt/commands/indexcmds/rebuild.go +++ b/go/cmd/dolt/commands/indexcmds/rebuild.go @@ -20,7 +20,6 @@ import ( "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/dolt/go/cmd/dolt/cli" - "github.com/dolthub/dolt/go/cmd/dolt/commands" "github.com/dolthub/dolt/go/cmd/dolt/errhand" "github.com/dolthub/dolt/go/libraries/doltcore/env" "github.com/dolthub/dolt/go/libraries/doltcore/table/editor" @@ -72,9 +71,7 @@ func (cmd RebuildCmd) Exec(ctx context.Context, commandStr string, args []string return HandleErr(errhand.BuildDError("Both the table and index names must be provided.").Build(), usage) } - if dEnv.IsLocked() { - return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), usage) - } + // TODO: Error if dEnv.DoltDB.AccessMode() == ReadOnly? working, err := dEnv.WorkingRoot(context.Background()) if err != nil { diff --git a/go/cmd/dolt/commands/schcmds/import.go b/go/cmd/dolt/commands/schcmds/import.go index e08ef2483c..a39f49deec 100644 --- a/go/cmd/dolt/commands/schcmds/import.go +++ b/go/cmd/dolt/commands/schcmds/import.go @@ -170,9 +170,7 @@ func (cmd ImportCmd) Exec(ctx context.Context, commandStr string, args []string, return 1 } - if dEnv.IsLocked() { - return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), usage) - } + // TODO: Error if dEnv.DoltDB.AccessMode() == ReadOnly? return commands.HandleVErrAndExitCode(importSchema(ctx, dEnv, apr), usage) } diff --git a/go/cmd/dolt/commands/sqlserver/creds.go b/go/cmd/dolt/commands/sqlserver/creds.go new file mode 100644 index 0000000000..7e419e1dc3 --- /dev/null +++ b/go/cmd/dolt/commands/sqlserver/creds.go @@ -0,0 +1,127 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sqlserver + +import ( + "os" + "fmt" + "path/filepath" + "strconv" + "strings" + + "github.com/google/uuid" + + "github.com/dolthub/dolt/go/libraries/doltcore/dbfactory" + "github.com/dolthub/dolt/go/libraries/utils/filesys" +) + +const ServerLocalCredsFile = "sql-server.lock" + +// LocalCreds is a struct that contains information about how to access the +// locally running server for a CLI process which wants to operate against a +// database while a sql-server process is running. It contains the pid of the +// process that created the lockfile, the port that the server is running on +// and the password to be used connecting to the server. +// +// Pid is a legacy field which is retained for compatibility but no longer +// influences the behavior of the running program(s). +type LocalCreds struct { + Pid int + Port int + Secret string +} + +func NewLocalCreds(port int) *LocalCreds { + return &LocalCreds{os.Getpid(), port, uuid.New().String()} +} + +// Best effort attempt to remove local creds file persisted as the Filesys +// rooted there. +func RemoveLocalCreds(fs filesys.Filesys) { + credsFilePath, err := fs.Abs(filepath.Join(dbfactory.DoltDir, ServerLocalCredsFile)) + if err != nil { + return + } + _ = fs.Delete(credsFilePath, false) +} + +// WriteLocalCreds writes a file containing the contents of LocalCreds to the +// DoltDir rooted at the provided Filesys. +func WriteLocalCreds(fs filesys.Filesys, creds *LocalCreds) error { + // if the DoltDir doesn't exist, create it. + doltDir, err := fs.Abs(dbfactory.DoltDir) + if err != nil { + return err + } + err = fs.MkDirs(doltDir) + if err != nil { + return err + } + + credsFile, err := fs.Abs(filepath.Join(dbfactory.DoltDir, ServerLocalCredsFile)) + if err != nil { + return err + } + + portStr := strconv.Itoa(creds.Port) + if creds.Port < 0 { + portStr = "-" + } + + return fs.WriteFile(credsFile, []byte(fmt.Sprintf("%d:%s:%s", creds.Pid, portStr, creds.Secret)), 0600) +} + +func LoadLocalCreds(fs filesys.Filesys, credsFilePath string) (creds *LocalCreds, err error) { + rd, err := fs.OpenForRead(credsFilePath) + if err != nil { + return nil, err + } + defer rd.Close() + + b := make([]byte, 256) + n, err := rd.Read(b) + if err != nil { + return nil, err + } + + data := strings.TrimSpace(string(b[:n])) + + parts := strings.Split(data, ":") + if len(parts) == 1 { + // Legacy Lock file. We can remove this code path in a couple of months (6/2023) + pid, err := strconv.Atoi(parts[0]) + if err != nil { + return nil, err + } + return &LocalCreds{Pid: pid, Port: -1, Secret: ""}, nil + } + if len(parts) != 3 { + return nil, fmt.Errorf("invalid lock file format") + } + + pid, err := strconv.Atoi(parts[0]) + if err != nil { + return nil, err + } + port := -1 + if parts[1] != "-" { + port, err = strconv.Atoi(parts[1]) + if err != nil { + return nil, err + } + } + secret := parts[2] + return &LocalCreds{Pid: pid, Port: port, Secret: secret}, nil +} diff --git a/go/cmd/dolt/commands/sqlserver/server.go b/go/cmd/dolt/commands/sqlserver/server.go index a505a058f4..0ce348acb0 100644 --- a/go/cmd/dolt/commands/sqlserver/server.go +++ b/go/cmd/dolt/commands/sqlserver/server.go @@ -140,7 +140,7 @@ func Serve( var mrEnv *env.MultiRepoEnv InitMultiEnv := &svcs.AnonService{ InitF: func(ctx context.Context) (err error) { - mrEnv, err = env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), fs, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err = env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), fs, dEnv.Version, dEnv) return err }, } @@ -154,18 +154,18 @@ func Serve( } controller.Register(AssertNoDatabasesInAccessModeReadOnly) - var serverLock *env.DBLock - InitGlobalServerLock := &svcs.AnonService{ + var localCreds *LocalCreds + InitServerLocalCreds := &svcs.AnonService{ InitF: func(context.Context) (err error) { - serverLock, err = acquireGlobalSqlServerLock(serverConfig.Port(), dEnv) + localCreds, err = persistServerLocalCreds(serverConfig.Port(), dEnv) return err }, StopF: func() error { - dEnv.FS.Delete(dEnv.LockFile(), false) + RemoveLocalCreds(dEnv.FS) return nil }, } - controller.Register(InitGlobalServerLock) + controller.Register(InitServerLocalCreds) var clusterController *cluster.Controller InitClusterController := &svcs.AnonService{ @@ -283,7 +283,7 @@ func Serve( InitF: func(context.Context) error { mysqlDb := sqlEngine.GetUnderlyingEngine().Analyzer.Catalog.MySQLDb ed := mysqlDb.Editor() - mysqlDb.AddSuperUser(ed, LocalConnectionUser, "localhost", serverLock.Secret) + mysqlDb.AddSuperUser(ed, LocalConnectionUser, "localhost", localCreds.Secret) ed.Close() return nil }, @@ -555,26 +555,13 @@ func Serve( return nil, controller.WaitForStop() } -// acquireGlobalSqlServerLock attempts to acquire a global lock on the SQL server. If no error is returned, then the lock was acquired. -func acquireGlobalSqlServerLock(port int, dEnv *env.DoltEnv) (*env.DBLock, error) { - locked, _, err := dEnv.GetLock() +func persistServerLocalCreds(port int, dEnv *env.DoltEnv) (*LocalCreds, error) { + creds := NewLocalCreds(port) + err := WriteLocalCreds(dEnv.FS, creds) if err != nil { return nil, err } - if locked { - lockPath := dEnv.LockFile() - err = fmt.Errorf("Database locked by another sql-server; Lock file: %s", lockPath) - return nil, err - } - - lck := env.NewDBLock(port) - err = dEnv.Lock(&lck) - if err != nil { - err = fmt.Errorf("Server can not start. Failed to acquire lock: %s", err.Error()) - return nil, err - } - - return &lck, nil + return creds, err } // remotesapiAuth facilitates the implementation remotesrv.AccessControl for the remotesapi server. diff --git a/go/cmd/dolt/commands/stashcmds/clear.go b/go/cmd/dolt/commands/stashcmds/clear.go index 8c81bd1451..456319f90f 100644 --- a/go/cmd/dolt/commands/stashcmds/clear.go +++ b/go/cmd/dolt/commands/stashcmds/clear.go @@ -71,9 +71,8 @@ func (cmd StashClearCmd) Exec(ctx context.Context, commandStr string, args []str ap := cmd.ArgParser() help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, stashClearDocs, ap)) apr := cli.ParseArgsOrDie(ap, args, help) - if dEnv.IsLocked() { - return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), help) - } + + // TODO: Error if dEnv.DoltDB.AccessMode() == ReadOnly? if apr.NArg() != 0 { usage() diff --git a/go/cmd/dolt/commands/stashcmds/drop.go b/go/cmd/dolt/commands/stashcmds/drop.go index 3873e8bfc1..ab1c720c55 100644 --- a/go/cmd/dolt/commands/stashcmds/drop.go +++ b/go/cmd/dolt/commands/stashcmds/drop.go @@ -74,9 +74,8 @@ func (cmd StashDropCmd) Exec(ctx context.Context, commandStr string, args []stri ap := cmd.ArgParser() help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, stashDropDocs, ap)) apr := cli.ParseArgsOrDie(ap, args, help) - if dEnv.IsLocked() { - return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), help) - } + + // TODO: Error if dEnv.DoltDB.AccessMode() == ReadOnly? var idx = 0 var err error diff --git a/go/cmd/dolt/commands/stashcmds/list.go b/go/cmd/dolt/commands/stashcmds/list.go index d28ce12730..b00d7043ca 100644 --- a/go/cmd/dolt/commands/stashcmds/list.go +++ b/go/cmd/dolt/commands/stashcmds/list.go @@ -71,9 +71,8 @@ func (cmd StashListCmd) Exec(ctx context.Context, commandStr string, args []stri ap := cmd.ArgParser() help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, stashListDocs, ap)) cli.ParseArgsOrDie(ap, args, help) - if dEnv.IsLocked() { - return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), help) - } + + // TODO: Error if dEnv.DoltDB.AccessMode() == ReadOnly? err := listStashes(ctx, dEnv) if err != nil { diff --git a/go/cmd/dolt/commands/stashcmds/pop.go b/go/cmd/dolt/commands/stashcmds/pop.go index 5dddd4ae32..8ac10fd5ec 100644 --- a/go/cmd/dolt/commands/stashcmds/pop.go +++ b/go/cmd/dolt/commands/stashcmds/pop.go @@ -80,9 +80,8 @@ func (cmd StashPopCmd) Exec(ctx context.Context, commandStr string, args []strin ap := cmd.ArgParser() help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, stashPopDocs, ap)) apr := cli.ParseArgsOrDie(ap, args, help) - if dEnv.IsLocked() { - return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), help) - } + + // TODO: Error if dEnv.DoltDB.AccessMode() == ReadOnly? _, sqlCtx, closer, err := cliCtx.QueryEngine(ctx) if err != nil { diff --git a/go/cmd/dolt/commands/stashcmds/stash.go b/go/cmd/dolt/commands/stashcmds/stash.go index 39a836f792..ef1aca7087 100644 --- a/go/cmd/dolt/commands/stashcmds/stash.go +++ b/go/cmd/dolt/commands/stashcmds/stash.go @@ -21,7 +21,6 @@ import ( "github.com/dolthub/dolt/go/cmd/dolt/cli" "github.com/dolthub/dolt/go/cmd/dolt/commands" - "github.com/dolthub/dolt/go/cmd/dolt/errhand" eventsapi "github.com/dolthub/dolt/go/gen/proto/dolt/services/eventsapi/v1alpha1" "github.com/dolthub/dolt/go/libraries/doltcore/diff" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" @@ -100,9 +99,7 @@ func (cmd StashCmd) Exec(ctx context.Context, commandStr string, args []string, return 1 } - if dEnv.IsLocked() { - return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrActiveServerLock.New(dEnv.LockFile())), help) - } + // TODO: Error if dEnv.DoltDB.AccessMode() == ReadOnly? err := stashChanges(ctx, dEnv, apr) if err != nil { diff --git a/go/cmd/dolt/dolt.go b/go/cmd/dolt/dolt.go index 41b3ef5b28..a43c653da6 100644 --- a/go/cmd/dolt/dolt.go +++ b/go/cmd/dolt/dolt.go @@ -440,7 +440,9 @@ func runMain() int { var fs filesys.Filesys fs = filesys.LocalFS dEnv := env.Load(ctx, env.GetCurrentUserHomeDir, fs, doltdb.LocalDirDoltDB, Version) - dEnv.IgnoreLockFile = ignoreLockFile + + // TODO: Decide what we're doing with --ignore-lock-file; does it mean always operate locally? + _ = ignoreLockFile root, err := env.GetCurrentUserHomeDir() if err != nil { @@ -550,7 +552,7 @@ func runMain() int { } dEnv.FS = dataDirFS - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dataDirFS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dataDirFS, dEnv.Version, dEnv) if err != nil { cli.PrintErrln("failed to load database names") return 1 @@ -699,7 +701,11 @@ If you're interested in running this command against a remote host, hit us up on targetEnv = rootEnv } - isLocked, lock, err := targetEnv.GetLock() + // TODO: if targetEnv.DoltDB.AccessMode() == ReadOnly... + // Need to go looking for local creds to use... + var isLocked bool + var lock *sqlserver.LocalCreds + var err error if err != nil { return nil, err } diff --git a/go/libraries/doltcore/env/environment.go b/go/libraries/doltcore/env/environment.go index 5973fdd06e..3888583244 100644 --- a/go/libraries/doltcore/env/environment.go +++ b/go/libraries/doltcore/env/environment.go @@ -20,12 +20,9 @@ import ( "fmt" "os" "path/filepath" - "strconv" "strings" "time" - "github.com/google/uuid" - ps "github.com/mitchellh/go-ps" goerrors "gopkg.in/src-d/go-errors.v1" "github.com/dolthub/dolt/go/cmd/dolt/errhand" @@ -97,7 +94,6 @@ type DoltEnv struct { urlStr string hdp HomeDirProvider - IgnoreLockFile bool UserPassConfig *creds.DoltCredsForPass } @@ -1187,164 +1183,3 @@ func (dEnv *DoltEnv) BulkDbEaFactory() editor.DbEaFactory { } return editor.NewBulkImportTEAFactory(dEnv.DoltDB.ValueReadWriter(), tmpDir) } - -func (dEnv *DoltEnv) LockFile() string { - f, _ := dEnv.FS.Abs(filepath.Join(dbfactory.DoltDir, ServerLockFile)) - return f -} - -// IsLocked returns true if this database's lockfile exists and the pid contained in lockfile is alive. -func (dEnv *DoltEnv) IsLocked() bool { - if dEnv.IgnoreLockFile { - return false - } - - ans, _, _ := fsIsLocked(dEnv.FS) - return ans -} - -// GetLock returns the lockfile for this database or nil if the database is not locked -func (dEnv *DoltEnv) GetLock() (bool, *DBLock, error) { - if dEnv.IgnoreLockFile { - return false, nil, nil - } - - return fsIsLocked(dEnv.FS) -} - -// DBLock is a struct that contains the pid of the process that created the lockfile and the port that the server is running on -// The secret is used by dolt to ensure that the contents of the lockfile are required to perform a local server connection -type DBLock struct { - Pid int - Port int - Secret string -} - -// DBLock constructor -func NewDBLock(port int) DBLock { - return DBLock{Pid: os.Getpid(), Port: port, Secret: uuid.New().String()} -} - -// Lock writes this database's lockfile with the pid of the calling process or errors if it already exists -func (dEnv *DoltEnv) Lock(lock *DBLock) error { - if dEnv.IgnoreLockFile { - return nil - } - - if dEnv.IsLocked() { - return ErrActiveServerLock.New(dEnv.LockFile()) - } - - return WriteLockfile(dEnv.FS, lock) -} - -func LoadDBLockFile(fs filesys.Filesys, lockFilePath string) (lock *DBLock, err error) { - rd, err := fs.OpenForRead(lockFilePath) - if err != nil { - return nil, err - } - defer rd.Close() - - b := make([]byte, 256) - n, err := rd.Read(b) - if err != nil { - return nil, err - } - - data := strings.TrimSpace(string(b[:n])) - - parts := strings.Split(data, ":") - if len(parts) == 1 { - // Legacy Lock file. We can remove this code path in a couple of months (6/2023) - pid, err := strconv.Atoi(parts[0]) - if err != nil { - return nil, err - } - return &DBLock{Pid: pid, Port: -1, Secret: ""}, nil - } - if len(parts) != 3 { - return nil, fmt.Errorf("invalid lock file format") - } - - pid, err := strconv.Atoi(parts[0]) - if err != nil { - return nil, err - } - port := -1 - if parts[1] != "-" { - port, err = strconv.Atoi(parts[1]) - if err != nil { - return nil, err - } - } - secret := parts[2] - return &DBLock{Pid: pid, Port: port, Secret: secret}, nil -} - -// Unlock deletes this database's lockfile -func (dEnv *DoltEnv) Unlock() error { - if dEnv.IgnoreLockFile { - return nil - } - - return dEnv.FS.DeleteFile(dEnv.LockFile()) -} - -// WriteLockfile writes a lockfile encoding the pid of the calling process. -func WriteLockfile(fs filesys.Filesys, lock *DBLock) error { - // if the DoltDir doesn't exist, create it. - doltDir, _ := fs.Abs(dbfactory.DoltDir) - err := fs.MkDirs(doltDir) - if err != nil { - return err - } - - lockFile, _ := fs.Abs(filepath.Join(dbfactory.DoltDir, ServerLockFile)) - - portStr := strconv.Itoa(lock.Port) - if lock.Port < 0 { - portStr = "-" - } - - err = fs.WriteFile(lockFile, []byte(fmt.Sprintf("%d:%s:%s", lock.Pid, portStr, lock.Secret)), 0600) - if err != nil { - return err - } - - return nil -} - -// fsIsLocked returns true if the database in qeustion is locked. Two additional return values are lock and err. In the -// event that the DB is locked (locked == true), then either the lock or an error is returned. In either case, -// the caller should not attempt to use the DB. If lock is returned, in some cases you can use it to connect to the -// server that has locked the DB. If an error is returned, then no further processing should be done. -func fsIsLocked(fs filesys.Filesys) (locked bool, lock *DBLock, err error) { - lockFile, _ := fs.Abs(filepath.Join(dbfactory.DoltDir, ServerLockFile)) - - ok, _ := fs.Exists(lockFile) - if !ok { - return false, nil, nil - } - - loadedLock, err := LoadDBLockFile(fs, lockFile) - if err != nil { // if there's any error assume that env is locked since the file exists - return true, nil, err - } - - // If the PID is for this process, then ignore the lock file. This happens frequently with docker containers - // https://github.com/dolthub/dolt/issues/6183. - if os.Getpid() == loadedLock.Pid { - return false, nil, nil - } - - // Check whether the pid that spawned the lock file is still running. Ignore it if not. - proc, err := ps.FindProcess(loadedLock.Pid) - if err != nil { - return true, nil, err // This will happen if we can't load the OS processes. Assume locked. - } - if proc != nil { - return true, loadedLock, nil // The process is still running. Return the lock details so the caller can connect to it if appropriate. - } - - return false, nil, nil -} diff --git a/go/libraries/doltcore/env/multi_repo_env.go b/go/libraries/doltcore/env/multi_repo_env.go index e61f9a7a2d..6f966d8f5a 100644 --- a/go/libraries/doltcore/env/multi_repo_env.go +++ b/go/libraries/doltcore/env/multi_repo_env.go @@ -53,12 +53,11 @@ type MultiRepoEnv struct { fs filesys.Filesys cfg config.ReadWriteConfig dialProvider dbfactory.GRPCDialProvider - ignoreLockFile bool } // NewMultiEnv returns a new MultiRepoEnv instance dirived from a root DoltEnv instance. func MultiEnvForSingleEnv(ctx context.Context, env *DoltEnv) (*MultiRepoEnv, error) { - return MultiEnvForDirectory(ctx, env.Config.WriteableConfig(), env.FS, env.Version, env.IgnoreLockFile, env) + return MultiEnvForDirectory(ctx, env.Config.WriteableConfig(), env.FS, env.Version, env) } // MultiEnvForDirectory returns a MultiRepoEnv for the directory rooted at the file system given. The doltEnv from the @@ -69,7 +68,6 @@ func MultiEnvForDirectory( config config.ReadWriteConfig, dataDirFS filesys.Filesys, version string, - ignoreLockFile bool, dEnv *DoltEnv, ) (*MultiRepoEnv, error) { // Load current dataDirFS and put into mr env @@ -94,7 +92,6 @@ func MultiEnvForDirectory( fs: dataDirFS, cfg: config, dialProvider: NewGRPCDialProviderFromDoltEnv(newDEnv), - ignoreLockFile: ignoreLockFile, } envSet := map[string]*DoltEnv{} diff --git a/go/libraries/doltcore/env/multi_repo_env_test.go b/go/libraries/doltcore/env/multi_repo_env_test.go index f4b5eeba02..c5d2674093 100644 --- a/go/libraries/doltcore/env/multi_repo_env_test.go +++ b/go/libraries/doltcore/env/multi_repo_env_test.go @@ -121,7 +121,7 @@ func TestMultiEnvForDirectory(t *testing.T) { envPath := filepath.Join(rootPath, " test---name _ 123") dEnv := initRepoWithRelativePath(t, envPath, hdp) - mrEnv, err := MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) require.NoError(t, err) assert.Len(t, mrEnv.envs, 1) @@ -158,7 +158,7 @@ func TestMultiEnvForDirectoryWithMultipleRepos(t *testing.T) { subEnv1 := initRepoWithRelativePath(t, filepath.Join(envPath, "abc"), hdp) subEnv2 := initRepoWithRelativePath(t, filepath.Join(envPath, "def"), hdp) - mrEnv, err := MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) require.NoError(t, err) assert.Len(t, mrEnv.envs, 3) diff --git a/go/libraries/doltcore/merge/integration_test.go b/go/libraries/doltcore/merge/integration_test.go index 1bd376f9c9..03e3418c85 100644 --- a/go/libraries/doltcore/merge/integration_test.go +++ b/go/libraries/doltcore/merge/integration_test.go @@ -363,7 +363,7 @@ func setupConcurrencyTest(t *testing.T, ctx context.Context) (dEnv *env.DoltEnv) } func engineFromEnvironment(ctx context.Context, dEnv *env.DoltEnv) (dbName string, eng *engine.SqlEngine) { - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { panic(err) } diff --git a/go/libraries/doltcore/mvdata/engine_table_reader.go b/go/libraries/doltcore/mvdata/engine_table_reader.go index fe3573df08..5a87ed027f 100644 --- a/go/libraries/doltcore/mvdata/engine_table_reader.go +++ b/go/libraries/doltcore/mvdata/engine_table_reader.go @@ -42,7 +42,7 @@ type sqlEngineTableReader struct { } func NewSqlEngineReader(ctx context.Context, dEnv *env.DoltEnv, tableName string) (*sqlEngineTableReader, error) { - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { return nil, err } diff --git a/go/libraries/doltcore/mvdata/engine_table_writer.go b/go/libraries/doltcore/mvdata/engine_table_writer.go index 0f2695f4b0..f786a37246 100644 --- a/go/libraries/doltcore/mvdata/engine_table_writer.go +++ b/go/libraries/doltcore/mvdata/engine_table_writer.go @@ -62,11 +62,9 @@ type SqlEngineTableWriter struct { } func NewSqlEngineTableWriter(ctx context.Context, dEnv *env.DoltEnv, createTableSchema, rowOperationSchema schema.Schema, options *MoverOptions, statsCB noms.StatsCB) (*SqlEngineTableWriter, error) { - if dEnv.IsLocked() { - return nil, env.ErrActiveServerLock.New(dEnv.LockFile()) - } + // TODO: Assert that dEnv.DoltDB.AccessMode() != ReadOnly? - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { return nil, err } diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_harness.go b/go/libraries/doltcore/sqle/enginetest/dolt_harness.go index aefbabff3e..17f12f2b3f 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_harness.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_harness.go @@ -420,7 +420,7 @@ func (d *DoltHarness) newProvider() sql.MutableDatabaseProvider { store := dEnv.DoltDB.ValueReadWriter().(*types.ValueStore) store.SetValidateContentAddresses(true) - mrEnv, err := env.MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) require.NoError(d.t, err) d.multiRepoEnv = mrEnv diff --git a/go/libraries/doltcore/sqle/index/mergeable_indexes_setup_test.go b/go/libraries/doltcore/sqle/index/mergeable_indexes_setup_test.go index cee830b107..e6c6b79292 100644 --- a/go/libraries/doltcore/sqle/index/mergeable_indexes_setup_test.go +++ b/go/libraries/doltcore/sqle/index/mergeable_indexes_setup_test.go @@ -95,7 +95,7 @@ func setupIndexes(t *testing.T, tableName, insertQuery string) (*sqle.Engine, *s cols: idxv2v1Cols, } - mrEnv, err := env.MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) require.NoError(t, err) b := env.GetDefaultInitBranch(dEnv.Config) pro, err := dsqle.NewDoltDatabaseProviderWithDatabase(b, mrEnv.FileSystem(), db, dEnv.FS) diff --git a/go/libraries/doltcore/sqle/logictest/dolt/doltharness.go b/go/libraries/doltcore/sqle/logictest/dolt/doltharness.go index 5886f1fbda..37e49f1474 100644 --- a/go/libraries/doltcore/sqle/logictest/dolt/doltharness.go +++ b/go/libraries/doltcore/sqle/logictest/dolt/doltharness.go @@ -286,7 +286,7 @@ func sqlNewEngine(dEnv *env.DoltEnv) (*sqle.Engine, dsess.DoltDatabaseProvider, return nil, nil, err } - mrEnv, err := env.MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(context.Background(), dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { return nil, nil, err } diff --git a/go/libraries/doltcore/sqle/sqlddl_test.go b/go/libraries/doltcore/sqle/sqlddl_test.go index b0ea1d6cad..269d4e83ea 100644 --- a/go/libraries/doltcore/sqle/sqlddl_test.go +++ b/go/libraries/doltcore/sqle/sqlddl_test.go @@ -1108,7 +1108,7 @@ func newTestEngine(ctx context.Context, dEnv *env.DoltEnv) (*gms.Engine, *sql.Co panic(err) } - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) if err != nil { panic(err) } diff --git a/go/performance/microsysbench/sysbench_test.go b/go/performance/microsysbench/sysbench_test.go index 5cc5434fa3..2b894f7abc 100644 --- a/go/performance/microsysbench/sysbench_test.go +++ b/go/performance/microsysbench/sysbench_test.go @@ -115,7 +115,7 @@ func setupBenchmark(t *testing.B, dEnv *env.DoltEnv) (*sql.Context, *engine.SqlE Autocommit: true, } - mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv.IgnoreLockFile, dEnv) + mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) require.NoError(t, err) eng, err := engine.NewSqlEngine(ctx, mrEnv, config)