Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions go/cmd/dolt/cli/cli_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ type LateBindQueryistResult struct {
Closer func()
}

type LateBindQueryistConfig struct {
EnableAutoGC bool
}

type LateBindQueryistOption func(*LateBindQueryistConfig)

// LateBindQueryist is a function that will be called the first time Queryist is needed for use. Input is a context which
// is appropriate for the call to commence. Output is a LateBindQueryistResult, which includes a Queryist, a sql.Context, and
// a closer function. It can also result in an error.
Expand All @@ -48,15 +54,15 @@ type LateBindQueryistResult struct {
// This state is useful for determining whether a command making use of the CliContext is being run within the context of
// another command. This is particularly interesting when running a \checkout in a dolt sql session. It makes sense to do
// so in the context of `dolt sql`, but not in the context of `dolt checkout` when connected to a remote server.
type LateBindQueryist func(ctx context.Context) (LateBindQueryistResult, error)
type LateBindQueryist func(ctx context.Context, opts ...LateBindQueryistOption) (LateBindQueryistResult, error)

// CliContexct is used to pass top level command information down to subcommands.
type CliContext interface {
// GlobalArgs returns the arguments passed before the subcommand.
GlobalArgs() *argparser.ArgParseResults
WorkingDir() filesys.Filesys
Config() *env.DoltCliConfig
QueryEngine(ctx context.Context) (QueryEngineResult, error)
QueryEngine(ctx context.Context, opts ...LateBindQueryistOption) (QueryEngineResult, error)
// Release resources associated with the CliContext, including
// any QueryEngines which were provisioned over the lifetime
// of the CliContext.
Expand Down Expand Up @@ -115,7 +121,7 @@ func (lbc LateBindCliContext) GlobalArgs() *argparser.ArgParseResults {
// QueryEngine returns a Queryist, a sql.Context, a closer function, and an error. It ensures that only one call to the
// LateBindQueryist is made, and caches the result. Note that if this is called twice, the closer function returns will
// be nil, callers should check if is nil.
func (lbc LateBindCliContext) QueryEngine(ctx context.Context) (res QueryEngineResult, err error) {
func (lbc LateBindCliContext) QueryEngine(ctx context.Context, opts ...LateBindQueryistOption) (res QueryEngineResult, err error) {
if lbc.activeContext != nil && lbc.activeContext.qryist != nil && lbc.activeContext.sqlCtx != nil {
res.Queryist = *lbc.activeContext.qryist
res.Context = lbc.activeContext.sqlCtx
Expand All @@ -125,7 +131,7 @@ func (lbc LateBindCliContext) QueryEngine(ctx context.Context) (res QueryEngineR
return res, nil
}

bindRes, err := lbc.bind(ctx)
bindRes, err := lbc.bind(ctx, opts...)
if err != nil {
return res, err
}
Expand Down
2 changes: 2 additions & 0 deletions go/cmd/dolt/commands/engine/sqlengine.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ type SqlEngineConfig struct {
EventSchedulerStatus eventscheduler.SchedulerStatus
}

type SqlEngineConfigOption func(*SqlEngineConfig)

// NewSqlEngine returns a SqlEngine
func NewSqlEngine(
ctx context.Context,
Expand Down
4 changes: 3 additions & 1 deletion go/cmd/dolt/commands/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ func TestInit(t *testing.T) {
gCfg, _ := dEnv.Config.GetConfig(env.GlobalConfig)
gCfg.SetStrings(test.GlobalConfig)
apr := argparser.ArgParseResults{}
latebind := func(ctx context.Context) (res cli.LateBindQueryistResult, err error) { return res, nil }
latebind := func(ctx context.Context, opts ...cli.LateBindQueryistOption) (res cli.LateBindQueryistResult, err error) {
return res, nil
}
cliCtx, _ := cli.NewCliContext(&apr, dEnv.Config, dEnv.FS, latebind)

result := InitCmd{}.Exec(ctx, "dolt init", test.Args, dEnv, cliCtx)
Expand Down
21 changes: 20 additions & 1 deletion go/cmd/dolt/commands/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ const (
outputFlag = "output"
binaryAsHexFlag = "binary-as-hex"
skipBinaryAsHexFlag = "skip-binary-as-hex"
disableAutoGCFlag = "disable-auto-gc"
// TODO: Consider simplifying to use MySQL's skip pattern with single flag definition
// MySQL handles both --binary-as-hex and --skip-binary-as-hex with one option definition
// and uses disabled_my_option to distinguish between enable/disable
Expand Down Expand Up @@ -155,6 +156,7 @@ func (cmd SqlCmd) ArgParser() *argparser.ArgParser {
ap.SupportsFlag(binaryAsHexFlag, "", "Print binary data as hex. Enabled by default for interactive terminals.")
// TODO: MySQL uses a skip- pattern for negating flags and doesn't show them in help
ap.SupportsFlag(skipBinaryAsHexFlag, "", "Disable binary data as hex output.")
ap.SupportsFlag(disableAutoGCFlag, "", "Disable automatically running GC.")
return ap
}

Expand Down Expand Up @@ -227,7 +229,13 @@ func (cmd SqlCmd) Exec(ctx context.Context, commandStr string, args []string, dE
return HandleVErrAndExitCode(errhand.BuildDError("cannot use both --%s and --%s", binaryAsHexFlag, skipBinaryAsHexFlag).Build(), usage)
}

queryist, err := cliCtx.QueryEngine(ctx)
enableAutoGC := true
if apr.Contains(disableAutoGCFlag) {
enableAutoGC = false
}
queryist, err := cliCtx.QueryEngine(ctx, func(config *cli.LateBindQueryistConfig) {
config.EnableAutoGC = enableAutoGC
})
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
Expand Down Expand Up @@ -618,6 +626,11 @@ func execBatchMode(ctx *sql.Context, qryist cli.Queryist, input io.Reader, conti
scanner := NewStreamScanner(input)
var query string
for scanner.Scan() {
// The session we get is wrapped in a command begin/end block.
// By ending the command and starting a new one, Auto GC is able
// to form safe points if/when it is enabled.
sql.SessionCommandEnd(ctx.Session)
sql.SessionCommandBegin(ctx.Session)
if fileReadProg != nil {
updateFileReadProgressOutput()
fileReadProg.setReadBytes(int64(len(scanner.Bytes())))
Expand Down Expand Up @@ -763,6 +776,12 @@ func execShell(sqlCtx *sql.Context, qryist cli.Queryist, format engine.PrintResu
lastSqlCmd := ""

shell.Uninterpreted(func(c *ishell.Context) {
// The session we get is wrapped in a command begin/end block.
// By ending the command and starting a new one, Auto GC is able
// to form safe points if/when it is enabled.
sql.SessionCommandEnd(sqlCtx.Session)
sql.SessionCommandBegin(sqlCtx.Session)

query := c.Args[0]
query = strings.TrimSpace(query)
if len(query) == 0 {
Expand Down
2 changes: 1 addition & 1 deletion go/cmd/dolt/commands/sqlserver/queryist_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func BuildConnectionStringQueryist(ctx context.Context, cwdFS filesys.Filesys, c
gatherWarnings := false
queryist := ConnectionQueryist{connection: conn, gatherWarnings: &gatherWarnings}

var lateBind cli.LateBindQueryist = func(ctx context.Context) (res cli.LateBindQueryistResult, err error) {
var lateBind cli.LateBindQueryist = func(ctx context.Context, opts ...cli.LateBindQueryistOption) (res cli.LateBindQueryistResult, err error) {
sqlCtx := sql.NewContext(ctx)
sqlCtx.SetCurrentDatabase(dbRev)
res.Queryist = queryist
Expand Down
19 changes: 18 additions & 1 deletion go/cmd/dolt/commands/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"crypto/sha1"
"fmt"
"io"
"net"
"os"
"path/filepath"
Expand All @@ -31,6 +32,7 @@ import (
"github.com/fatih/color"
"github.com/gocraft/dbr/v2"
"github.com/gocraft/dbr/v2/dialect"
"github.com/sirupsen/logrus"

"github.com/dolthub/dolt/go/cmd/dolt/cli"
"github.com/dolthub/dolt/go/cmd/dolt/commands/engine"
Expand All @@ -39,11 +41,13 @@ import (
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/doltcore/env/actions"
"github.com/dolthub/dolt/go/libraries/doltcore/sqle"
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
"github.com/dolthub/dolt/go/libraries/utils/config"
"github.com/dolthub/dolt/go/libraries/utils/editor"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
"github.com/dolthub/dolt/go/store/chunks"
"github.com/dolthub/dolt/go/store/datas"
"github.com/dolthub/dolt/go/store/util/outputpager"
)
Expand Down Expand Up @@ -246,12 +250,25 @@ func newLateBindingEngine(
Autocommit: true,
}

var lateBinder cli.LateBindQueryist = func(ctx context.Context) (res cli.LateBindQueryistResult, err error) {
var lateBinder cli.LateBindQueryist = func(ctx context.Context, opts ...cli.LateBindQueryistOption) (res cli.LateBindQueryistResult, err error) {
// We've deferred loading the database as long as we can.
// If we're binding the Queryist, that means that engine is actually
// going to be used.
mrEnv.ReloadDBs(ctx)

queryistConfig := &cli.LateBindQueryistConfig{}
for _, opt := range opts {
opt(queryistConfig)
}

if queryistConfig.EnableAutoGC {
// We use a null logger here, as we do not want `dolt sql` output
// to include auto-gc log lines.
nullLgr := logrus.New()
nullLgr.SetOutput(io.Discard)
config.AutoGCController = sqle.NewAutoGCController(chunks.NoArchive, nullLgr)
}

se, err := engine.NewSqlEngine(
ctx,
mrEnv,
Expand Down
2 changes: 1 addition & 1 deletion go/cmd/dolt/dolt.go
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ If you're interested in running this command against a remote host, hit us up on
isValidRepositoryRequired := subcommandName != "init" && subcommandName != "sql" && subcommandName != "sql-server" && subcommandName != "sql-client"

if noValidRepository && isValidRepositoryRequired {
return func(ctx context.Context) (res cli.LateBindQueryistResult, err error) {
return func(ctx context.Context, opts ...cli.LateBindQueryistOption) (res cli.LateBindQueryistResult, err error) {
err = errors.New("The current directory is not a valid dolt repository.")
if errors.Is(rootEnv.DBLoadError, nbs.ErrUnsupportedTableFileFormat) {
// This is fairly targeted and specific to allow for better error messaging. We should consider
Expand Down
23 changes: 16 additions & 7 deletions go/libraries/doltcore/sqle/auto_gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,14 @@ func (c *AutoGCController) newCommitHook(name string, db *doltdb.DoltDB) *autoGC
closed := make(chan *gcWorkReport)
close(closed)
ret := &autoGCCommitHook{
c: c,
name: name,
done: closed,
next: make(chan *gcWorkReport, 1),
db: db,
tickCh: make(chan struct{}),
stopCh: make(chan struct{}),
c: c,
name: name,
done: closed,
next: make(chan *gcWorkReport, 1),
db: db,
tickCh: make(chan struct{}),
stopCh: make(chan struct{}),
stoppedCh: make(chan struct{}),
}
c.hooks[name] = ret
if c.threads != nil {
Expand Down Expand Up @@ -235,6 +236,11 @@ type autoGCCommitHook struct {
// Closed when the thread should shutdown because the database
// is being removed.
stopCh chan struct{}
// Closed as the background processing thread shuts down. The
// database hook selects on this to avoid deadlocking if it
// is trying to send to the worker thread after it has been
// shutdown.
stoppedCh chan struct{}
// An optimistic send on this channel notifies the background
// thread that the sizes may have changed and it can check for
// the GC condition.
Expand Down Expand Up @@ -280,6 +286,8 @@ func (h *autoGCCommitHook) Execute(ctx context.Context, _ datas.Dataset, _ *dolt
select {
case h.tickCh <- struct{}{}:
return nil, nil
case <-h.stoppedCh:
return nil, nil
case <-ctx.Done():
return nil, context.Cause(ctx)
}
Expand Down Expand Up @@ -359,6 +367,7 @@ func (h *autoGCCommitHook) checkForGC(ctx context.Context) error {

func (h *autoGCCommitHook) thread(ctx context.Context) {
defer h.wg.Done()
defer close(h.stoppedCh)
timer := time.NewTimer(checkInterval)
defer timer.Stop()
for {
Expand Down
12 changes: 7 additions & 5 deletions go/performance/microsysbench/sysbench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"os"
"strconv"
"strings"
"sync"
"testing"

"github.com/dolthub/go-mysql-server/server"
Expand Down Expand Up @@ -49,11 +50,6 @@ const (

var dEnv *env.DoltEnv

func init() {
dEnv = dtestutils.CreateTestEnv()
populateRepo(dEnv, readTestData(dataFile))
}

func BenchmarkOltpPointSelect(b *testing.B) {
benchmarkSysbenchQuery(b, func(int) string {
q := "SELECT c FROM sbtest1 WHERE id=%d"
Expand Down Expand Up @@ -119,7 +115,13 @@ func BenchmarkSelectRandomRanges(b *testing.B) {
})
}

var initOnce sync.Once

func benchmarkSysbenchQuery(b *testing.B, getQuery func(int) string) {
initOnce.Do(func() {
dEnv = dtestutils.CreateTestEnv()
populateRepo(dEnv, readTestData(dataFile))
})
ctx, eng := setupBenchmark(b, dEnv)
for i := 0; i < b.N; i++ {
schema, iter, _, err := eng.Query(ctx, getQuery(i))
Expand Down
23 changes: 23 additions & 0 deletions integration-tests/bats/gen_vals.awk
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function randint(n)
{
return int(n * rand())
}
function valueslines(n)
{
end = "),"
for (i = 0; i < n; i++) {
if (i == n-1) {
end = ");"
}
print "(" randint(65536) ",", randint(65536) ",", randint(65536) ",", randint(65536) end;
}
}
BEGIN {
print "DROP TABLE IF EXISTS vals;";
print "CREATE TABLE vals (c1 int, c2 int, c3 int, c4 int);";
for (j = 0; j < 256; j++) {
print "INSERT INTO vals VALUES";
valueslines(1024);
}
}

39 changes: 39 additions & 0 deletions integration-tests/bats/sql-auto-gc.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bats
load $BATS_TEST_DIRNAME/helper/common.bash

setup() {
setup_common
}

teardown() {
assert_feature_version
teardown_common
}

@test "sql-auto-gc: import through 'dolt sql' runs auto gc" {
if [ "$SQL_ENGINE" = "remote-engine" ]; then
skip "dolt sql does not control auto GC behavior when in remote mode"
fi

before=$(du -sk .dolt | awk '{print $1}')
awk -f $BATS_TEST_DIRNAME/gen_vals.awk | dolt sql
after=$(du -sk .dolt | awk '{print $1}')
[[ after-before -lt 524288 ]] || (echo ".dolt should be less than 512MB after the import" && false)
tablefiles=$(ls -1 .dolt/noms/ | egrep '[0-9a-v]{32}' | egrep -v 'v{32}')
[[ $(echo "$tablefiles" | wc -l) -eq 1 ]] || (echo ".dolt/noms should have one table file" && false)
}

@test "sql-auto-gc: import through 'dolt sql' can disable auto gc" {
if [ "$SQL_ENGINE" = "remote-engine" ]; then
skip "dolt sql does not control auto GC behavior when in remote mode"
fi

before=$(du -sk .dolt | awk '{print $1}')
awk -f $BATS_TEST_DIRNAME/gen_vals.awk | dolt sql --disable-auto-gc
after=$(du -sk .dolt | awk '{print $1}')
[[ after-before -gt 524288 ]] || (echo ".dolt should be more than 512MB after the import" && false)
if ls -1 .dolt/noms/ | egrep '[0-9a-v]{32}' | egrep -v 'v{32}'; then
echo ".dolt/noms should have two non-journal table files";
false
fi
}
Loading