mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 17:15:56 +00:00
mvoe check to subcommand
This commit is contained in:
parent
ff532f2064
commit
01020d06a8
3 changed files with 180 additions and 135 deletions
35
cmd/check.go
Normal file
35
cmd/check.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/pilosa/pilosa/ctl"
|
||||
)
|
||||
|
||||
var checker = ctl.NewCheckCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
|
||||
var checkCmd = &cobra.Command{
|
||||
Use: "check <path> [path2]...",
|
||||
Short: "check - check a pilosa data file",
|
||||
Long: `
|
||||
Performs a consistency check on data files.
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
fmt.Println("path required")
|
||||
return
|
||||
}
|
||||
checker.Paths = args
|
||||
if err := checker.Run(context.Background()); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(checkCmd)
|
||||
}
|
||||
|
|
@ -9,13 +9,10 @@ import (
|
|||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pilosa/pilosa"
|
||||
"github.com/pilosa/pilosa/roaring"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -88,7 +85,6 @@ Usage:
|
|||
|
||||
The commands are:
|
||||
|
||||
check performs a consistency check of data files
|
||||
bench benchmarks operations
|
||||
|
||||
Use the "-h" flag with any command for more information.
|
||||
|
|
@ -111,8 +107,6 @@ func (m *Main) ParseFlags(args []string) error {
|
|||
fmt.Fprintln(m.Stderr, m.Usage())
|
||||
fmt.Fprintln(m.Stderr, "")
|
||||
return flag.ErrHelp
|
||||
case "check":
|
||||
m.Cmd = NewCheckCommand(m.Stdin, m.Stdout, m.Stderr)
|
||||
case "bench":
|
||||
m.Cmd = NewBenchCommand(m.Stdin, m.Stdout, m.Stderr)
|
||||
default:
|
||||
|
|
@ -138,135 +132,6 @@ type Command interface {
|
|||
Run(context.Context) error
|
||||
}
|
||||
|
||||
// CheckCommand represents a command for performing consistency checks on data files.
|
||||
type CheckCommand struct {
|
||||
// Data file paths.
|
||||
Paths []string
|
||||
|
||||
// Standard input/output
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
}
|
||||
|
||||
// NewCheckCommand returns a new instance of CheckCommand.
|
||||
func NewCheckCommand(stdin io.Reader, stdout, stderr io.Writer) *CheckCommand {
|
||||
return &CheckCommand{
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseFlags parses command line flags from args.
|
||||
func (cmd *CheckCommand) ParseFlags(args []string) error {
|
||||
fs := flag.NewFlagSet("pilosactl", flag.ContinueOnError)
|
||||
fs.SetOutput(ioutil.Discard)
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse path.
|
||||
if fs.NArg() == 0 {
|
||||
return errors.New("path required")
|
||||
}
|
||||
cmd.Paths = fs.Args()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Usage returns the usage message to be printed.
|
||||
func (cmd *CheckCommand) Usage() string {
|
||||
return strings.TrimSpace(`
|
||||
usage: pilosactl check PATHS...
|
||||
|
||||
Performs a consistency check on data files.
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
// Run executes the main program execution.
|
||||
func (cmd *CheckCommand) Run(ctx context.Context) error {
|
||||
for _, path := range cmd.Paths {
|
||||
switch filepath.Ext(path) {
|
||||
case "":
|
||||
if err := cmd.checkBitmapFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case ".cache":
|
||||
if err := cmd.checkCacheFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case ".snapshotting":
|
||||
if err := cmd.checkSnapshotFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkBitmapFile performs a consistency check on path for a roaring bitmap file.
|
||||
func (cmd *CheckCommand) checkBitmapFile(path string) error {
|
||||
// Open file handle.
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Memory map the file.
|
||||
data, err := syscall.Mmap(int(f.Fd()), 0, int(fi.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Munmap(data)
|
||||
|
||||
// Attach the mmap file to the bitmap.
|
||||
bm := roaring.NewBitmap()
|
||||
if err := bm.UnmarshalBinary(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform consistency check.
|
||||
if err := bm.Check(); err != nil {
|
||||
// Print returned errors.
|
||||
switch err := err.(type) {
|
||||
case roaring.ErrorList:
|
||||
for i := range err {
|
||||
fmt.Fprintf(cmd.Stdout, "%s: %s\n", path, err[i].Error())
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(cmd.Stdout, "%s: %s\n", path, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Print success message if no errors were found.
|
||||
fmt.Fprintf(cmd.Stdout, "%s: ok\n", path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkCacheFile performs a consistency check on path for a cache file.
|
||||
func (cmd *CheckCommand) checkCacheFile(path string) error {
|
||||
fmt.Fprintf(cmd.Stderr, "%s: ignoring cache file\n", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkSnapshotFile performs a consistency check on path for a snapshot file.
|
||||
func (cmd *CheckCommand) checkSnapshotFile(path string) error {
|
||||
fmt.Fprintf(cmd.Stderr, "%s: ignoring snapshot file\n", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// BenchCommand represents a command for benchmarking database operations.
|
||||
type BenchCommand struct {
|
||||
// Destination host and port.
|
||||
|
|
|
|||
145
ctl/check.go
Normal file
145
ctl/check.go
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
package ctl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/pilosa/pilosa/roaring"
|
||||
)
|
||||
|
||||
// CheckCommand represents a command for performing consistency checks on data files.
|
||||
type CheckCommand struct {
|
||||
// Data file paths.
|
||||
Paths []string
|
||||
|
||||
// Standard input/output
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
}
|
||||
|
||||
// NewCheckCommand returns a new instance of CheckCommand.
|
||||
func NewCheckCommand(stdin io.Reader, stdout, stderr io.Writer) *CheckCommand {
|
||||
return &CheckCommand{
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseFlags parses command line flags from args.
|
||||
func (cmd *CheckCommand) ParseFlags(args []string) error {
|
||||
fs := flag.NewFlagSet("pilosactl", flag.ContinueOnError)
|
||||
fs.SetOutput(ioutil.Discard)
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse path.
|
||||
if fs.NArg() == 0 {
|
||||
return errors.New("path required")
|
||||
}
|
||||
cmd.Paths = fs.Args()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Usage returns the usage message to be printed.
|
||||
func (cmd *CheckCommand) Usage() string {
|
||||
return strings.TrimSpace(`
|
||||
usage: pilosactl check PATHS...
|
||||
|
||||
Performs a consistency check on data files.
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
// Run executes the main program execution.
|
||||
func (cmd *CheckCommand) Run(ctx context.Context) error {
|
||||
for _, path := range cmd.Paths {
|
||||
switch filepath.Ext(path) {
|
||||
case "":
|
||||
if err := cmd.checkBitmapFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case ".cache":
|
||||
if err := cmd.checkCacheFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case ".snapshotting":
|
||||
if err := cmd.checkSnapshotFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkBitmapFile performs a consistency check on path for a roaring bitmap file.
|
||||
func (cmd *CheckCommand) checkBitmapFile(path string) error {
|
||||
// Open file handle.
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Memory map the file.
|
||||
data, err := syscall.Mmap(int(f.Fd()), 0, int(fi.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Munmap(data)
|
||||
|
||||
// Attach the mmap file to the bitmap.
|
||||
bm := roaring.NewBitmap()
|
||||
if err := bm.UnmarshalBinary(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform consistency check.
|
||||
if err := bm.Check(); err != nil {
|
||||
// Print returned errors.
|
||||
switch err := err.(type) {
|
||||
case roaring.ErrorList:
|
||||
for i := range err {
|
||||
fmt.Fprintf(cmd.Stdout, "%s: %s\n", path, err[i].Error())
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(cmd.Stdout, "%s: %s\n", path, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Print success message if no errors were found.
|
||||
fmt.Fprintf(cmd.Stdout, "%s: ok\n", path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkCacheFile performs a consistency check on path for a cache file.
|
||||
func (cmd *CheckCommand) checkCacheFile(path string) error {
|
||||
fmt.Fprintf(cmd.Stderr, "%s: ignoring cache file\n", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkSnapshotFile performs a consistency check on path for a snapshot file.
|
||||
func (cmd *CheckCommand) checkSnapshotFile(path string) error {
|
||||
fmt.Fprintf(cmd.Stderr, "%s: ignoring snapshot file\n", path)
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue