コード例 #1
0
ファイル: snapshot.go プロジェクト: soundcloud/doozer-journal
func runSnapshot(cmd *Command) error {
	f, err := os.OpenFile(
		cmd.Globals.File,
		os.O_CREATE|os.O_EXCL|os.O_WRONLY|os.O_TRUNC,
		0666,
	)
	if err != nil {
		if os.IsExist(err) {
			return fmt.Errorf("Journal already exists at %s", cmd.Globals.File)
		}
		return fmt.Errorf("Unable to open journal: %s", err)
	}

	j := journal.New(f)
	err = journal.Snapshot(cmd.Conn, cmd.Rev, cmd.Globals.Root, j)
	if err != nil {
		return err
	}

	err = f.Sync()
	if err != nil {
		return fmt.Errorf("file sync failed: %s", err)
	}

	return nil
}
コード例 #2
0
ファイル: journal.go プロジェクト: soundcloud/doozer-journal
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
		}
	}
}
コード例 #3
0
ファイル: compress.go プロジェクト: soundcloud/doozer-journal
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
}