163 lines
3.7 KiB
Go
163 lines
3.7 KiB
Go
// Package dumptsmwal dumps all data from a WAL file.
|
|
package dumptsmwal
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
|
|
"github.com/influxdata/influxdb/tsdb/engine/tsm1"
|
|
)
|
|
|
|
// Command represents the program execution for "influxd dumptsmwal".
|
|
type Command struct {
|
|
// Standard input/output, overridden for testing.
|
|
Stderr io.Writer
|
|
Stdout io.Writer
|
|
|
|
showDuplicates bool
|
|
}
|
|
|
|
// NewCommand returns a new instance of Command.
|
|
func NewCommand() *Command {
|
|
return &Command{
|
|
Stderr: os.Stderr,
|
|
Stdout: os.Stdout,
|
|
}
|
|
}
|
|
|
|
// Run executes the command.
|
|
func (cmd *Command) Run(args ...string) (err error) {
|
|
fs := flag.NewFlagSet("dumptsmwal", flag.ExitOnError)
|
|
fs.SetOutput(cmd.Stdout)
|
|
fs.BoolVar(&cmd.showDuplicates, "show-duplicates", false, "prints keys with out-of-order or duplicate values")
|
|
fs.Usage = cmd.printUsage
|
|
if err := fs.Parse(args); err != nil {
|
|
return err
|
|
} else if fs.NArg() == 0 {
|
|
fmt.Printf("path required\n\n")
|
|
fs.Usage()
|
|
return nil
|
|
}
|
|
|
|
// Process each TSM WAL file.
|
|
for _, path := range fs.Args() {
|
|
if err := cmd.process(path); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (cmd *Command) process(path string) error {
|
|
if filepath.Ext(path) != "."+tsm1.WALFileExtension {
|
|
log.Printf("invalid wal filename, skipping %s", path)
|
|
return nil
|
|
}
|
|
|
|
// Track the earliest timestamp for each key and a set of keys with out-of-order points.
|
|
minTimestampByKey := make(map[string]int64)
|
|
duplicateKeys := make(map[string]struct{})
|
|
|
|
// Open WAL reader.
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
r := tsm1.NewWALSegmentReader(f)
|
|
|
|
// Iterate over the WAL entries.
|
|
for r.Next() {
|
|
entry, err := r.Read()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot read entry: %s", err)
|
|
}
|
|
|
|
switch entry := entry.(type) {
|
|
case *tsm1.WriteWALEntry:
|
|
if !cmd.showDuplicates {
|
|
fmt.Printf("[write] sz=%d\n", entry.MarshalSize())
|
|
}
|
|
|
|
keys := make([]string, 0, len(entry.Values))
|
|
for k := range entry.Values {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
for _, k := range keys {
|
|
for _, v := range entry.Values[k] {
|
|
t := v.UnixNano()
|
|
|
|
// Check for duplicate/out of order keys.
|
|
if min, ok := minTimestampByKey[k]; ok && t <= min {
|
|
duplicateKeys[k] = struct{}{}
|
|
}
|
|
minTimestampByKey[k] = t
|
|
|
|
// Skip printing if we are only showing duplicate keys.
|
|
if cmd.showDuplicates {
|
|
continue
|
|
}
|
|
|
|
switch v := v.(type) {
|
|
case tsm1.IntegerValue:
|
|
fmt.Printf("%s %vi %d\n", k, v.Value(), t)
|
|
case tsm1.UnsignedValue:
|
|
fmt.Printf("%s %vu %d\n", k, v.Value(), t)
|
|
case tsm1.FloatValue:
|
|
fmt.Printf("%s %v %d\n", k, v.Value(), t)
|
|
case tsm1.BooleanValue:
|
|
fmt.Printf("%s %v %d\n", k, v.Value(), t)
|
|
case tsm1.StringValue:
|
|
fmt.Printf("%s %q %d\n", k, v.Value(), t)
|
|
default:
|
|
fmt.Printf("%s EMPTY\n", k)
|
|
}
|
|
}
|
|
}
|
|
|
|
case *tsm1.DeleteWALEntry:
|
|
fmt.Printf("[delete] sz=%d\n", entry.MarshalSize())
|
|
for _, k := range entry.Keys {
|
|
fmt.Printf("%s\n", string(k))
|
|
}
|
|
|
|
case *tsm1.DeleteRangeWALEntry:
|
|
fmt.Printf("[delete-range] min=%d max=%d sz=%d\n", entry.Min, entry.Max, entry.MarshalSize())
|
|
for _, k := range entry.Keys {
|
|
fmt.Printf("%s\n", string(k))
|
|
}
|
|
|
|
default:
|
|
return fmt.Errorf("invalid wal entry: %#v", entry)
|
|
}
|
|
}
|
|
|
|
// Print keys with duplicate or out-of-order points, if requested.
|
|
if cmd.showDuplicates {
|
|
keys := make([]string, 0, len(duplicateKeys))
|
|
for k := range duplicateKeys {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
for _, k := range keys {
|
|
fmt.Println(k)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (cmd *Command) printUsage() {
|
|
fmt.Print(`Dumps all entries from one or more TSM WAL files.
|
|
|
|
Usage: influx_inspect dumptsmwal path...`)
|
|
}
|