vitess.io/vitess@v0.16.2/go/vt/topo/zk2topo/utils.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 zk2topo 18 19 import ( 20 "fmt" 21 "path" 22 "sort" 23 "strings" 24 "sync" 25 26 "context" 27 28 "github.com/z-division/go-zookeeper/zk" 29 30 "vitess.io/vitess/go/vt/log" 31 "vitess.io/vitess/go/vt/vterrors" 32 33 "vitess.io/vitess/go/fileutil" 34 ) 35 36 // CreateRecursive is a helper function on top of Create. It will 37 // create a path and any pieces required, think mkdir -p. 38 // Intermediate znodes are always created empty. 39 // Pass maxCreationDepth=-1 to create all nodes to the top. 40 func CreateRecursive(ctx context.Context, conn *ZkConn, zkPath string, value []byte, flags int32, aclv []zk.ACL, maxCreationDepth int) (string, error) { 41 pathCreated, err := conn.Create(ctx, zkPath, value, flags, aclv) 42 if err == zk.ErrNoNode { 43 if maxCreationDepth == 0 { 44 return "", zk.ErrNoNode 45 } 46 47 // Make sure that nodes are either "file" or 48 // "directory" to mirror file system semantics. 49 dirAclv := make([]zk.ACL, len(aclv)) 50 for i, acl := range aclv { 51 dirAclv[i] = acl 52 dirAclv[i].Perms = PermDirectory 53 } 54 parentPath := path.Dir(zkPath) 55 _, err = CreateRecursive(ctx, conn, parentPath, nil, 0, dirAclv, maxCreationDepth-1) 56 if err != nil && err != zk.ErrNodeExists { 57 return "", err 58 } 59 pathCreated, err = conn.Create(ctx, zkPath, value, flags, aclv) 60 } 61 return pathCreated, err 62 } 63 64 // ChildrenRecursive returns the relative path of all the children of 65 // the provided node. 66 func ChildrenRecursive(ctx context.Context, zconn *ZkConn, zkPath string) ([]string, error) { 67 var err error 68 mutex := sync.Mutex{} 69 wg := sync.WaitGroup{} 70 pathList := make([]string, 0, 32) 71 children, _, err := zconn.Children(ctx, zkPath) 72 if err != nil { 73 return nil, err 74 } 75 76 for _, child := range children { 77 wg.Add(1) 78 go func(child string) { 79 childPath := path.Join(zkPath, child) 80 rChildren, zkErr := ChildrenRecursive(ctx, zconn, childPath) 81 if zkErr != nil { 82 // If other processes are deleting nodes, we need to ignore 83 // the missing nodes. 84 if zkErr != zk.ErrNoNode { 85 mutex.Lock() 86 err = zkErr 87 mutex.Unlock() 88 } 89 } else { 90 mutex.Lock() 91 pathList = append(pathList, child) 92 for _, rChild := range rChildren { 93 pathList = append(pathList, path.Join(child, rChild)) 94 } 95 mutex.Unlock() 96 } 97 wg.Done() 98 }(child) 99 } 100 101 wg.Wait() 102 103 mutex.Lock() 104 defer mutex.Unlock() 105 if err != nil { 106 return nil, err 107 } 108 return pathList, nil 109 } 110 111 // ResolveWildcards resolves paths like: 112 // /zk/nyc/vt/tablets/*/action 113 // /zk/global/vt/keyspaces/*/shards/*/action 114 // /zk/*/vt/tablets/*/action 115 // into real existing paths 116 // 117 // If you send paths that don't contain any wildcard and 118 // don't exist, this function will return an empty array. 119 func ResolveWildcards(ctx context.Context, zconn *ZkConn, zkPaths []string) ([]string, error) { 120 results := make([][]string, len(zkPaths)) 121 wg := &sync.WaitGroup{} 122 mu := &sync.Mutex{} 123 var firstError error 124 125 for i, zkPath := range zkPaths { 126 wg.Add(1) 127 parts := strings.Split(zkPath, "/") 128 go func(i int) { 129 defer wg.Done() 130 subResult, err := resolveRecursive(ctx, zconn, parts, true) 131 if err != nil { 132 mu.Lock() 133 if firstError != nil { 134 log.Infof("Multiple error: %v", err) 135 } else { 136 firstError = err 137 } 138 mu.Unlock() 139 } else { 140 results[i] = subResult 141 } 142 }(i) 143 } 144 145 wg.Wait() 146 if firstError != nil { 147 return nil, firstError 148 } 149 150 result := make([]string, 0, 32) 151 for i := 0; i < len(zkPaths); i++ { 152 subResult := results[i] 153 if subResult != nil { 154 result = append(result, subResult...) 155 } 156 } 157 158 return result, nil 159 } 160 161 func resolveRecursive(ctx context.Context, zconn *ZkConn, parts []string, toplevel bool) ([]string, error) { 162 for i, part := range parts { 163 if fileutil.HasWildcard(part) { 164 var children []string 165 var err error 166 zkParentPath := strings.Join(parts[:i], "/") 167 children, _, err = zconn.Children(ctx, zkParentPath) 168 if err != nil { 169 // we asked for something like 170 // /zk/cell/aaa/* and 171 // /zk/cell/aaa doesn't exist 172 // -> return empty list, no error 173 // (note we check both a regular zk 174 // error and the error the test 175 // produces) 176 if err == zk.ErrNoNode { 177 return nil, nil 178 } 179 // otherwise we return the error 180 return nil, err 181 } 182 sort.Strings(children) 183 184 results := make([][]string, len(children)) 185 wg := &sync.WaitGroup{} 186 mu := &sync.Mutex{} 187 var firstError error 188 189 for j, child := range children { 190 matched, err := path.Match(part, child) 191 if err != nil { 192 return nil, err 193 } 194 if matched { 195 // we have a match! 196 wg.Add(1) 197 newParts := make([]string, len(parts)) 198 copy(newParts, parts) 199 newParts[i] = child 200 go func(j int) { 201 defer wg.Done() 202 subResult, err := resolveRecursive(ctx, zconn, newParts, false) 203 if err != nil { 204 mu.Lock() 205 if firstError != nil { 206 log.Infof("Multiple error: %v", err) 207 } else { 208 firstError = err 209 } 210 mu.Unlock() 211 } else { 212 results[j] = subResult 213 } 214 }(j) 215 } 216 } 217 218 wg.Wait() 219 if firstError != nil { 220 return nil, firstError 221 } 222 223 result := make([]string, 0, 32) 224 for j := 0; j < len(children); j++ { 225 subResult := results[j] 226 if subResult != nil { 227 result = append(result, subResult...) 228 } 229 } 230 231 // we found a part that is a wildcard, we 232 // added the children already, we're done 233 return result, nil 234 } 235 } 236 237 // no part contains a wildcard, add the path if it exists, and done 238 path := strings.Join(parts, "/") 239 if toplevel { 240 // for whatever the user typed at the toplevel, we don't 241 // check it exists or not, we just return it 242 return []string{path}, nil 243 } 244 245 // this is an expanded path, we need to check if it exists 246 exists, _, err := zconn.Exists(ctx, path) 247 if err != nil { 248 return nil, err 249 } 250 if exists { 251 return []string{path}, nil 252 } 253 return nil, nil 254 } 255 256 // DeleteRecursive will delete all children of the given path. 257 func DeleteRecursive(ctx context.Context, zconn *ZkConn, zkPath string, version int32) error { 258 // version: -1 delete any version of the node at path - only applies to the top node 259 err := zconn.Delete(ctx, zkPath, version) 260 if err == nil { 261 return nil 262 } 263 if err != zk.ErrNotEmpty { 264 return err 265 } 266 // Remove the ability for other nodes to get created while we are trying to delete. 267 // Otherwise, you can enter a race condition, or get starved out from deleting. 268 err = zconn.SetACL(ctx, zkPath, zk.WorldACL(zk.PermAdmin|zk.PermDelete|zk.PermRead), version) 269 if err != nil { 270 return err 271 } 272 children, _, err := zconn.Children(ctx, zkPath) 273 if err != nil { 274 return err 275 } 276 for _, child := range children { 277 err := DeleteRecursive(ctx, zconn, path.Join(zkPath, child), -1) 278 if err != nil && err != zk.ErrNoNode { 279 return vterrors.Wrapf(err, "DeleteRecursive: recursive delete failed") 280 } 281 } 282 283 err = zconn.Delete(ctx, zkPath, version) 284 if err != nil && err != zk.ErrNotEmpty { 285 err = fmt.Errorf("DeleteRecursive: nodes getting recreated underneath delete (app race condition): %v", zkPath) 286 } 287 return err 288 } 289 290 // obtainQueueLock waits until we hold the lock in the provided path. 291 // The lexically lowest node is the lock holder - verify that this 292 // path holds the lock. Call this queue-lock because the semantics are 293 // a hybrid. Normal Zookeeper locks make assumptions about sequential 294 // numbering that don't hold when the data in a lock is modified. 295 func obtainQueueLock(ctx context.Context, conn *ZkConn, zkPath string) error { 296 queueNode := path.Dir(zkPath) 297 lockNode := path.Base(zkPath) 298 299 for { 300 // Get our siblings. 301 children, _, err := conn.Children(ctx, queueNode) 302 if err != nil { 303 return vterrors.Wrap(err, "obtainQueueLock: trylock failed %v") 304 } 305 sort.Strings(children) 306 if len(children) == 0 { 307 return fmt.Errorf("obtainQueueLock: empty queue node: %v", queueNode) 308 } 309 310 // If we are the first node, we got the lock. 311 if children[0] == lockNode { 312 return nil 313 } 314 315 // If not, find the previous node. 316 prevLock := "" 317 for i := 1; i < len(children); i++ { 318 if children[i] == lockNode { 319 prevLock = children[i-1] 320 break 321 } 322 } 323 if prevLock == "" { 324 return fmt.Errorf("obtainQueueLock: no previous queue node found: %v", zkPath) 325 } 326 327 // Set a watch on the previous node. 328 zkPrevLock := path.Join(queueNode, prevLock) 329 exists, _, watch, err := conn.ExistsW(ctx, zkPrevLock) 330 if err != nil { 331 return vterrors.Wrapf(err, "obtainQueueLock: unable to watch queued node %v", zkPrevLock) 332 } 333 if !exists { 334 // The lock disappeared, try to read again. 335 continue 336 } 337 select { 338 case <-ctx.Done(): 339 return ctx.Err() 340 case <-watch: 341 // Something happened to the previous lock. 342 // It doesn't matter what, read again. 343 } 344 } 345 }