// prune garbage-collects zookeeper anchor directories that have no descendant files in them func (dir *Dir) prune(dirs map[string]struct{}) error { for cname, _ := range dirs { cdir_, err := dir.OpenDir(cname) if zutil.IsNoNode(err) { delete(dirs, cname) continue } else if err != nil { return err } cdir := cdir_.(*Dir) _, dfiles, err := cdir.Files() if err != nil { return err } if len(dfiles) > 0 { continue } ddirs, dstat, err := cdir.syncDirs() if err != nil { return err } if len(ddirs) > 0 { continue } delete(dirs, cname) if err = dir.fs.zookeeper.Delete(cdir.zdir(), dstat.Version()); err != nil { return err } } return nil }
func (fs *FS) Resolve(id int64) error { fs.Lock() defer fs.Unlock() // Read issue file unresolved := path.Join(fs.root, "unresolved", issuefs.IDString(id)) data, _, err := fs.z.Get(unresolved) if err != nil && zutil.IsNoNode(err) { return err } if err != nil { panic(err) } // Write issue file in resolved if _, err = fs.z.Create(path.Join(fs.root, "resolved", issuefs.IDString(id)), data, 0, zutil.PermitAll); err != nil { panic(err) } // Remove issue file if err = fs.z.Delete(unresolved, -1); err != nil { panic(err) } return nil }
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 } }
func (fs *FS) Unsubscribe(email string) error { fs.Lock() defer fs.Unlock() err := fs.z.Delete(path.Join(fs.root, "listener", email), -1) if err != nil && zutil.IsNoNode(err) { return err } if err != nil { panic(err) } return nil }
// sync updates the files view from Zookeeper, if necessary func (dir *Dir) sync() error { dir.Lock() watch := dir.watch dir.Unlock() if watch == nil { return ErrClosed } children, stat, err := dir.watch.Children() if zutil.IsNoNode(err) { // No represents a present and empty directory. } else if err != nil { return err } dir.update(children, stat) return nil }
// sync updates the files view from Zookeeper, if necessary func (dir *Dir) sync() error { children, stat, err := dir.watch.Children() if zutil.IsNoNode(err) { return dir.clear() } else if err != nil { return err } // If no change since last time, just return dir.Lock() if dir.stat != nil && dir.stat.CVersion() >= stat.CVersion() { dir.Unlock() return nil } dir.Unlock() return dir.fetch(children, stat) }
func (dir *Dir) change(sinceRev int64, expire time.Duration) error { // Check whether the present data is newer than sinceRev dir.Lock() if dir.rev() > sinceRev { dir.Unlock() return nil } stat := dir.stat dir.Unlock() children, stat, err := dir.watch.ChildrenChange(stat, expire) if zutil.IsNoNode(err) { return dir.clear() } else if err != nil { return err } return dir.fetch(children, stat) }
func (dir *Dir) change(expire time.Duration) error { dir.Lock() watch := dir.watch dir.Unlock() if watch == nil { return ErrClosed } dir.Lock() stat := dir.stat dir.Unlock() children, stat, err := dir.watch.ChildrenChange(stat, expire) if zutil.IsNoNode(err) { // No represents a present and empty directory. } else if err != nil { return err } dir.update(children, stat) return nil }