vitess.io/vitess@v0.16.2/go/vt/schema/ddl_strategy.go (about) 1 /* 2 Copyright 2021 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 schema 18 19 import ( 20 "fmt" 21 "regexp" 22 23 "github.com/google/shlex" 24 ) 25 26 var ( 27 strategyParserRegexp = regexp.MustCompile(`^([\S]+)\s+(.*)$`) 28 ) 29 30 const ( 31 declarativeFlag = "declarative" 32 skipTopoFlag = "skip-topo" // legacy. Kept for backwards compatibility, but unused 33 singletonFlag = "singleton" 34 singletonContextFlag = "singleton-context" 35 allowZeroInDateFlag = "allow-zero-in-date" 36 postponeLaunchFlag = "postpone-launch" 37 postponeCompletionFlag = "postpone-completion" 38 inOrderCompletionFlag = "in-order-completion" 39 allowConcurrentFlag = "allow-concurrent" 40 preferInstantDDL = "prefer-instant-ddl" 41 fastRangeRotationFlag = "fast-range-rotation" 42 vreplicationTestSuite = "vreplication-test-suite" 43 allowForeignKeysFlag = "unsafe-allow-foreign-keys" 44 ) 45 46 // DDLStrategy suggests how an ALTER TABLE should run (e.g. "direct", "online", "gh-ost" or "pt-osc") 47 type DDLStrategy string 48 49 const ( 50 // DDLStrategyDirect means not an online-ddl migration; unmanaged. Just a normal MySQL `ALTER TABLE` 51 DDLStrategyDirect DDLStrategy = "direct" 52 // DDLStrategyVitess requests vreplication to run the migration; new name for DDLStrategyOnline 53 DDLStrategyVitess DDLStrategy = "vitess" 54 // DDLStrategyOnline requests vreplication to run the migration 55 DDLStrategyOnline DDLStrategy = "online" 56 // DDLStrategyGhost requests gh-ost to run the migration 57 DDLStrategyGhost DDLStrategy = "gh-ost" 58 // DDLStrategyPTOSC requests pt-online-schema-change to run the migration 59 DDLStrategyPTOSC DDLStrategy = "pt-osc" 60 // DDLStrategyMySQL is a managed migration (queued and executed by the scheduler) but runs through a MySQL `ALTER TABLE` 61 DDLStrategyMySQL DDLStrategy = "mysql" 62 ) 63 64 // IsDirect returns true if this strategy is a direct strategy 65 // A strategy is direct if it's not explciitly one of the online DDL strategies 66 func (s DDLStrategy) IsDirect() bool { 67 switch s { 68 case DDLStrategyVitess, DDLStrategyOnline, DDLStrategyGhost, DDLStrategyPTOSC, DDLStrategyMySQL: 69 return false 70 } 71 return true 72 } 73 74 // DDLStrategySetting is a formal breakdown of the @@ddl_strategy variable, into strategy and options 75 type DDLStrategySetting struct { 76 Strategy DDLStrategy `json:"strategy,omitempty"` 77 Options string `json:"options,omitempty"` 78 } 79 80 // NewDDLStrategySetting instantiates a new setting 81 func NewDDLStrategySetting(strategy DDLStrategy, options string) *DDLStrategySetting { 82 return &DDLStrategySetting{ 83 Strategy: strategy, 84 Options: options, 85 } 86 } 87 88 // ParseDDLStrategy parses and validates the value of @@ddl_strategy or -ddl_strategy variables 89 func ParseDDLStrategy(strategyVariable string) (*DDLStrategySetting, error) { 90 setting := &DDLStrategySetting{} 91 strategyName := strategyVariable 92 if submatch := strategyParserRegexp.FindStringSubmatch(strategyVariable); len(submatch) > 0 { 93 strategyName = submatch[1] 94 setting.Options = submatch[2] 95 } 96 97 switch strategy := DDLStrategy(strategyName); strategy { 98 case "": // backward compatiblity and to handle unspecified values 99 setting.Strategy = DDLStrategyDirect 100 case DDLStrategyVitess, DDLStrategyOnline, DDLStrategyGhost, DDLStrategyPTOSC, DDLStrategyMySQL, DDLStrategyDirect: 101 setting.Strategy = strategy 102 default: 103 return nil, fmt.Errorf("Unknown online DDL strategy: '%v'", strategy) 104 } 105 return setting, nil 106 } 107 108 // isFlag return true when the given string is a CLI flag of the given name 109 func isFlag(s string, name string) bool { 110 if s == fmt.Sprintf("-%s", name) { 111 return true 112 } 113 if s == fmt.Sprintf("--%s", name) { 114 return true 115 } 116 return false 117 } 118 119 // hasFlag returns true when Options include named flag 120 func (setting *DDLStrategySetting) hasFlag(name string) bool { 121 opts, _ := shlex.Split(setting.Options) 122 for _, opt := range opts { 123 if isFlag(opt, name) { 124 return true 125 } 126 } 127 return false 128 } 129 130 // IsDeclarative checks if strategy options include --declarative 131 func (setting *DDLStrategySetting) IsDeclarative() bool { 132 return setting.hasFlag(declarativeFlag) 133 } 134 135 // IsSingleton checks if strategy options include --singleton 136 func (setting *DDLStrategySetting) IsSingleton() bool { 137 return setting.hasFlag(singletonFlag) 138 } 139 140 // IsSingletonContext checks if strategy options include --singleton-context 141 func (setting *DDLStrategySetting) IsSingletonContext() bool { 142 return setting.hasFlag(singletonContextFlag) 143 } 144 145 // IsAllowZeroInDateFlag checks if strategy options include --allow-zero-in-date 146 func (setting *DDLStrategySetting) IsAllowZeroInDateFlag() bool { 147 return setting.hasFlag(allowZeroInDateFlag) 148 } 149 150 // IsPostponeLaunch checks if strategy options include --postpone-launch 151 func (setting *DDLStrategySetting) IsPostponeLaunch() bool { 152 return setting.hasFlag(postponeLaunchFlag) 153 } 154 155 // IsPostponeCompletion checks if strategy options include --postpone-completion 156 func (setting *DDLStrategySetting) IsPostponeCompletion() bool { 157 return setting.hasFlag(postponeCompletionFlag) 158 } 159 160 // IsInOrderCompletion checks if strategy options include --in-order-completion 161 func (setting *DDLStrategySetting) IsInOrderCompletion() bool { 162 return setting.hasFlag(inOrderCompletionFlag) 163 } 164 165 // IsAllowConcurrent checks if strategy options include --allow-concurrent 166 func (setting *DDLStrategySetting) IsAllowConcurrent() bool { 167 return setting.hasFlag(allowConcurrentFlag) 168 } 169 170 // IsPreferInstantDDL checks if strategy options include --prefer-instant-ddl 171 func (setting *DDLStrategySetting) IsPreferInstantDDL() bool { 172 return setting.hasFlag(preferInstantDDL) 173 } 174 175 // IsFastRangeRotationFlag checks if strategy options include --fast-range-rotation 176 func (setting *DDLStrategySetting) IsFastRangeRotationFlag() bool { 177 return setting.hasFlag(fastRangeRotationFlag) 178 } 179 180 // IsVreplicationTestSuite checks if strategy options include --vreplicatoin-test-suite 181 func (setting *DDLStrategySetting) IsVreplicationTestSuite() bool { 182 return setting.hasFlag(vreplicationTestSuite) 183 } 184 185 // IsAllowForeignKeysFlag checks if strategy options include --unsafe-allow-foreign-keys 186 func (setting *DDLStrategySetting) IsAllowForeignKeysFlag() bool { 187 return setting.hasFlag(allowForeignKeysFlag) 188 } 189 190 // RuntimeOptions returns the options used as runtime flags for given strategy, removing any internal hint options 191 func (setting *DDLStrategySetting) RuntimeOptions() []string { 192 opts, _ := shlex.Split(setting.Options) 193 validOpts := []string{} 194 for _, opt := range opts { 195 switch { 196 case isFlag(opt, declarativeFlag): 197 case isFlag(opt, skipTopoFlag): 198 case isFlag(opt, singletonFlag): 199 case isFlag(opt, singletonContextFlag): 200 case isFlag(opt, allowZeroInDateFlag): 201 case isFlag(opt, postponeLaunchFlag): 202 case isFlag(opt, postponeCompletionFlag): 203 case isFlag(opt, inOrderCompletionFlag): 204 case isFlag(opt, allowConcurrentFlag): 205 case isFlag(opt, preferInstantDDL): 206 case isFlag(opt, fastRangeRotationFlag): 207 case isFlag(opt, vreplicationTestSuite): 208 case isFlag(opt, allowForeignKeysFlag): 209 default: 210 validOpts = append(validOpts, opt) 211 } 212 } 213 return validOpts 214 } 215 216 // ToString returns a simple string representation of this instance 217 func (setting *DDLStrategySetting) ToString() string { 218 return fmt.Sprintf("DDLStrategySetting: strategy=%v, options=%s", setting.Strategy, setting.Options) 219 }