diff --git a/go/cmd/dolt/commands/engine/utils.go b/go/cmd/dolt/commands/engine/utils.go index b775e18d5a0..a007643da5c 100644 --- a/go/cmd/dolt/commands/engine/utils.go +++ b/go/cmd/dolt/commands/engine/utils.go @@ -16,6 +16,8 @@ package engine import ( "context" + "errors" + "fmt" "github.com/dolthub/dolt/go/libraries/doltcore/env" "github.com/dolthub/dolt/go/libraries/doltcore/sqle" @@ -52,6 +54,9 @@ func CollectDBs(ctx context.Context, mrEnv *env.MultiRepoEnv) ([]dsess.SqlDataba func newDatabase(ctx context.Context, name string, dEnv *env.DoltEnv) (sqle.Database, error) { dbdata := dEnv.DbData(ctx) + if !dEnv.Valid() { + return sqle.Database{}, fmt.Errorf("failed to load database %q: %w", name, errors.Join(dEnv.CfgLoadErr, dEnv.DBLoadError)) + } // Databases registered with the SQL engine are always // configured for FatalBehaviorCrash. These are local // databases and it isn't necessarily safe to continue diff --git a/go/libraries/doltcore/env/multi_repo_env.go b/go/libraries/doltcore/env/multi_repo_env.go index 1e5f6c1a4dc..d41421a662c 100644 --- a/go/libraries/doltcore/env/multi_repo_env.go +++ b/go/libraries/doltcore/env/multi_repo_env.go @@ -188,8 +188,10 @@ func MultiEnvForDirectory( } envSet := map[string]*DoltEnv{} + var openedEnvs []*DoltEnv if newDEnv.Valid() { envSet[dbName] = newDEnv + openedEnvs = append(openedEnvs, newDEnv) } else { dbErr := newDEnv.DBLoadError if dbErr != nil { @@ -231,6 +233,7 @@ func MultiEnvForDirectory( } if newEnv.Valid() { envSet[dbfactory.DirToDBName(dir)] = newEnv + openedEnvs = append(openedEnvs, newEnv) } else { dbErr := newEnv.DBLoadError if dbErr != nil { @@ -249,6 +252,11 @@ func MultiEnvForDirectory( return false }) if err != nil { + for _, dEnv := range openedEnvs { + if ddb := dEnv.DoltDB(ctx); ddb != nil { + ddb.Close() + } + } return nil, err } @@ -311,6 +319,19 @@ func (mrEnv *MultiRepoEnv) Config() config.ReadWriteConfig { return mrEnv.cfg } +// Close closes all DoltDBs held by environments in this MultiRepoEnv. +func (mrEnv *MultiRepoEnv) Close(ctx context.Context) error { + var errs []error + for _, namedEnv := range mrEnv.envs { + if ddb := namedEnv.env.DoltDB(ctx); ddb != nil { + if err := ddb.Close(); err != nil { + errs = append(errs, err) + } + } + } + return errors.Join(errs...) +} + // addEnv adds an environment to the MultiRepoEnv by name func (mrEnv *MultiRepoEnv) addEnv(name string, dEnv *DoltEnv) { mrEnv.envs = append(mrEnv.envs, NamedEnv{ diff --git a/go/libraries/doltcore/env/multi_repo_env_test.go b/go/libraries/doltcore/env/multi_repo_env_test.go index 9a5b6bdb82b..e581ef79921 100644 --- a/go/libraries/doltcore/env/multi_repo_env_test.go +++ b/go/libraries/doltcore/env/multi_repo_env_test.go @@ -176,6 +176,24 @@ func TestMultiEnvForDirectoryWithMultipleRepos(t *testing.T) { assert.Equal(t, expected, actual) } +func TestMultiRepoEnvClose(t *testing.T) { + rootPath, err := test.ChangeToTestDir("TestMultiRepoEnvClose") + require.NoError(t, err) + + hdp := func() (string, error) { return rootPath, nil } + envPath := filepath.Join(rootPath, "main_db") + dEnv := initRepoWithRelativePath(t, envPath, hdp) + _ = initRepoWithRelativePath(t, filepath.Join(envPath, "sub_db"), hdp) + + ctx := context.Background() + mrEnv, err := MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv) + require.NoError(t, err) + assert.Len(t, mrEnv.envs, 2) + + err = mrEnv.Close(ctx) + require.NoError(t, err) +} + func initMultiEnv(t *testing.T, testName string, names []string) (string, HomeDirProvider, map[string]*DoltEnv) { rootPath, err := test.ChangeToTestDir(testName) require.NoError(t, err)