Commit 23dd78a4 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 72099b1a
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package fs1tools
import (
// "crypto/sha1"
// "flag"
// "fmt"
// "io"
// "log"
// "os"
// "lab.nexedi.com/kirr/go123/xbytes"
// "lab.nexedi.com/kirr/go123/xerr"
// "lab.nexedi.com/kirr/go123/xfmt"
)
/*
Tail dumps the last few transactions from a FileStorage.
Format is the same as in fstail/py originally written by Jeremy Hylton:
https://github.com/zopefoundation/ZODB/blob/master/src/ZODB/scripts/fstail.py
https://github.com/zopefoundation/ZODB/commit/551122cc
*/
/*
func Tail(w io.Writer, path string, ntxn int) (err error) {
// path & fstail on error context
defer xerr.Contextf(&err, "%s: fstail", path)
// we are not using fs1.Open here, since the file or index could be
// e.g. corrupt - we want to iterate directly by FileStorage records
// (same logic as in fstail/py)
f, err := os.Open(path)
if err != nil {
return err
}
defer func() {
err2 := f.Close()
err = xerr.First(err, err2)
}()
// get file size as topPos
fi, err := f.Stat()
if err != nil {
return err
}
topPos := fi.Size()
// txn header & data buffer for iterating
txnh := fs1.TxnHeader{}
data := []byte{}
// use sequential IO buffer
fSeq := xbufio.NewSeqReaderAt(f)
// XXX -> LoadPrev starting @ NextPrevStartMagic ?
// start iterating at tail.
// this should get EOF but read txnh.LenPrev ok.
err = txnh.Load(fSeq, topPos, fs1.LoadAll)
if err != io.EOF {
if err == nil {
// XXX or allow this?
// though then, if we start not from a txn boundary - there are
// high chances further iteration will go wrong.
err = fmt.Errorf("@%v: reading past file end was unexpectedly successful: probably the file is being modified simultaneously", topPos)
}
// otherwise err already has the context
return err
}
if txnh.LenPrev <= 0 {
return fmt.Errorf("@%v: previous record could not be read", topPos)
}
// buffer for formatting
buf := xfmt.Buffer{}
// now loop loading transactions backwards until EOF / ntxn limit
for i := ntxn; i > 0; i-- {
err = txnh.LoadPrev(fSeq, fs1.LoadAll)
if err != nil {
if err == io.EOF {
err = nil // XXX -> okEOF(err)
}
break
}
// read raw data inside transaction record
dataLen := txnh.DataLen()
data = xbytes.Realloc64(data, dataLen)
_, err = fSeq.ReadAt(data, txnh.DataPos())
if err != nil {
// XXX -> txnh.Err(...) ?
// XXX err = noEOF(err)
err = &fs1.ErrTxnRecord{txnh.Pos, "read data payload", err}
break
}
// print information about read txn record
buf.Reset()
dataSha1 := sha1.Sum(data)
buf .V(txnh.Tid.Time()) .S(": hash=") .Xb(dataSha1[:])
// fstail.py uses repr to print user/description:
// https://github.com/zopefoundation/ZODB/blob/5.2.0-5-g6047e2fae/src/ZODB/scripts/fstail.py#L39
buf .S("\nuser=") .Qpyb(txnh.User) .S(" description=") .Qpyb(txnh.Description)
// NOTE in zodb/py .length is len - 8, in zodb/go - whole txn record length
buf .S(" length=") .D64(txnh.Len - 8)
buf .S(" offset=") .D64(txnh.Pos) .S(" (+") .D64(txnh.HeaderLen()) .S(")\n\n")
_, err = w.Write(buf.Bytes())
if err != nil {
break
}
}
return err
}
*/
// ----------------------------------------
/*
const tailSummary = "dump last few transactions of a database"
const ntxnDefault = 10
func tailUsage(w io.Writer) {
fmt.Fprintf(w,
`Usage: fs1 tail [options] <storage>
Dump transactions from a FileStorage in reverse order
<storage> is a path to FileStorage
options:
-h --help this help text.
-n <N> output the last <N> transactions (default %d).
`, ntxnDefault)
}
func tailMain(argv []string) {
ntxn := ntxnDefault
flags := flag.FlagSet{Usage: func() { tailUsage(os.Stderr) }}
flags.Init("", flag.ExitOnError)
flags.IntVar(&ntxn, "n", ntxn, "output the last <N> transactions")
flags.Parse(argv[1:])
argv = flags.Args()
if len(argv) < 1 {
flags.Usage()
os.Exit(2)
}
storPath := argv[0]
err := Tail(os.Stdout, storPath, ntxn)
if err != nil {
log.Fatal(err)
}
}
*/
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