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) }
// 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) }
// 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) }
// 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)), } }