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 }