Skip to content

Commit

Permalink
Merge pull request #7069 from dolthub/aaron/new-sql-server-lock-seman…
Browse files Browse the repository at this point in the history
…tics

go/cmd/dolt: Implement new semantics for sql-server.lock.
  • Loading branch information
reltuk authored Dec 1, 2023
2 parents 0d5eeb5 + 2d738b7 commit b977298
Show file tree
Hide file tree
Showing 58 changed files with 833 additions and 679 deletions.
28 changes: 0 additions & 28 deletions go/Godeps/LICENSES

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion go/cmd/dolt/commands/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
6 changes: 1 addition & 5 deletions go/cmd/dolt/commands/engine/sqlengine.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,6 @@ func NewSqlEngine(
mrEnv *env.MultiRepoEnv,
config *SqlEngineConfig,
) (*SqlEngine, error) {
if ok, _ := mrEnv.IsLocked(); ok {
config.IsServerLocked = true
}

dbs, locations, err := CollectDBs(ctx, mrEnv, config.Bulk)
if err != nil {
return nil, err
Expand Down Expand Up @@ -411,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
}
Expand Down
6 changes: 1 addition & 5 deletions go/cmd/dolt/commands/filter-branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,6 @@ 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)
}

queryString := apr.GetValueOrDefault(QueryFlag, "")
verbose := apr.Contains(cli.VerboseFlag)
continueOnErr := apr.Contains(continueFlag)
Expand Down Expand Up @@ -281,7 +277,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
}
Expand Down
7 changes: 5 additions & 2 deletions go/cmd/dolt/commands/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ 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)
// We assert this here simply because the implementation of GC can
// delay actually trying to write to the chunk store for a long time
// after doing a lot or work. It's better to fail early.
if dEnv.IsAccessModeReadOnly() {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(env.ErrDatabaseIsLocked), help)
}

var err error
Expand Down
5 changes: 0 additions & 5 deletions go/cmd/dolt/commands/indexcmds/rebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -72,10 +71,6 @@ 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)
}

working, err := dEnv.WorkingRoot(context.Background())
if err != nil {
return HandleErr(errhand.BuildDError("Unable to get working.").AddCause(err).Build(), nil)
Expand Down
4 changes: 0 additions & 4 deletions go/cmd/dolt/commands/schcmds/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,6 @@ 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)
}

return commands.HandleVErrAndExitCode(importSchema(ctx, dEnv, apr), usage)
}

Expand Down
156 changes: 156 additions & 0 deletions go/cmd/dolt/commands/sqlserver/creds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// 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 (
"errors"
"fmt"
iofs "io/fs"
"os"
"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.info"

// 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)
}

// Starting at `fs`, look for the a ServerLocalCredsFile in the .dolt directory
// of this directory and every parent directory, until we find one. When we
// find one, we return its contents if we can open and parse it successfully.
// Otherwise, we return an error associated with attempting to read it. If we
// do not find anything all the way up to the root of the filesystem, returns
// `nil` *LocalCreds and a `nil` error.
func FindAndLoadLocalCreds(fs filesys.Filesys) (creds *LocalCreds, err error) {
root, err := fs.Abs(".")
if err != nil {
return nil, err
}
for root != "" && root[len(root)-1] != '/' {
creds, err := LoadLocalCreds(fs)
if err == nil {
return creds, err
}
// If we have an error that is not ErrNotExist, for example, a
// permission error opening the credentials file, or an error
// indicating that the contents of the file were malformed, go
// ahead and return the error and terminate our search here.
if !errors.Is(err, iofs.ErrNotExist) {
return nil, err
}
fs, err = fs.WithWorkingDir("..")
if err != nil {
return nil, err
}
root, err = fs.Abs(".")
if err != nil {
return nil, err
}
}
return nil, nil
}

func LoadLocalCreds(fs filesys.Filesys) (creds *LocalCreds, err error) {
rd, err := fs.OpenForRead(filepath.Join(dbfactory.DoltDir, ServerLocalCredsFile))
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) != 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
}
Loading

0 comments on commit b977298

Please sign in to comment.