vitess.io/vitess@v0.16.2/go/vt/schemamanager/schemamanager.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package schemamanager 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "time" 23 24 "context" 25 26 "vitess.io/vitess/go/vt/log" 27 querypb "vitess.io/vitess/go/vt/proto/query" 28 ) 29 30 const ( 31 // SchemaChangeDirName is the key name in the ControllerFactory params. 32 // It specifies the schema change directory. 33 SchemaChangeDirName = "schema_change_dir" 34 // SchemaChangeUser is the key name in the ControllerFactory params. 35 // It specifies the user who submits this schema change. 36 SchemaChangeUser = "schema_change_user" 37 ) 38 39 // ControllerFactory takes a set params and construct a Controller instance. 40 type ControllerFactory func(params map[string]string) (Controller, error) 41 42 var ( 43 controllerFactories = make(map[string]ControllerFactory) 44 ) 45 46 // Controller is responsible for getting schema change for a 47 // certain keyspace and also handling various events happened during schema 48 // change. 49 type Controller interface { 50 Open(ctx context.Context) error 51 Read(ctx context.Context) (sqls []string, err error) 52 Close() 53 Keyspace() string 54 OnReadSuccess(ctx context.Context) error 55 OnReadFail(ctx context.Context, err error) error 56 OnValidationSuccess(ctx context.Context) error 57 OnValidationFail(ctx context.Context, err error) error 58 OnExecutorComplete(ctx context.Context, result *ExecuteResult) error 59 } 60 61 // Executor applies schema changes to underlying system 62 type Executor interface { 63 Open(ctx context.Context, keyspace string) error 64 Validate(ctx context.Context, sqls []string) error 65 Execute(ctx context.Context, sqls []string) *ExecuteResult 66 Close() 67 } 68 69 // ExecuteResult contains information about schema management state 70 type ExecuteResult struct { 71 FailedShards []ShardWithError 72 SuccessShards []ShardResult 73 CurSQLIndex int 74 Sqls []string 75 UUIDs []string 76 ExecutorErr string 77 TotalTimeSpent time.Duration 78 } 79 80 // ShardWithError contains information why a shard failed to execute given sql 81 type ShardWithError struct { 82 Shard string 83 Err string 84 } 85 86 // ShardResult contains sql execute information on a particular shard 87 type ShardResult struct { 88 Shard string 89 Result *querypb.QueryResult 90 // Position is a replication position that is guaranteed to be after the 91 // schema change was applied. It can be used to wait for replicas to receive 92 // the schema change via replication. 93 Position string 94 } 95 96 // Run applies schema changes on Vitess through VtGate. 97 func Run(ctx context.Context, controller Controller, executor Executor) (execResult *ExecuteResult, err error) { 98 if err := controller.Open(ctx); err != nil { 99 log.Errorf("failed to open data sourcer: %v", err) 100 return execResult, err 101 } 102 defer controller.Close() 103 sqls, err := controller.Read(ctx) 104 if err != nil { 105 log.Errorf("failed to read data from data sourcer: %v", err) 106 controller.OnReadFail(ctx, err) 107 return execResult, err 108 } 109 controller.OnReadSuccess(ctx) 110 if len(sqls) == 0 { 111 return execResult, nil 112 } 113 keyspace := controller.Keyspace() 114 if err := executor.Open(ctx, keyspace); err != nil { 115 log.Errorf("failed to open executor: %v", err) 116 return execResult, err 117 } 118 defer executor.Close() 119 if err := executor.Validate(ctx, sqls); err != nil { 120 log.Errorf("validation fail: %v", err) 121 controller.OnValidationFail(ctx, err) 122 return execResult, err 123 } 124 125 if err := controller.OnValidationSuccess(ctx); err != nil { 126 return execResult, err 127 } 128 129 execResult = executor.Execute(ctx, sqls) 130 131 if err := controller.OnExecutorComplete(ctx, execResult); err != nil { 132 return execResult, err 133 } 134 if execResult.ExecutorErr != "" || len(execResult.FailedShards) > 0 { 135 out, _ := json.MarshalIndent(execResult, "", " ") 136 return execResult, fmt.Errorf("schema change failed, ExecuteResult: %v", string(out)) 137 } 138 return execResult, nil 139 } 140 141 // RegisterControllerFactory register a control factory. 142 func RegisterControllerFactory(name string, factory ControllerFactory) { 143 if _, ok := controllerFactories[name]; ok { 144 panic(fmt.Sprintf("register a registered key: %s", name)) 145 } 146 controllerFactories[name] = factory 147 } 148 149 // GetControllerFactory gets a ControllerFactory. 150 func GetControllerFactory(name string) (ControllerFactory, error) { 151 factory, ok := controllerFactories[name] 152 if !ok { 153 return nil, fmt.Errorf("there is no data sourcer factory with name: %s", name) 154 } 155 return factory, nil 156 }