func wait( conn *doozer.Conn, rev int64, root string, entryc chan *journal.Entry, errc chan error, ) { for { ev, err := conn.Wait(path.Join(root, "**"), rev+1) if err != nil { errc <- fmt.Errorf("error waiting for event: %s", err) return } rev = ev.Rev var entry *journal.Entry if ev.IsSet() { entry = journal.NewEntry(ev.Rev, journal.OpSet, ev.Path, ev.Body) } else if ev.IsDel() { entry = journal.NewEntry(ev.Rev, journal.OpDel, ev.Path, []byte{}) } else { continue } entryc <- entry } }
func walk( conn *doozer.Conn, rev int64, entryc chan *journal.Entry, ) doozer.WalkFunc { return func(p string, info *doozer.FileInfo, err error) error { if err != nil { return fmt.Errorf("error walking tree: %s", err) } if !info.IsDir { val, _, err := conn.Get(p, &rev) if err != nil { return fmt.Errorf("error getting value for '%s': %s", p, err) } entryc <- journal.NewEntry(-1, journal.OpSet, p, val) } return nil } }
func runJournal(cmd *Command) error { sighupc := make(chan os.Signal, 1) signal.Notify(sighupc, syscall.SIGHUP) f, err := newJournalFile(cmd.Globals.File) if err != nil { return err } defer f.Close() j := journal.New(f) err = journal.Snapshot(cmd.Conn, cmd.Rev, cmd.Globals.Root, j) if err != nil { return err } if err := f.Sync(); err != nil { return fmt.Errorf("file sync failed: %s", err) } var ( isUnsynced = false opCounter = 0 rev = cmd.Rev syncInterval = 10 * time.Second syncOps = 100 watchroot = path.Join(cmd.Globals.Root, "**") errc = make(chan error) eventc = make(chan doozer.Event) ticker = time.Tick(syncInterval) ) go func(errc chan error, eventc chan doozer.Event, rev int64) { for { ev, err := cmd.Conn.Wait(watchroot, rev+1) if err != nil { errc <- fmt.Errorf("conn wait failed: %s", err) return } // Advance in time! rev = ev.Rev eventc <- ev } }(errc, eventc, rev) for { select { case ev := <-eventc: var entry *journal.Entry if ev.IsSet() { entry = journal.NewEntry(ev.Rev, journal.OpSet, ev.Path, ev.Body) } else if ev.IsDel() { entry = journal.NewEntry(ev.Rev, journal.OpDel, ev.Path, []byte{}) } else { continue } err = j.Append(entry) if err != nil { return err } opCounter++ // Log entry b, err := journal.Marshal(entry) if err != nil { return fmt.Errorf("entry marshal failed: %s", err) } if !strings.HasPrefix(ev.Path, journal.InternalPrefix) { fmt.Fprintf(os.Stdout, "%s\n", string(b)) } case <-sighupc: if err := f.reopen(); err != nil { return err } case err := <-errc: return err case <-ticker: isUnsynced = true } if opCounter >= syncOps || isUnsynced { if err := f.Sync(); err != nil { return fmt.Errorf("file sync failed: %s", err) } isUnsynced = false opCounter = 0 } } }
func runCompress(cmd *Command) error { if len(cmd.Args) != 1 { cmd.Usage() } tree := map[string]*journal.Entry{} uncompressed, err := os.Open(cmd.Globals.File) if err != nil { return fmt.Errorf("file open failed: %s", err) } defer uncompressed.Close() u := journal.NewReader(uncompressed) for { entry, err := u.ReadEntry() if err == io.EOF { break } if err != nil { return err } switch entry.Op { case journal.OpSet: tree[entry.Path] = entry case journal.OpDel: delete(tree, entry.Path) default: return fmt.Errorf("unknown operation %s", entry.Op) } } compressed, err := os.Create(cmd.Args[0]) if err != nil { return fmt.Errorf("file create failed: %s", err) } defer compressed.Close() var ( c = journal.New(compressed) rev int64 ) for _, entry := range tree { err := c.Append(journal.NewEntry(rev, journal.OpSet, entry.Path, entry.Value)) if err != nil { return fmt.Errorf("append failed: %s", err) } rev++ } err = compressed.Sync() if err != nil { return fmt.Errorf("file sync failed: %s", err) } return nil }