Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Port influxd inspect verify-seriesfile #21635

Merged
merged 7 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/influxd/inspect/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ func NewCommand(v *viper.Viper) (*cobra.Command, error) {
base.AddCommand(exportLp)
base.AddCommand(NewExportIndexCommand())

base.AddCommand(NewVerifySeriesfileCommand())

return base, nil
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package seriesfile
package inspect

import (
"errors"
"fmt"
"io/ioutil"
"os"
Expand All @@ -9,10 +10,95 @@ import (
"sort"
"sync"

"github.com/influxdata/influxdb/v2/logger"
"github.com/influxdata/influxdb/v2/tsdb"
"github.com/spf13/cobra"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

type args struct {
dir string
db string
seriesFile string
verbose bool
concurrent int
}

func NewVerifySeriesfileCommand() *cobra.Command {
var arguments args
cmd := &cobra.Command{
Use: "verify-seriesfile",
Short: "Verifies the integrity of series files.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SetOut(os.Stdout)

config := logger.NewConfig()
config.Level = zapcore.WarnLevel
if arguments.verbose {
config.Level = zapcore.InfoLevel
}
log, err := config.New(os.Stderr)
if err != nil {
return err
}

v := NewVerify()
v.Logger = log
v.Concurrent = arguments.concurrent

var db string
if arguments.seriesFile != "" {
db = arguments.seriesFile
} else if arguments.db != "" {
db = filepath.Join(arguments.dir, arguments.db, "_series")
}
if db != "" {
_, err := v.VerifySeriesFile(db)
return err
}

dbs, err := ioutil.ReadDir(arguments.dir)
if err != nil {
return err
}

var hasError bool
for _, db := range dbs {
if !db.IsDir() {
continue
}
filePath := filepath.Join(arguments.dir, db.Name(), "_series")
_, err := v.VerifySeriesFile(filePath)
if err != nil {
v.Logger.Error("Failed to verify series file",
zap.String("filename", filePath),
zap.Error(err))
hasError = true
}
}
if hasError {
return errors.New("some files failed verification, see logs for details")
}
return nil
},
}

cmd.Flags().StringVar(&arguments.dir, "dir", filepath.Join(os.Getenv("HOME"), ".influxdbv2", "engine", "data"),
"Data Directory.")
cmd.Flags().StringVar(&arguments.db, "db", "",
"Only use this database inside of the data directory.")
cmd.Flags().StringVar(&arguments.seriesFile, "series-file", "",
"Path to a series file. This overrides --db and --dir.")
cmd.Flags().BoolVar(&arguments.verbose, "v", false,
"Verbose output.")
cmd.Flags().IntVar(&arguments.concurrent, "c", runtime.GOMAXPROCS(0),
"How many concurrent workers to run.")

return cmd
}

// verifyResult contains the result of a Verify... call
type verifyResult struct {
valid bool
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package seriesfile_test
package inspect

import (
"fmt"
Expand All @@ -9,33 +9,40 @@ import (
"testing"
"time"

"github.com/influxdata/influxdb/v2/cmd/influx_inspect/verify/seriesfile"
"github.com/influxdata/influxdb/v2/models"
"github.com/influxdata/influxdb/v2/tsdb"
"go.uber.org/zap"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)

func TestVerifies_BasicCobra(t *testing.T) {
test := NewTest(t)
defer os.RemoveAll(test.Path)

verify := NewVerifySeriesfileCommand()
verify.SetArgs([]string{"--dir", test.Path})
require.NoError(t, verify.Execute())
}

func TestVerifies_Valid(t *testing.T) {
test := NewTest(t)
defer test.Close()
defer os.RemoveAll(test.Path)

verify := NewVerify()
verify.Logger = zaptest.NewLogger(t)

verify := seriesfile.NewVerify()
if testing.Verbose() {
verify.Logger, _ = zap.NewDevelopment()
}
passed, err := verify.VerifySeriesFile(test.Path)
test.AssertNoError(err)
test.Assert(passed)
require.NoError(t, err)
require.True(t, passed)
}

func TestVerifies_Invalid(t *testing.T) {
test := NewTest(t)
defer test.Close()
defer os.RemoveAll(test.Path)

require.NoError(t, filepath.Walk(test.Path, func(path string, info os.FileInfo, err error) error {
require.NoError(t, err)

test.AssertNoError(filepath.Walk(test.Path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
Expand All @@ -44,25 +51,24 @@ func TestVerifies_Invalid(t *testing.T) {
defer test.Restore(path)

fh, err := os.OpenFile(path, os.O_RDWR, 0)
test.AssertNoError(err)
require.NoError(t, err)
defer fh.Close()

_, err = fh.WriteAt([]byte("BOGUS"), 0)
test.AssertNoError(err)
test.AssertNoError(fh.Close())
_, err = fh.WriteAt([]byte("foobar"), 0)
require.NoError(t, err)
require.NoError(t, fh.Close())

passed, err := seriesfile.NewVerify().VerifySeriesFile(test.Path)
test.AssertNoError(err)
test.Assert(!passed)
verify := NewVerify()
verify.Logger = zaptest.NewLogger(t)

passed, err := verify.VerifySeriesFile(test.Path)
require.NoError(t, err)
require.False(t, passed)

return nil
}))
}

//
// helpers
//

type Test struct {
*testing.T
Path string
Expand All @@ -72,9 +78,7 @@ func NewTest(t *testing.T) *Test {
t.Helper()

dir, err := ioutil.TempDir("", "verify-seriesfile-")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)

// create a series file in the directory
err = func() error {
Expand Down Expand Up @@ -135,39 +139,21 @@ func NewTest(t *testing.T) *Test {
}
}

func (t *Test) Close() {
os.RemoveAll(t.Path)
}

func (t *Test) AssertNoError(err error) {
t.Helper()
if err != nil {
t.Fatal("unexpected error:", err)
}
}

func (t *Test) Assert(x bool) {
t.Helper()
if !x {
t.Fatal("unexpected condition")
}
}

// Backup makes a copy of the path for a later Restore.
func (t *Test) Backup(path string) {
in, err := os.Open(path)
t.AssertNoError(err)
require.NoError(t.T, err)
defer in.Close()

out, err := os.Create(path + ".backup")
t.AssertNoError(err)
require.NoError(t.T, err)
defer out.Close()

_, err = io.Copy(out, in)
t.AssertNoError(err)
require.NoError(t.T, err)
}

// Restore restores the file at the path to the time when Backup was called last.
func (t *Test) Restore(path string) {
t.AssertNoError(os.Rename(path+".backup", path))
require.NoError(t.T, os.Rename(path+".backup", path))
}