Commit d1054012 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 2ef35dde
...@@ -81,7 +81,6 @@ func reindexMain(argv []string) { ...@@ -81,7 +81,6 @@ func reindexMain(argv []string) {
// ---------------------------------------- // ----------------------------------------
// TODO verify-index
// TODO verify-index -quick (only small sanity check) // TODO verify-index -quick (only small sanity check)
// VerifyIndexFor verifies that on-disk index for FileStorage file @ path is correct // VerifyIndexFor verifies that on-disk index for FileStorage file @ path is correct
...@@ -108,6 +107,6 @@ func verifyIdxUsage(w io.Writer) { ...@@ -108,6 +107,6 @@ func verifyIdxUsage(w io.Writer) {
panic("TODO") // XXX panic("TODO") // XXX
} }
func verifyIdxMaxin(argv []string) { func verifyIdxMain(argv []string) {
panic("TODO") // XXX panic("TODO") // XXX
} }
...@@ -28,7 +28,7 @@ var commands = zodbtools.CommandRegistry{ ...@@ -28,7 +28,7 @@ var commands = zodbtools.CommandRegistry{
// + fsstats? (fsstats.py) // + fsstats? (fsstats.py)
{"reindex", reindexSummary, reindexUsage, reindexMain}, {"reindex", reindexSummary, reindexUsage, reindexMain},
{"verify-index", verifyIdxSummary, verifyIdxUsage, verifyIdxMaxin}, {"verify-index", verifyIdxSummary, verifyIdxUsage, verifyIdxMain},
// recover (fsrecover.py) // recover (fsrecover.py)
// verify (fstest.py) // verify (fstest.py)
......
...@@ -411,7 +411,7 @@ func treeEqual(a, b *fsb.Tree) bool { ...@@ -411,7 +411,7 @@ func treeEqual(a, b *fsb.Tree) bool {
return true return true
} }
// --- build/verify index from FileStorage data --- // --- build index from FileStorage data ---
// Update updates in-memory index from r's FileStorage data in byte-range index.TopPos..topPos // Update updates in-memory index from r's FileStorage data in byte-range index.TopPos..topPos
// //
...@@ -536,21 +536,46 @@ func BuildIndexForFile(ctx context.Context, path string) (index *Index, err erro ...@@ -536,21 +536,46 @@ func BuildIndexForFile(ctx context.Context, path string) (index *Index, err erro
return BuildIndex(ctx, fSeq) return BuildIndex(ctx, fSeq)
} }
// VerifyNTxn checks index correctness against several transactions of FileStorage data in r. // --- verify index against data in FileStorage ---
// IndexCorrupyError is the error type returned by index verification routines
// when index was found to not match original FileStorage data.
type IndexCorruptError struct {
DataFileName string
Detail string
}
func (e *IndexCorruptError) Error() string {
return fmt.Sprintf("%s: verify index: %s", e.DataFileName, e.Detail)
}
func indexCorrupt(r io.ReaderAt, format string, argv ...interface{}) *IndexCorruptError {
return &IndexCorruptError{DataFileName: xio.Name(r), Detail: fmt.Sprintf(format, argv...)}
}
// VerifyTail checks index correctness against several newest transactions of FileStorage data in r.
// //
// For ntxn transactions starting from index.TopPos backwards it verifies // For ntxn transactions starting from index.TopPos backwards, it verifies
// whether oid there have correct entries in the index. // whether oid there have correct entries in the index.
// //
// XXX return: ? (how calling code should distinguish IO error on main file from consistency check error) // ntxn=-1 means data range to verify is till start of the file.
// XXX naming? //
func (index *Index) VerifyNTxn(ctx context.Context, r io.ReaderAt, ntxn int) (oidChecked map[zodb.Oid]struct{}, err error) { // Returned error is either:
defer xerr.Contextf(&err, "index quick check") // XXX +main file // - of type *IndexCorruptError, when data in index was found not to match original data, or
it := Iterate(r, index.TopPos, IterBackward) // - any other error type representing e.g. IO error when reading original data or something else.
func (index *Index) VerifyTail(ctx context.Context, r io.ReaderAt, ntxn int) (oidChecked map[zodb.Oid]struct{}, err error) {
defer func() {
if _, ok := err.(*IndexCorruptError); ok {
return // leave it as is
}
xerr.Contextf(&err, "%s: verify index @%v~{%v}", xio.Name(r), index.TopPos, ntxn)
}()
oidChecked = map[zodb.Oid]struct{}{} // Set<zodb.Oid> oidChecked = map[zodb.Oid]struct{}{} // Set<zodb.Oid>
// XXX ntxn=-1 - check all it := Iterate(r, index.TopPos, IterBackward)
for i := 0; i < ntxn; i++ { for i := 0; ntxn == -1 || i < ntxn; i++ {
// check ctx cancel once per transaction // check ctx cancel once per transaction
select { select {
case <-ctx.Done(): case <-ctx.Done():
...@@ -582,11 +607,13 @@ func (index *Index) VerifyNTxn(ctx context.Context, r io.ReaderAt, ntxn int) (oi ...@@ -582,11 +607,13 @@ func (index *Index) VerifyNTxn(ctx context.Context, r io.ReaderAt, ntxn int) (oi
dataPos, ok := index.Get(it.Datah.Oid) dataPos, ok := index.Get(it.Datah.Oid)
if !ok { if !ok {
return nil, fmt.Errorf("oid %v @%v: no index entry", it.Datah.Oid, it.Datah.Pos) return nil, indexCorrupt(r, "oid %v @%v: no index entry",
it.Datah.Oid, it.Datah.Pos)
} }
if dataPos != it.Datah.Pos { if dataPos != it.Datah.Pos {
return nil, fmt.Errorf("oid %v @%v: index has wrong pos (%v)", it.Datah.Oid, it.Datah.Pos, dataPos) return nil, indexCorrupt(r, "oid %v @%v: index has wrong pos (%v)",
it.Datah.Oid, it.Datah.Pos, dataPos)
} }
} }
} }
...@@ -599,8 +626,10 @@ func (index *Index) VerifyNTxn(ctx context.Context, r io.ReaderAt, ntxn int) (oi ...@@ -599,8 +626,10 @@ func (index *Index) VerifyNTxn(ctx context.Context, r io.ReaderAt, ntxn int) (oi
// //
// it verifies whether index is exactly the same as if it was build anew for // it verifies whether index is exactly the same as if it was build anew for
// data in range ..index.TopPos . // data in range ..index.TopPos .
//
// See VerifyTail for description about errors returned.
func (index *Index) Verify(ctx context.Context, r io.ReaderAt) error { func (index *Index) Verify(ctx context.Context, r io.ReaderAt) error {
oidChecked, err := index.VerifyNTxn(ctx, r, -1) oidChecked, err := index.VerifyTail(ctx, r, -1)
if err != nil { if err != nil {
return err return err
} }
...@@ -621,7 +650,7 @@ func (index *Index) Verify(ctx context.Context, r io.ReaderAt) error { ...@@ -621,7 +650,7 @@ func (index *Index) Verify(ctx context.Context, r io.ReaderAt) error {
} }
if _, ok := oidChecked[oid]; !ok { if _, ok := oidChecked[oid]; !ok {
return fmt.Errorf("oid %v @%v: present in index but not in data", oid, pos) return indexCorrupt(r, "oid %v @%v: present in index but not in data", oid, pos)
} }
} }
......
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