Restrict generations command to single db

This commit is contained in:
Ben Johnson
2020-12-30 15:44:21 -07:00
parent ffc25e2654
commit 8a7d8175fc

View File

@@ -12,89 +12,86 @@ import (
"time" "time"
) )
type GenerationsCommand struct { type GenerationsCommand struct{}
ConfigPath string
Config Config
DBPath string
}
func NewGenerationsCommand() *GenerationsCommand { func NewGenerationsCommand() *GenerationsCommand {
return &GenerationsCommand{} return &GenerationsCommand{}
} }
func (c *GenerationsCommand) Run(ctx context.Context, args []string) (err error) { func (c *GenerationsCommand) Run(ctx context.Context, args []string) (err error) {
var configPath string
fs := flag.NewFlagSet("litestream-generations", flag.ContinueOnError) fs := flag.NewFlagSet("litestream-generations", flag.ContinueOnError)
registerConfigFlag(fs, &c.ConfigPath) registerConfigFlag(fs, &configPath)
replicaName := fs.String("replica", "", "replica name")
fs.Usage = c.Usage fs.Usage = c.Usage
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
} else if fs.NArg() == 0 || fs.Arg(0) == "" {
return fmt.Errorf("database path required")
} else if fs.NArg() > 1 { } else if fs.NArg() > 1 {
return fmt.Errorf("too many arguments") return fmt.Errorf("too many arguments")
} }
// Load configuration. // Load configuration.
if c.ConfigPath == "" { if configPath == "" {
return errors.New("-config required") return errors.New("-config required")
} }
config, err := ReadConfigFile(c.ConfigPath) config, err := ReadConfigFile(configPath)
if err != nil { if err != nil {
return err return err
} }
// Determine absolute path for database, if specified. // Determine absolute path for database.
if c.DBPath = fs.Arg(0); c.DBPath != "" { dbPath, err := filepath.Abs(fs.Arg(0))
if c.DBPath, err = filepath.Abs(c.DBPath); err != nil { if err != nil {
return err return err
} }
// Instantiate DB from from configuration.
dbConfig := config.DBConfig(dbPath)
if dbConfig == nil {
return fmt.Errorf("database not found in config: %s", dbPath)
}
db, err := newDBFromConfig(dbConfig)
if err != nil {
return err
}
// Determine last time database or WAL was updated.
updatedAt, err := db.UpdatedAt()
if err != nil {
return err
} }
// List each generation. // List each generation.
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
fmt.Fprintln(w, "db\tname\tgeneration\tlag\tstart\tend") fmt.Fprintln(w, "name\tgeneration\tlag\tstart\tend")
for _, dbConfig := range config.DBs { for _, r := range db.Replicas {
// Filter database, if specified in the arguments. if *replicaName != "" && r.Name() != *replicaName {
if c.DBPath != "" && dbConfig.Path != c.DBPath {
continue continue
} }
// Instantiate DB from from configuration. generations, err := r.Generations(ctx)
db, err := newDBFromConfig(dbConfig)
if err != nil { if err != nil {
return err log.Printf("%s: cannot list generations: %s", r.Name(), err)
continue
} }
// Determine last time database or WAL was updated. // Iterate over each generation for the replica.
updatedAt, err := db.UpdatedAt() for _, generation := range generations {
if err != nil { stats, err := r.GenerationStats(ctx, generation)
return err
}
// Iterate over each replica in the database.
for _, r := range db.Replicas {
generations, err := r.Generations(ctx)
if err != nil { if err != nil {
log.Printf("%s: cannot list generations: %s", r.Name(), err) log.Printf("%s: cannot find generation stats: %s", r.Name(), err)
continue continue
} }
// Iterate over each generation for the replica. fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
for _, generation := range generations { r.Name(),
stats, err := r.GenerationStats(ctx, generation) generation,
if err != nil { truncateDuration(stats.UpdatedAt.Sub(updatedAt)).String(),
log.Printf("%s: cannot find generation stats: %s", r.Name(), err) stats.CreatedAt.Format(time.RFC3339),
continue stats.UpdatedAt.Format(time.RFC3339),
} )
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n",
db.Path(),
r.Name(),
generation,
truncateDuration(stats.UpdatedAt.Sub(updatedAt)).String(),
stats.CreatedAt.Format(time.RFC3339),
stats.UpdatedAt.Format(time.RFC3339),
)
}
} }
} }
w.Flush() w.Flush()
@@ -104,7 +101,7 @@ func (c *GenerationsCommand) Run(ctx context.Context, args []string) (err error)
func (c *GenerationsCommand) Usage() { func (c *GenerationsCommand) Usage() {
fmt.Printf(` fmt.Printf(`
The generations command lists all generations across all replicas along with The generations command lists all generations for a database. It also lists
stats about their lag behind the primary database and the time range they cover. stats about their lag behind the primary database and the time range they cover.
Usage: Usage:
@@ -116,6 +113,9 @@ Arguments:
-config PATH -config PATH
Specifies the configuration file. Defaults to %s Specifies the configuration file. Defaults to %s
-replica NAME
Optional, filters by replica.
`[1:], `[1:],
DefaultConfigPath, DefaultConfigPath,
) )