// lockForAction creates the action node in zookeeper, waits for the // queue lock, displays a nice error message if it cant get it func (zkts *Server) lockForAction(actionDir, contents string, timeout time.Duration, interrupted chan struct{}) (string, error) { // create the action path actionPath, err := zkts.zconn.Create(actionDir, contents, zookeeper.SEQUENCE, zookeeper.WorldACL(zookeeper.PERM_ALL)) if err != nil { return "", err } err = zk.ObtainQueueLock(zkts.zconn, actionPath, timeout, interrupted) if err != nil { var errToReturn error switch err { case zk.ErrInterrupted: errToReturn = topo.ErrInterrupted case zk.ErrTimeout: errToReturn = topo.ErrTimeout default: errToReturn = fmt.Errorf("failed to obtain action lock: %v %v", actionPath, err) } // Regardless of the reason, try to cleanup. log.Warningf("Failed to obtain action lock: %v", err) zkts.zconn.Delete(actionPath, -1) // Show the other actions in the directory dir := path.Dir(actionPath) children, _, err := zkts.zconn.Children(dir) if err != nil { log.Warningf("Failed to get children of %v: %v", dir, err) return "", errToReturn } if len(children) == 0 { log.Warningf("No other action running, you may just try again now.") return "", errToReturn } childPath := path.Join(dir, children[0]) data, _, err := zkts.zconn.Get(childPath) if err != nil { log.Warningf("Failed to get first action node %v (may have just ended): %v", childPath, err) return "", errToReturn } log.Warningf("------ Most likely blocking action: %v\n%v", childPath, data) return "", errToReturn } return actionPath, nil }
func cmdQlock(subFlags *flag.FlagSet, args []string) { var ( lockWaitTimeout = subFlags.Duration("lock-wait-timeout", 0, "wait for a lock for the specified duration") ) subFlags.Parse(args) zkPath := fixZkPath(subFlags.Arg(0)) sigRecv := make(chan os.Signal, 1) interrupted := make(chan struct{}) signal.Notify(sigRecv, os.Interrupt) go func() { <-sigRecv close(interrupted) }() if err := zk.ObtainQueueLock(zconn, zkPath, *lockWaitTimeout, interrupted); err != nil { log.Fatalf("qlock: error %v: %v", zkPath, err) } fmt.Printf("qlock: locked %v\n", zkPath) }
// WaitForMastership is part of the topo.MasterParticipation interface. func (mp *zkMasterParticipation) WaitForMastership() (context.Context, error) { electionPath := path.Join(GlobalElectionPath, mp.name) // fast path if Stop was already called select { case <-mp.stop: close(mp.done) return nil, topo.ErrInterrupted default: } // create the current proposal proposal, err := mp.zkts.zconn.Create(electionPath+"/", mp.id, zookeeper.FlagSequence|zookeeper.FlagEphemeral, zookeeper.WorldACL(zk.PermFile)) if err != nil { return nil, fmt.Errorf("cannot create proposal file in %v: %v", electionPath, err) } // Wait until we are it, or we are interrupted. Using a // small-ish time out so it gets exercised faster (as opposed // to crashing after a day of use). for { err = zk.ObtainQueueLock(mp.zkts.zconn, proposal, 5*time.Minute, mp.stop) if err == nil { // we got the lock, move on break } if err == zk.ErrInterrupted { // mp.stop is closed, we should return close(mp.done) return nil, topo.ErrInterrupted } if err == zk.ErrTimeout { // we try again continue } // something else went wrong return nil, err } // we got the lock, create our background context ctx, cancel := context.WithCancel(context.Background()) go mp.watchMastership(proposal, cancel) return ctx, nil }
func cmdQlock(args []string) { zkPath := fixZkPath(args[0]) timeout, err := time.ParseDuration(*lockWaitTimeout) if err != nil { log.Fatalf("qlock: invalid timeout %v: %v", *lockWaitTimeout, err) } sigRecv := make(chan os.Signal, 1) interrupted := make(chan struct{}) signal.Notify(sigRecv, os.Interrupt) go func() { <-sigRecv close(interrupted) }() err = zk.ObtainQueueLock(zconn, zkPath, timeout, interrupted) if err != nil { log.Fatalf("qlock: error %v: %v", zkPath, err) } fmt.Printf("qlock: locked %v\n", zkPath) }
// lockForAction creates the action node in zookeeper, waits for the // queue lock, displays a nice error message if it cant get it func (zkts *Server) lockForAction(ctx context.Context, actionDir, contents string) (string, error) { // create the action path actionPath, err := zkts.zconn.Create(actionDir, contents, zookeeper.FlagSequence|zookeeper.FlagEphemeral, zookeeper.WorldACL(zk.PermFile)) if err != nil { return "", convertError(err) } // get the timeout from the context var timeout time.Duration deadline, ok := ctx.Deadline() if !ok { // enforce a default timeout timeout = 30 * time.Second } else { timeout = deadline.Sub(time.Now()) } // get the interrupted channel from context or don't interrupt interrupted := ctx.Done() if interrupted == nil { interrupted = make(chan struct{}) } err = zk.ObtainQueueLock(zkts.zconn, actionPath, timeout, interrupted) if err != nil { var errToReturn error switch err { case zk.ErrTimeout: errToReturn = topo.ErrTimeout case zk.ErrInterrupted: // the context failed, get the error from it if ctx.Err() == context.DeadlineExceeded { errToReturn = topo.ErrTimeout } else { errToReturn = topo.ErrInterrupted } default: errToReturn = fmt.Errorf("failed to obtain action lock: %v %v", actionPath, err) } // Regardless of the reason, try to cleanup. log.Warningf("Failed to obtain action lock: %v", err) zkts.zconn.Delete(actionPath, -1) // Show the other actions in the directory dir := path.Dir(actionPath) children, _, err := zkts.zconn.Children(dir) if err != nil { log.Warningf("Failed to get children of %v: %v", dir, err) return "", errToReturn } if len(children) == 0 { log.Warningf("No other action running, you may just try again now.") return "", errToReturn } childPath := path.Join(dir, children[0]) data, _, err := zkts.zconn.Get(childPath) if err != nil { log.Warningf("Failed to get first action node %v (may have just ended): %v", childPath, err) return "", errToReturn } log.Warningf("------ Most likely blocking action: %v\n%v", childPath, data) return "", errToReturn } return actionPath, nil }