Example #1
0
func (c *Connection) CreateEphemeral(path string, node client.Node) (string, error) {
	if c.conn == nil {
		return "", client.ErrConnectionClosed
	}

	p := join(c.basePath, path)

	bytes, err := json.Marshal(node)
	if err != nil {
		return "", client.ErrSerialization
	}

	path, err = c.conn.CreateProtectedEphemeralSequential(p, bytes, zklib.WorldACL(zklib.PermAll))
	if err == zklib.ErrNoNode {
		// Create parent node.
		parts := strings.Split(p, "/")
		pth := ""
		if len(parts) > 1 {
			for _, p := range parts[1 : len(parts)-1] {
				pth += "/" + p
				_, err = c.conn.Create(pth, []byte{}, 0, zklib.WorldACL(zklib.PermAll))
				if err != nil && err != zklib.ErrNodeExists {
					return "", xlateError(err)
				}
			}
			path, err = c.conn.CreateProtectedEphemeralSequential(p, bytes, zklib.WorldACL(zklib.PermAll))
		}
	}
	if err == nil {
		node.SetVersion(&zklib.Stat{})
	}
	return path, xlateError(err)
}
Example #2
0
// Create places data at the node at the given path.
func (c *Connection) Create(path string, node client.Node) error {
	if c.conn == nil {
		return client.ErrConnectionClosed
	}

	p := join(c.basePath, path)

	bytes, err := json.Marshal(node)
	if err != nil {
		return client.ErrSerialization
	}

	_, err = c.conn.Create(p, bytes, 0, zklib.WorldACL(zklib.PermAll))
	if err == zklib.ErrNoNode {
		// Create parent node.
		parts := strings.Split(p, "/")
		pth := ""
		for _, p := range parts[1:] {
			pth += "/" + p
			_, err = c.conn.Create(pth, []byte{}, 0, zklib.WorldACL(zklib.PermAll))
			if err != nil && err != zklib.ErrNodeExists {
				return xlateError(err)
			}
		}
	}
	if err == nil {
		node.SetVersion(&zklib.Stat{})
	}
	return xlateError(err)
}
Example #3
0
// TakeLead attempts to aquire the leader role. When aquired it return a
// channel on the leader node so the caller can react to changes in zookeeper
func (l *Leader) TakeLead() (echan <-chan client.Event, err error) {
	if l.lockPath != "" {
		return nil, ErrDeadlock
	}

	prefix := l.prefix()

	data, err := json.Marshal(l.node)
	if err != nil {
		return nil, xlateError(err)
	}

	path := ""
	for i := 0; i < 3; i++ {
		if l.c.conn == nil {
			// TODO: race condition exists
			return nil, fmt.Errorf("connection lost")
		}
		path, err = l.c.conn.CreateProtectedEphemeralSequential(prefix, data, zklib.WorldACL(zklib.PermAll))

		if err == zklib.ErrNoNode {
			// Create parent node.
			parts := strings.Split(l.path, "/")
			pth := ""
			for _, p := range parts[1:] {
				pth += "/" + p
				if l.c.conn == nil {
					// TODO: race condition exists
					return nil, fmt.Errorf("connection lost")
				}
				_, err := l.c.conn.Create(pth, []byte{}, 0, zklib.WorldACL(zklib.PermAll))
				if err != nil && err != zklib.ErrNodeExists {
					return nil, xlateError(err)
				}
			}
		} else if err == nil {
			break
		} else {
			return nil, xlateError(err)
		}
	}
	if err != nil {
		return nil, xlateError(err)
	}
	seq, err := parseSeq(path)
	if err != nil {
		return nil, xlateError(err)
	}

	// This implements the leader election recipe recommeded by ZooKeeper
	// https://zookeeper.apache.org/doc/trunk/recipes.html#sc_leaderElection
	for {
		children, _, err := l.c.conn.Children(l.path)
		if err != nil {
			return nil, xlateError(err)
		}

		lowestSeq := seq
		var prevSeq uint64
		prevSeqPath := ""
		// find the lowest sequenced node
		for _, p := range children {
			s, err := parseSeq(p)
			if err != nil {
				return nil, xlateError(err)
			}
			if s < lowestSeq {
				lowestSeq = s
			}
			if s < seq && s > prevSeq {
				prevSeq = s
				prevSeqPath = p
			}
		}

		if seq == lowestSeq {
			// Acquired the lock
			break
		}

		// Wait on the node next in line for the lock
		_, _, ch, err := l.c.conn.GetW(l.path + "/" + prevSeqPath)
		if err != nil && err != zklib.ErrNoNode {
			return nil, xlateError(err)
		} else if err != nil && err == zklib.ErrNoNode {
			// try again
			continue
		}

		ev := <-ch
		if ev.Err != nil {
			return nil, xlateError(ev.Err)
		}
	}

	glog.Infof("w %s", path)
	_, _, event, err := l.c.conn.GetW(path)
	glog.Infof("calling wait on %s: %s", path, err)
	if err == nil {
		l.seq = seq
		l.lockPath = path
	} else {
		l.c.Delete(path)
	}
	return toClientEvent(event), xlateError(err)
}
Example #4
0
// NewLock returns a managed lock object at the given path bound to the current
// connection.
func (c *Connection) NewLock(path string) client.Lock {
	return &Lock{
		lock: zklib.NewLock(c.conn, join(c.basePath, path), zklib.WorldACL(zklib.PermAll)),
	}
}