github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/cluster/initdbhook.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cluster
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/dolthub/go-mysql-server/sql"
    23  
    24  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    25  	"github.com/dolthub/dolt/go/libraries/doltcore/env"
    26  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle"
    27  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
    28  	"github.com/dolthub/dolt/go/store/types"
    29  )
    30  
    31  func NewInitDatabaseHook(controller *Controller, bt *sql.BackgroundThreads) sqle.InitDatabaseHook {
    32  	return func(ctx *sql.Context, pro *sqle.DoltDatabaseProvider, name string, denv *env.DoltEnv, db dsess.SqlDatabase) error {
    33  		dialprovider := controller.gRPCDialProvider(denv)
    34  		var remoteDBs []func(context.Context) (*doltdb.DoltDB, error)
    35  		var remoteUrls []string
    36  		for _, r := range controller.cfg.StandbyRemotes() {
    37  			// TODO: url sanitize name
    38  			remoteUrl := strings.Replace(r.RemoteURLTemplate(), dsess.URLTemplateDatabasePlaceholder, name, -1)
    39  
    40  			// We're going to check if this database already has
    41  			// the remote we're trying to add. This can happen in
    42  			// the DOLT_UNDROP case, for example. If a matching
    43  			// remote exists, we assert that it has the expected
    44  			// URL. It's an error otherwise.
    45  			remotes, err := denv.GetRemotes()
    46  			if err != nil {
    47  				// XXX: An error here means we are not replicating.
    48  				return err
    49  			}
    50  
    51  			var er env.Remote
    52  			var ok bool
    53  			if er, ok = remotes.Get(r.Name()); ok {
    54  				if er.Url != remoteUrl {
    55  					return fmt.Errorf("invalid remote (%s) for cluster replication found in database %s: expect url %s but the existing remote had url %s", r.Name(), name, remoteUrl, er.Url)
    56  				}
    57  			} else {
    58  				// TODO: Assert remotesapi URL.
    59  				er = env.NewRemote(r.Name(), remoteUrl, nil)
    60  				err := denv.AddRemote(er)
    61  				if err != nil {
    62  					return err
    63  				}
    64  			}
    65  
    66  			remoteDBs = append(remoteDBs, func(ctx context.Context) (*doltdb.DoltDB, error) {
    67  				return er.GetRemoteDB(ctx, types.Format_Default, dialprovider)
    68  			})
    69  			remoteUrls = append(remoteUrls, remoteUrl)
    70  		}
    71  
    72  		// When we create a new database, we stop trying to replicate a
    73  		// previous drop of that database to the replicas. Successfully
    74  		// replicating a new head update will set the state of any
    75  		// existing database to the state of this new database going
    76  		// forward.
    77  		controller.cancelDropDatabaseReplication(name)
    78  
    79  		role, _ := controller.roleAndEpoch()
    80  		for i, r := range controller.cfg.StandbyRemotes() {
    81  			ttfdir, err := denv.TempTableFilesDir()
    82  			if err != nil {
    83  				// XXX: An error here means we are not replicating to every standby.
    84  				return err
    85  			}
    86  			commitHook := newCommitHook(controller.lgr, r.Name(), remoteUrls[i], name, role, remoteDBs[i], denv.DoltDB, ttfdir)
    87  			denv.DoltDB.PrependCommitHook(ctx, commitHook)
    88  			controller.registerCommitHook(commitHook)
    89  			if err := commitHook.Run(bt); err != nil {
    90  				// XXX: An error here means we are not replicating to every standby.
    91  				return err
    92  			}
    93  		}
    94  
    95  		return nil
    96  	}
    97  }