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

     1  // Copyright 2022-2023 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  	"errors"
    19  	"fmt"
    20  
    21  	"github.com/dolthub/go-mysql-server/sql"
    22  	"github.com/dolthub/go-mysql-server/sql/types"
    23  
    24  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
    25  )
    26  
    27  var ErrServerTransitionedRolesErr = errors.New("this server transitioned cluster roles. this connection can no longer be used. please reconnect.")
    28  
    29  func newAssumeRoleProcedure(controller *Controller) sql.ExternalStoredProcedureDetails {
    30  	return sql.ExternalStoredProcedureDetails{
    31  		Name: "dolt_assume_cluster_role",
    32  		Schema: sql.Schema{
    33  			&sql.Column{
    34  				Name:     "status",
    35  				Type:     types.Int64,
    36  				Nullable: false,
    37  			},
    38  		},
    39  		Function: func(ctx *sql.Context, role string, epoch int) (sql.RowIter, error) {
    40  			if role == string(RoleDetectedBrokenConfig) {
    41  				return nil, errors.New("cannot set role to detected_broken_config; valid values are 'primary' and 'standby'")
    42  			}
    43  			saveConnID := int(ctx.Session.ID())
    44  			res, err := controller.setRoleAndEpoch(role, epoch, roleTransitionOptions{
    45  				graceful:   true,
    46  				saveConnID: &saveConnID,
    47  			})
    48  			if err != nil {
    49  				// We did not transition, no need to set our session to read-only, etc.
    50  				return nil, err
    51  			}
    52  			if res.changedRole {
    53  				// We transitioned, make sure we do not run anymore queries on this session.
    54  				ctx.Session.SetTransaction(nil)
    55  				dsess.DSessFromSess(ctx.Session).SetValidateErr(ErrServerTransitionedRolesErr)
    56  			}
    57  			return sql.RowsToRowIter(sql.Row{0}), nil
    58  		},
    59  		ReadOnly: true,
    60  	}
    61  }
    62  
    63  func newTransitionToStandbyProcedure(controller *Controller) sql.ExternalStoredProcedureDetails {
    64  	return sql.ExternalStoredProcedureDetails{
    65  		Name: "dolt_cluster_transition_to_standby",
    66  		Schema: sql.Schema{
    67  			&sql.Column{
    68  				Name:     "caught_up",
    69  				Type:     types.Int8,
    70  				Nullable: false,
    71  			},
    72  			&sql.Column{
    73  				Name:     "database",
    74  				Type:     types.LongText,
    75  				Nullable: false,
    76  			},
    77  			&sql.Column{
    78  				Name:     "remote",
    79  				Type:     types.LongText,
    80  				Nullable: false,
    81  			},
    82  			&sql.Column{
    83  				Name:     "remote_url",
    84  				Type:     types.LongText,
    85  				Nullable: false,
    86  			},
    87  		},
    88  		Function: func(ctx *sql.Context, epoch, minCaughtUpStandbys int) (sql.RowIter, error) {
    89  			saveConnID := int(ctx.Session.ID())
    90  			res, err := controller.setRoleAndEpoch("standby", epoch, roleTransitionOptions{
    91  				graceful:            true,
    92  				minCaughtUpStandbys: minCaughtUpStandbys,
    93  				saveConnID:          &saveConnID,
    94  			})
    95  			if err != nil {
    96  				// We did not transition, no need to set our session to read-only, etc.
    97  				return nil, err
    98  			}
    99  			if res.changedRole {
   100  				// We transitioned, make sure we do not run anymore queries on this session.
   101  				ctx.Session.SetTransaction(nil)
   102  				dsess.DSessFromSess(ctx.Session).SetValidateErr(ErrServerTransitionedRolesErr)
   103  				rows := make([]sql.Row, len(res.gracefulTransitionResults))
   104  				for i, r := range res.gracefulTransitionResults {
   105  					var caughtUp int8
   106  					if r.caughtUp {
   107  						caughtUp = 1
   108  					}
   109  					rows[i] = sql.Row{
   110  						caughtUp,
   111  						r.database,
   112  						r.remote,
   113  						r.remoteUrl,
   114  					}
   115  				}
   116  				return sql.RowsToRowIter(rows...), nil
   117  			} else {
   118  				return nil, fmt.Errorf("failed to transition server to standby; it is already standby.")
   119  			}
   120  		},
   121  	}
   122  }