func (ch Chg) applyData(lfs zx.RWTree, rfs zx.Tree) error { nd := ch.D.UsrAttrs() for _, k := range ignoredPutAttrs { delete(nd, k) } datc := rfs.Get(ch.D["path"], 0, zx.All, "") dc := lfs.Put(ch.D["path"], nd, 0, datc, "") <-dc return cerror(dc) }
func (ch Chg) applyAdd(lfs zx.RWTree, rfs zx.Tree, pred string, ec chan<- error) error { var err error gc := rfs.FindGet(ch.D["path"], pred, "", "", 0) for g := range gc { dprintf("get %s\n", g) d := g.Dir if d == nil { break } for _, k := range ignoredPutAttrs { delete(d, k) } if d["err"] != "" { e := errors.New(d["err"]) perr(ec, e) dprintf("%s: %s\n", d["path"], d["err"]) if err == nil { err = e } continue } if g.Datac == nil && d["type"] != "d" { g.Datac = nchan.Null } if d["type"] == "d" { e := <-lfs.Mkdir(d["path"], d) if e != nil { perr(ec, e) if err == nil { err = e } } continue } dc := lfs.Put(d["path"], d, 0, g.Datac, "") <-dc if e := cerror(dc); e != nil { dprintf("%s: put: %s\n", d["path"], e) perr(ec, e) if err == nil { err = e } } } close(gc) if e := cerror(gc); e != nil { dprintf("get: %s\n", e) perr(ec, e) if err == nil { err = e } } return err }
func StatsBench(b *testing.B, fs zx.Tree) { for bi := 0; bi < b.N; bi++ { i := bi%len(StatTests) st := StatTests[i] if st.Fails { continue } dc := fs.Stat(st.Path) d := <-dc if d == nil { b.Fatalf("stat %s: %s", st.Path, cerror(dc)) } } }
// Facade that serves t at the given address by using the ds // to serve and calling Serve for each client. func Server(t zx.Tree, addr string) { dbg.Warn("serve %s at %s...", t.Name(), addr) cc, ec, err := ds.Serve(os.Args[0], addr) if err != nil { dbg.Warn("serve: %s", err) return } go func() { for c := range cc { if c != nil { go serveFor(t, *c) } } if err := cerror(cc); err != nil { dbg.Warn("serve: %s", err) } close(ec, "done") }() }
// returns true if the caller must poll itself rfs for changes func newInvalQ(tag string, dbgf *bool, rfs zx.Tree) (*invalQ, bool) { iq := &invalQ{ Tag: tag, Dbg: dbgf, cchgc: make(chan bool, 1), rfs: rfs, invalsc: make(chan bool, 1), } go iq.postinvalproc() if rfs == nil { return iq, false } // Use /Chg from rfs or poll rfs it if there's no other way. dc := rfs.Get("/Chg", 0, zx.All, "") msg := <-dc if len(msg) == 0 { dbg.Warn("no invalidations: %s", cerror(dc)) return iq, true } go iq.getinvalproc(dc) return iq, false }
func mkfs(addr string) (zx.Tree, func(), error) { if len(addr) == 0 { opts.Usage(os.Stderr) dbg.Fatal("usage") } var fs zx.Tree var st *zx.IOstats var err error if _, err := os.Stat(addr); err == nil { fs, st, err = mklfs(addr) } else { fs, st, err = mkrfs(addr) } if err != nil { return nil, nil, err } fn := func() {} if sflag { fn = func() { st.Averages() dbg.Warn("%s iostats:\n%s\n", fs.Name(), st) } } if mfscfs { dbg.Warn("%s: mfs cache", addr) return mfscache(fs, fn) } if lfsdir != "" { dbg.Warn("%s: lfs cache", addr) return lfscache(fs, fn) } if !nocaching && !delayed { dbg.Warn("%s: old cache", addr) return cache(fs, fn) } dbg.Warn("%s: uncached", addr) return fs, fn, nil }
func chkok(fs zx.Tree, attr string) error { d, err := zx.Stat(fs, "/") if err != nil { return fmt.Errorf("%s: %s", fs.Name(), err) } rwfs, ok := fs.(zx.RWTree) if !ok { return nil } if err := <-rwfs.Wstat("/", zx.Dir{attr: "666"}); err != nil { return err } d, err = zx.Stat(fs, "/") if err != nil { return fmt.Errorf("%s: %s", fs.Name(), err) } if d[attr] != "666" { return fmt.Errorf("%s: does not preserve %s", fs.Name(), attr) } if err := <-rwfs.Wstat("/", zx.Dir{attr: ""}); err != nil { return err } return nil }
// Create a new cfs given a local tree used as a cache of a remote one. // Operations are performed on behalf of each file owner. // The lfs tree must have permission checking disabled // (cfs will want to update everything in it no matter the user who makes the requests) func New(tag string, lfs zx.RWTree, rfs zx.Tree, rdonly bool) (*Cfs, error) { if lfs == nil || rfs == nil { return nil, errors.New("no lfs or rfs") } rwrfs, ok := rfs.(zx.RWTree) if !ok && !rdonly { rdonly = true rwrfs = zx.ROTreeFor(rfs) dbg.Warn("remote %T not rw: rdonly set", rfs) } if !rdonly { if err := chkok(lfs, "Rtime"); err != nil { return nil, err } } if tag == "" { tag = "cfs!" + rfs.Name() } fs := &Cfs { Tag: tag, lfs: lfs, cfs: lfs, // but will keep its ai as nil to wstat uids rfs: rwrfs, rdonly: rdonly, noinvalproto: NoInvalProto, Flags: &zx.Flags{Dbg: Debug}, cUsers: &cUsers { who: make(map[string]time.Time), }, cache: cache.New(), closedc: make(chan bool), polldonec: make(chan bool), } if DebugLocks { fs.lktrz = &lockTrzs{} } fs.cache.Tag = tag fs.cache.Dbg = &fs.Flags.Dbg fs.tpath = fmt.Sprintf("cfs%p", fs) if fs.noinvalproto { fs.invalQ, _ = newInvalQ(tag, &fs.Flags.Dbg, nil) close(fs.polldonec) } else { var mustpoll bool fs.invalQ, mustpoll = newInvalQ(tag, &fs.Flags.Dbg, fs.rfs) if mustpoll { dbg.Warn("%s: polling %s for external changes", tag, fs.rfs) // runs with no ai go fs.pollproc() } else { close(fs.polldonec) } } go fs.invalproc() fs.Flags.Add("verbsync", &fs.cache.Verb) fs.Flags.Add("debug", &fs.Flags.Dbg) if d, ok := lfs.(zx.Debugger); ok { fs.Flags.Add("ldebug", d.Debug()) } if d, ok := rfs.(zx.Debugger); ok { fs.Flags.Add("rdebug", d.Debug()) } fs.Flags.AddRO("rdonly", &fs.rdonly) fs.Flags.AddRO("noperm", &fs.NoPermCheck) fs.Flags.Add("clear", func(...string)error{ fs.IOstats.Clear() return nil }) return fs, nil }
func dump(dir string, t zx.Tree, ec chan bool) { defer func() { ec <- true }() name := t.Name() data := zx.Path(dir, "data") doskip := Skip for { if doskip { waitDumpTime(name) doskip = false continue } dbg.Warn("snap %s...", name) if err := os.MkdirAll(data, 0750); err != nil { dbg.Warn("%s: %s", data, err) return } rd, err := zx.Stat(t, "/") if err != nil { dbg.Warn("%s: %s", name, err) continue } // make sure it's not empty ds, err := zx.GetDir(t, "/") if err != nil { dbg.Warn("%s: %s", name, err) continue } if len(ds) == 0 { dbg.Warn("%s: file system is empty. ignored.", name) continue } s, err := dumpDir(data, name, zx.File{t, rd}) if err != nil { dbg.Warn("%s: %s", name, err) } ts := time.Now().Format("2006/0102") tree := strings.Replace(name, "/", ".", -1) tspath0 := zx.Path(dir, tree, ts) os.MkdirAll(path.Dir(tspath0), 0755) spath := zx.Path(data, s) tspath := tspath0 for i := 1; ; i++ { fi, _ := os.Stat(tspath) if fi == nil { break } tspath = fmt.Sprintf("%s.%d", tspath0, i) } os.MkdirAll(path.Dir(tspath), 0755) if err := os.Symlink(spath, tspath); err != nil { dbg.Warn("%s: %s", name, err) } dbg.Warn("snap %s %s", tspath, s) if Once { break } waitDumpTime(name) } }