Пример #1
0
// 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
}
Пример #2
0
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)
}
Пример #3
0
// 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
}
Пример #4
0
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)
}
Пример #5
0
// 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
}