// ChildrenChange blocks until the children of the watched Zookeeper node change // relative to the returned values of the last invokation of Children or ChildrenChange. // It returns the new children and stat values. func (w *Watch) ChildrenChange(sinceStat *zookeeper.Stat, expire time.Duration) (children []string, stat *zookeeper.Stat, err error) { // Still alive? w.lk.Lock() z, cwatch := w.zookeeper, w.cwatch w.lk.Unlock() if z == nil { return nil, nil, ErrClosed } // Wait if watch present, otherwise read from Zookeeper if cwatch != nil { // If we already have a newer revision, return it w.lk.Lock() if sinceStat == nil || w.cstat.CVersion() > sinceStat.CVersion() { defer w.lk.Unlock() return w.children, w.cstat, nil } w.lk.Unlock() if expire == 0 { <-cwatch } else { select { case <-cwatch: case <-time.After(expire): return nil, nil, ErrExpire } } } return w.fetchChildren() }
func (dir *Dir) update(children []string, stat *zookeeper.Stat) { // If no change since last time, just return dir.Lock() defer dir.Unlock() if dir.stat != nil && dir.stat.CVersion() >= stat.CVersion() { return } dir.stat = stat dir.children = make(map[string]durablefs.Info) for _, c := range children { nodepath := path.Join(dir.zroot, dir.dpath, c) // Get node data data, dstat, err := dir.conn.Get(nodepath) if zutil.IsNoNode(err) { continue } else if err != nil { println("problem fetching durable node data", nodepath, err.Error()) continue } // Get node children chld, cstat, err := dir.conn.Children(nodepath) if zutil.IsNoNode(err) { continue } else if err != nil { println("problem fetching durable node children", nodepath, err.Error()) continue } // TODO: To implement efficient recursive garbage collection, we'd need to keep a global in-memory // directories structure, as in for the anchor file system info := durablefs.Info{ Name: c, HasBody: len(data) > 0, HasChildren: len(chld) > 0, } if cstat.Version() != dstat.Version() { println("durable file", nodepath, "changed during pruning; leaving alone") } else if !info.HasBody && !info.HasChildren { if err = dir.conn.Delete(nodepath, dstat.Version()); err != nil && !zutil.IsNoNode(err) { // panic(err) } continue } dir.children[c] = info } }