Commit 6103fd3e authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent eab0c6e3
......@@ -37,6 +37,9 @@ import (
// Dumper is interface to implement various dumping modes
type Dumper interface {
// DumperName defines concise name to use in error-reporting when using this dumper.
DumperName() string
// DumpFileHeader dumps fh to buf
DumpFileHeader(buf *xfmt.Buffer, fh *fs1.FileHeader) error
......@@ -54,7 +57,7 @@ type Dumper interface {
// To do so it reads file header and then iterates over all transactions in the file.
// The logic to actually output information and if needed read/process data is implemented by Dumper d.
func Dump(w io.Writer, path string, dir fs1.IterDir, d Dumper) (err error) {
defer xerr.Contextf(&err, "%s: dump", path) // XXX ok? XXX name ?
defer xerr.Contextf(&err, "%s: %s", path, d.DumperName()) // XXX ok?
it, f, err := fs1.IterateFile(path, dir)
if err != nil {
......@@ -128,6 +131,10 @@ type DumperFsDump struct {
ntxn int // current transaction record #
}
func (d *DumperFsDump) DumperName() string {
return "fsdump"
}
func (d *DumperFsDump) DumpFileHeader(buf *xfmt.Buffer, fh *fs1.FileHeader) error {
return nil
}
......@@ -184,7 +191,6 @@ func (d *DumperFsDump) DumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error {
return nil
}
// DumperFsDumpVerbose implements a very verbose dumper with output identical
// to fsdump.Dumper in zodb/py originally written by Jeremy Hylton:
//
......@@ -193,6 +199,10 @@ func (d *DumperFsDump) DumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error {
type DumperFsDumpVerbose struct {
}
func (d *DumperFsDumpVerbose) DumperName() string {
return "fsdumpv"
}
func (d *DumperFsDumpVerbose) DumpFileHeader(buf *xfmt.Buffer, fh *fs1.FileHeader) error {
for i := 0; i < 60; i++ {
buf .S("*")
......@@ -254,6 +264,49 @@ func (d *DumperFsDumpVerbose) dumpData(buf *xfmt.Buffer, it *fs1.Iter) error {
return nil
}
const dumpSummary = "dump database transactions"
func dumpUsage(w io.Writer) {
fmt.Fprintf(w,
`Usage: fs1 dump [options] <storage>
Dump transactions from a FileStorage
<storage> is a path to FileStorage
options:
-h --help this help text.
-v verbose mode.
`)
}
func dumpMain(argv []string) {
var verbose bool
flags := flag.FlagSet{Usage: func() { tailUsage(os.Stderr) }}
flags.Init("", flag.ExitOnError)
flags.BoolVar(&verbose, "v", verbose, "verbose mode")
flags.Parse(argv[1:])
argv = flags.Args()
if len(argv) < 1 {
flags.Usage()
os.Exit(2)
}
storPath := argv[0]
var d Dumper
if verbose {
d = &DumperFsDumpVerbose{}
} else {
d = &DumperFsDump{}
}
err := Dump(os.Stdout, storPath, fs1.IterForward, d)
if err != nil {
log.Fatal(err)
}
}
// ----------------------------------------
// DumperFsTail implements dumping with the same format as in fstail/py
......@@ -266,6 +319,10 @@ type DumperFsTail struct {
data []byte // buffer for reading txn data
}
func (d *DumperFsTail) DumperName() string {
return "fstail"
}
func (d *DumperFsTail) DumpFileHeader(buf *xfmt.Buffer, fh *fs1.FileHeader) error {
return nil
}
......
......@@ -23,8 +23,8 @@ package fs1tools
import "lab.nexedi.com/kirr/neo/go/zodb/zodbtools"
var commands = zodbtools.CommandRegistry{
{"dump", dumpSummary, dumpUsage, dumpMain},
{"tail", tailSummary, tailUsage, tailMain},
// dump, dump+verbose (fsdump.py)
// + fsstats? (fsstats.py)
{"reindex", reindexSummary, reindexUsage, reindexMain},
......
......@@ -49,24 +49,24 @@ func diff(a, b string) string {
return dmp.DiffPrettyText(diffv)
}
func testDump(t *testing.T, name string, dir fs1.IterDir, d Dumper) {
func testDump(t *testing.T, dir fs1.IterDir, d Dumper) {
buf := bytes.Buffer{}
err := Dump(&buf, "../testdata/1.fs", dir, d)
if err != nil {
t.Fatalf("%s: %v", name, err)
t.Fatalf("%s: %v", d.DumperName(), err)
}
dumpOk := loadFile(t, fmt.Sprintf("testdata/1.%s.ok", name))
dumpOk := loadFile(t, fmt.Sprintf("testdata/1.%s.ok", d.DumperName()))
if dumpOk != buf.String() {
t.Errorf("%s: dump different:\n%v", name, diff(dumpOk, buf.String()))
t.Errorf("%s: dump different:\n%v", d.DumperName(), diff(dumpOk, buf.String()))
}
}
func TestFsDump(t *testing.T) { testDump(t, "fsdump", fs1.IterForward, &DumperFsDump{}) }
func TestFsDumpv(t *testing.T) { testDump(t, "fsdumpv", fs1.IterForward, &DumperFsDumpVerbose{}) }
func TestFsTail(t *testing.T) { testDump(t, "fstail", fs1.IterBackward, &DumperFsTail{Ntxn: 1000000}) }
func TestFsDump(t *testing.T) { testDump(t, fs1.IterForward, &DumperFsDump{}) }
func TestFsDumpv(t *testing.T) { testDump(t, fs1.IterForward, &DumperFsDumpVerbose{}) }
func TestFsTail(t *testing.T) { testDump(t, fs1.IterBackward, &DumperFsTail{Ntxn: 1000000}) }
func BenchmarkTail(b *testing.B) {
// FIXME small testdata/1.fs is not representative for benchmarking
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment