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  }