Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
neoppod
Commits
eab0c6e3
Commit
eab0c6e3
authored
Jul 26, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
b0b596a2
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
162 additions
and
64 deletions
+162
-64
go/zodb/storage/fs1/filestorage.go
go/zodb/storage/fs1/filestorage.go
+1
-1
go/zodb/storage/fs1/fs1tools/dump.go
go/zodb/storage/fs1/fs1tools/dump.go
+134
-43
go/zodb/storage/fs1/fs1tools/tail.go
go/zodb/storage/fs1/fs1tools/tail.go
+14
-14
go/zodb/storage/fs1/fs1tools/tail_test.go
go/zodb/storage/fs1/fs1tools/tail_test.go
+13
-6
No files found.
go/zodb/storage/fs1/filestorage.go
View file @
eab0c6e3
...
@@ -206,7 +206,7 @@ func (fh *FileHeader) Load(r io.ReaderAt) error {
...
@@ -206,7 +206,7 @@ func (fh *FileHeader) Load(r io.ReaderAt) error {
return
err
// XXX err more context
return
err
// XXX err more context
}
}
if
string
(
fh
.
Magic
[
:
])
!=
Magic
{
if
string
(
fh
.
Magic
[
:
])
!=
Magic
{
return
fmt
.
Errorf
(
"%s: invalid magic %q"
,
xio
.
Name
(
r
),
fh
.
Magic
)
// XXX -> decode err
return
fmt
.
Errorf
(
"%s: invalid magic %q"
,
xio
.
Name
(
r
),
fh
.
Magic
)
// XXX -> decode err
//return decodeErr(fh, "invalid magic %q", fh.Magic)
//return decodeErr(fh, "invalid magic %q", fh.Magic)
}
}
...
...
go/zodb/storage/fs1/fs1tools/dump.go
View file @
eab0c6e3
...
@@ -18,43 +18,43 @@
...
@@ -18,43 +18,43 @@
// See https://www.nexedi.com/licensing for rationale and options.
// See https://www.nexedi.com/licensing for rationale and options.
package
fs1tools
package
fs1tools
// various dumping routines / subcommands
import
(
import
(
"crypto/sha1"
"flag"
"fmt"
"fmt"
"io"
"io"
"log"
"os"
"lab.nexedi.com/kirr/neo/go/zodb/storage/fs1"
"lab.nexedi.com/kirr/neo/go/zodb/storage/fs1"
"lab.nexedi.com/kirr/go123/xbytes"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xfmt"
"lab.nexedi.com/kirr/go123/xfmt"
)
)
/*
// Dumper is interface to implement various dumping modes
Dump dumps transactions from a FileStorage.
type
Dumper
interface
{
// DumpFileHeader dumps fh to buf
Format is the same as in fsdump/py originally written by Jeremy Hylton:
DumpFileHeader
(
buf
*
xfmt
.
Buffer
,
fh
*
fs1
.
FileHeader
)
error
https://github.com/zopefoundation/ZODB/blob/master/src/ZODB/FileStorage/fsdump.py
// DumpTxn dumps current transaction from it to buf.
https://github.com/zopefoundation/ZODB/commit/ddcb46a2
//
https://github.com/zopefoundation/ZODB/commit/4d86e4e0
// It is dumper responsibility to iterate over data records inside
*/
// transaction if it needs to dump information about data records.
func
Dump
(
w
io
.
Writer
,
path
string
,
options
DumpOptions
)
(
err
error
)
{
//
var
d
dumper
// If dumper return io.EOF the whole dumping process finishes.
if
options
.
Verbose
{
// XXX -> better dedicated err?
d
=
&
dumperVerbose
{}
DumpTxn
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
}
else
{
d
=
&
dumper1
{}
}
return
dump
(
w
,
path
,
fs1
.
IterForward
,
d
)
// XXX hardcoded
}
type
DumpOptions
struct
{
Verbose
bool
// dump in verbose mode
}
}
func
dump
(
w
io
.
Writer
,
path
string
,
dir
fs1
.
IterDir
,
d
dumper
)
(
err
error
)
{
// Dump dumps content of a FileStorage file @ path.
defer
xerr
.
Contextf
(
&
err
,
"%s: fsdump"
,
path
)
// XXX ok?
// 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 ?
it
,
f
,
err
:=
fs1
.
IterateFile
(
path
,
dir
)
it
,
f
,
err
:=
fs1
.
IterateFile
(
path
,
dir
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -87,7 +87,10 @@ func dump(w io.Writer, path string, dir fs1.IterDir, d dumper) (err error) {
...
@@ -87,7 +87,10 @@ func dump(w io.Writer, path string, dir fs1.IterDir, d dumper) (err error) {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
d
.
dumpFileHeader
(
buf
,
&
fh
)
err
=
d
.
DumpFileHeader
(
buf
,
&
fh
)
if
err
!=
nil
{
return
err
}
// iter over txn/data
// iter over txn/data
for
{
for
{
...
@@ -99,7 +102,7 @@ func dump(w io.Writer, path string, dir fs1.IterDir, d dumper) (err error) {
...
@@ -99,7 +102,7 @@ func dump(w io.Writer, path string, dir fs1.IterDir, d dumper) (err error) {
return
err
return
err
}
}
err
=
d
.
d
umpTxn
(
buf
,
it
)
err
=
d
.
D
umpTxn
(
buf
,
it
)
if
err
!=
nil
{
if
err
!=
nil
{
if
err
==
io
.
EOF
{
if
err
==
io
.
EOF
{
err
=
nil
// XXX -> okEOF(err)
err
=
nil
// XXX -> okEOF(err)
...
@@ -114,24 +117,22 @@ func dump(w io.Writer, path string, dir fs1.IterDir, d dumper) (err error) {
...
@@ -114,24 +117,22 @@ func dump(w io.Writer, path string, dir fs1.IterDir, d dumper) (err error) {
}
}
}
}
// dumper is internal interface to implement various dumping modes
// ----------------------------------------
type
dumper
interface
{
dumpFileHeader
(
*
xfmt
.
Buffer
,
*
fs1
.
FileHeader
)
error
dumpTxn
(
*
xfmt
.
Buffer
,
*
fs1
.
Iter
)
error
// dumpData(*xfmt.Buffer, *fs1.Iter) error
// dumpTxnPost(*xfmt.Buffer, *fs1.Iter) error
}
// "normal" dumper XXX link to zodb/py
// DumperFsDump implements dumping with the same format as in fsdump/py
type
dumper1
struct
{
// originally written by Jeremy Hylton:
//
// https://github.com/zopefoundation/ZODB/blob/master/src/ZODB/FileStorage/fsdump.py
// https://github.com/zopefoundation/ZODB/commit/ddcb46a2
type
DumperFsDump
struct
{
ntxn
int
// current transaction record #
ntxn
int
// current transaction record #
}
}
func
(
d
*
dumper1
)
d
umpFileHeader
(
buf
*
xfmt
.
Buffer
,
fh
*
fs1
.
FileHeader
)
error
{
func
(
d
*
DumperFsDump
)
D
umpFileHeader
(
buf
*
xfmt
.
Buffer
,
fh
*
fs1
.
FileHeader
)
error
{
return
nil
return
nil
}
}
func
(
d
*
dumper1
)
d
umpTxn
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
{
func
(
d
*
DumperFsDump
)
D
umpTxn
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
{
txnh
:=
&
it
.
Txnh
txnh
:=
&
it
.
Txnh
buf
.
S
(
"Trans #"
)
buf
.
S
(
"Trans #"
)
buf
.
S
(
fmt
.
Sprintf
(
"%05d"
,
d
.
ntxn
))
// XXX -> .D_f("05", d.ntxn)
buf
.
S
(
fmt
.
Sprintf
(
"%05d"
,
d
.
ntxn
))
// XXX -> .D_f("05", d.ntxn)
...
@@ -183,13 +184,16 @@ func (d *dumper1) dumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error {
...
@@ -183,13 +184,16 @@ func (d *dumper1) dumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error {
return
nil
return
nil
}
}
// ----------------------------------------
// verbose dumper with output identical to fsdump.Dumper in zodb/py
// DumperFsDumpVerbose implements a very verbose dumper with output identical
type
dumperVerbose
struct
{
// to fsdump.Dumper in zodb/py originally written by Jeremy Hylton:
//
// https://github.com/zopefoundation/ZODB/blob/master/src/ZODB/FileStorage/fsdump.py
// https://github.com/zopefoundation/ZODB/commit/4d86e4e0
type
DumperFsDumpVerbose
struct
{
}
}
func
(
d
*
dumperVerbose
)
d
umpFileHeader
(
buf
*
xfmt
.
Buffer
,
fh
*
fs1
.
FileHeader
)
error
{
func
(
d
*
DumperFsDumpVerbose
)
D
umpFileHeader
(
buf
*
xfmt
.
Buffer
,
fh
*
fs1
.
FileHeader
)
error
{
for
i
:=
0
;
i
<
60
;
i
++
{
for
i
:=
0
;
i
<
60
;
i
++
{
buf
.
S
(
"*"
)
buf
.
S
(
"*"
)
}
}
...
@@ -198,7 +202,7 @@ func (d *dumperVerbose) dumpFileHeader(buf *xfmt.Buffer, fh *fs1.FileHeader) err
...
@@ -198,7 +202,7 @@ func (d *dumperVerbose) dumpFileHeader(buf *xfmt.Buffer, fh *fs1.FileHeader) err
return
nil
return
nil
}
}
func
(
d
*
dumperVerbose
)
d
umpTxn
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
{
func
(
d
*
DumperFsDumpVerbose
)
D
umpTxn
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
{
txnh
:=
&
it
.
Txnh
txnh
:=
&
it
.
Txnh
for
i
:=
0
;
i
<
60
;
i
++
{
for
i
:=
0
;
i
<
60
;
i
++
{
buf
.
S
(
"="
)
buf
.
S
(
"="
)
...
@@ -225,7 +229,7 @@ func (d *dumperVerbose) dumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error {
...
@@ -225,7 +229,7 @@ func (d *dumperVerbose) dumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error {
return
nil
return
nil
}
}
func
(
d
*
dumper
Verbose
)
dumpData
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
{
func
(
d
*
DumperFsDump
Verbose
)
dumpData
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
{
dh
:=
&
it
.
Datah
dh
:=
&
it
.
Datah
for
i
:=
0
;
i
<
60
;
i
++
{
for
i
:=
0
;
i
<
60
;
i
++
{
buf
.
S
(
"-"
)
buf
.
S
(
"-"
)
...
@@ -249,3 +253,90 @@ func (d *dumperVerbose) dumpData(buf *xfmt.Buffer, it *fs1.Iter) error {
...
@@ -249,3 +253,90 @@ func (d *dumperVerbose) dumpData(buf *xfmt.Buffer, it *fs1.Iter) error {
buf
.
S
(
"
\n
"
)
buf
.
S
(
"
\n
"
)
return
nil
return
nil
}
}
// ----------------------------------------
// DumperFsTail implements dumping with the same format 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
type
DumperFsTail
struct
{
Ntxn
int
// max # of transactions to dump
data
[]
byte
// buffer for reading txn data
}
func
(
d
*
DumperFsTail
)
DumpFileHeader
(
buf
*
xfmt
.
Buffer
,
fh
*
fs1
.
FileHeader
)
error
{
return
nil
}
func
(
d
*
DumperFsTail
)
DumpTxn
(
buf
*
xfmt
.
Buffer
,
it
*
fs1
.
Iter
)
error
{
if
d
.
Ntxn
==
0
{
return
io
.
EOF
}
d
.
Ntxn
--
txnh
:=
&
it
.
Txnh
// read raw data inside transaction record
dataLen
:=
txnh
.
DataLen
()
d
.
data
=
xbytes
.
Realloc64
(
d
.
data
,
dataLen
)
_
,
err
:=
it
.
R
.
ReadAt
(
d
.
data
,
txnh
.
DataPos
())
if
err
!=
nil
{
// XXX -> txnh.Err(...) ?
// XXX err = noEOF(err)
return
&
fs1
.
ErrTxnRecord
{
txnh
.
Pos
,
"read data payload"
,
err
}
}
// print information about read txn record
dataSha1
:=
sha1
.
Sum
(
d
.
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
(
"
\n
user="
)
.
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
"
)
return
nil
}
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
:=
Dump
(
os
.
Stdout
,
storPath
,
fs1
.
IterBackward
,
&
DumperFsTail
{
Ntxn
:
ntxn
})
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
}
go/zodb/storage/fs1/fs1tools/tail.go
View file @
eab0c6e3
...
@@ -20,20 +20,16 @@
...
@@ -20,20 +20,16 @@
package
fs1tools
package
fs1tools
import
(
import
(
"crypto/sha1"
// "crypto/sha1"
"flag"
// "flag"
"fmt"
// "fmt"
"io"
// "io"
"log"
// "log"
"os"
// "os"
"lab.nexedi.com/kirr/neo/go/zodb/storage/fs1"
// "lab.nexedi.com/kirr/go123/xbytes"
// "lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/neo/go/xcommon/xbufio"
// "lab.nexedi.com/kirr/go123/xfmt"
"lab.nexedi.com/kirr/go123/xbytes"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xfmt"
)
)
/*
/*
...
@@ -44,6 +40,7 @@ Format is the same as in fstail/py originally written by Jeremy Hylton:
...
@@ -44,6 +40,7 @@ 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/blob/master/src/ZODB/scripts/fstail.py
https://github.com/zopefoundation/ZODB/commit/551122cc
https://github.com/zopefoundation/ZODB/commit/551122cc
*/
*/
/*
func Tail(w io.Writer, path string, ntxn int) (err error) {
func Tail(w io.Writer, path string, ntxn int) (err error) {
// path & fstail on error context
// path & fstail on error context
defer xerr.Contextf(&err, "%s: fstail", path)
defer xerr.Contextf(&err, "%s: fstail", path)
...
@@ -138,9 +135,11 @@ func Tail(w io.Writer, path string, ntxn int) (err error) {
...
@@ -138,9 +135,11 @@ func Tail(w io.Writer, path string, ntxn int) (err error) {
return err
return err
}
}
*/
// ----------------------------------------
// ----------------------------------------
/*
const tailSummary = "dump last few transactions of a database"
const tailSummary = "dump last few transactions of a database"
const ntxnDefault = 10
const ntxnDefault = 10
...
@@ -178,3 +177,4 @@ func tailMain(argv []string) {
...
@@ -178,3 +177,4 @@ func tailMain(argv []string) {
log.Fatal(err)
log.Fatal(err)
}
}
}
}
*/
go/zodb/storage/fs1/fs1tools/tail_test.go
View file @
eab0c6e3
...
@@ -23,9 +23,12 @@ package fs1tools
...
@@ -23,9 +23,12 @@ package fs1tools
import
(
import
(
"bytes"
"bytes"
"fmt"
"io/ioutil"
"io/ioutil"
"testing"
"testing"
"lab.nexedi.com/kirr/neo/go/zodb/storage/fs1"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/sergi/go-diff/diffmatchpatch"
)
)
...
@@ -46,25 +49,29 @@ func diff(a, b string) string {
...
@@ -46,25 +49,29 @@ func diff(a, b string) string {
return
dmp
.
DiffPrettyText
(
diffv
)
return
dmp
.
DiffPrettyText
(
diffv
)
}
}
func
TestTail
(
t
*
testing
.
T
)
{
func
testDump
(
t
*
testing
.
T
,
name
string
,
dir
fs1
.
IterDir
,
d
Dumper
)
{
buf
:=
bytes
.
Buffer
{}
buf
:=
bytes
.
Buffer
{}
err
:=
Tail
(
&
buf
,
"../testdata/1.fs"
,
1000000
)
err
:=
Dump
(
&
buf
,
"../testdata/1.fs"
,
dir
,
d
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
f
(
"%s: %v"
,
name
,
err
)
}
}
dumpOk
:=
loadFile
(
t
,
"testdata/1.fstail.ok"
)
dumpOk
:=
loadFile
(
t
,
fmt
.
Sprintf
(
"testdata/1.%s.ok"
,
name
)
)
if
dumpOk
!=
buf
.
String
()
{
if
dumpOk
!=
buf
.
String
()
{
t
.
Errorf
(
"
dump different:
\n
%v"
,
diff
(
dumpOk
,
buf
.
String
()))
t
.
Errorf
(
"
%s: dump different:
\n
%v"
,
name
,
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
BenchmarkTail
(
b
*
testing
.
B
)
{
func
BenchmarkTail
(
b
*
testing
.
B
)
{
// FIXME small testdata/1.fs is not representative for benchmarking
// FIXME small testdata/1.fs is not representative for benchmarking
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
err
:=
Tail
(
ioutil
.
Discard
,
"../testdata/1.fs"
,
1000000
)
err
:=
Dump
(
ioutil
.
Discard
,
"../testdata/1.fs"
,
fs1
.
IterBackward
,
&
DumperFsTail
{
Ntxn
:
1000000
}
)
if
err
!=
nil
{
if
err
!=
nil
{
b
.
Fatal
(
err
)
b
.
Fatal
(
err
)
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment