106 lines
2.0 KiB
Go
106 lines
2.0 KiB
Go
package wal
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"text/tabwriter"
|
|
"time"
|
|
)
|
|
|
|
type Verifier struct {
|
|
Stderr io.Writer
|
|
Stdout io.Writer
|
|
Dir string
|
|
}
|
|
|
|
type VerificationSummary struct {
|
|
EntryCount int
|
|
FileCount int
|
|
CorruptFiles []string
|
|
}
|
|
|
|
func (v *Verifier) Run(print bool) (*VerificationSummary, error) {
|
|
if v.Stderr == nil {
|
|
v.Stderr = os.Stderr
|
|
}
|
|
|
|
if v.Stdout == nil {
|
|
v.Stdout = os.Stdout
|
|
}
|
|
|
|
if !print {
|
|
v.Stderr, v.Stdout = ioutil.Discard, ioutil.Discard
|
|
}
|
|
|
|
dir, err := os.Stat(v.Dir)
|
|
if err != nil {
|
|
return nil, err
|
|
} else if !dir.IsDir() {
|
|
return nil, errors.New("invalid data directory")
|
|
}
|
|
|
|
files, err := filepath.Glob(path.Join(v.Dir, "*.wal"))
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
start := time.Now()
|
|
tw := tabwriter.NewWriter(v.Stdout, 8, 2, 1, ' ', 0)
|
|
|
|
var corruptFiles []string
|
|
var entriesScanned int
|
|
|
|
for _, fpath := range files {
|
|
f, err := os.OpenFile(fpath, os.O_RDONLY, 0600)
|
|
if err != nil {
|
|
fmt.Fprintf(v.Stderr, "error opening file %s: %v. Exiting", fpath, err)
|
|
}
|
|
|
|
clean := true
|
|
reader := NewWALSegmentReader(f)
|
|
for reader.Next() {
|
|
entriesScanned++
|
|
_, err := reader.Read()
|
|
if err != nil {
|
|
clean = false
|
|
fmt.Fprintf(tw, "%s: corrupt entry found at position %d\n", fpath, reader.Count())
|
|
corruptFiles = append(corruptFiles, fpath)
|
|
break
|
|
}
|
|
|
|
}
|
|
|
|
if clean {
|
|
fmt.Fprintf(tw, "%s: clean\n", fpath)
|
|
}
|
|
}
|
|
|
|
fmt.Fprintf(tw, "Results:\n")
|
|
fmt.Fprintf(tw, " Files checked: %d\n", len(files))
|
|
fmt.Fprintf(tw, " Total entries checked: %d\n", entriesScanned)
|
|
fmt.Fprintf(tw, " Corrupt files found: ")
|
|
if len(corruptFiles) == 0 {
|
|
fmt.Fprintf(tw, "None")
|
|
} else {
|
|
for _, name := range corruptFiles {
|
|
fmt.Fprintf(tw, "\n %s", name)
|
|
}
|
|
}
|
|
|
|
fmt.Fprintf(tw, "\nCompleted in %v\n", time.Since(start))
|
|
|
|
summary := &VerificationSummary{
|
|
EntryCount: entriesScanned,
|
|
CorruptFiles: corruptFiles,
|
|
FileCount: len(files),
|
|
}
|
|
|
|
return summary, nil
|
|
}
|