lib/snapshot: move Time, Validate and NewName into lib/snapshot/snapshotutil package

This allows removing importing unneeded command-line flags into binaries, which import lib/storage,
which, in turn, was importing lib/snapshot in order to use Time, Validate and NewName functions.

This is a follow-up for 83e55456e2

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5738
This commit is contained in:
Aliaksandr Valialkin 2024-02-09 04:03:20 +02:00
parent ae8a867924
commit 39e0007e14
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
7 changed files with 112 additions and 99 deletions

View file

@ -20,6 +20,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/pushmetrics" "github.com/VictoriaMetrics/VictoriaMetrics/lib/pushmetrics"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/snapshot" "github.com/VictoriaMetrics/VictoriaMetrics/lib/snapshot"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/snapshot/snapshotutil"
) )
var ( var (
@ -169,7 +170,7 @@ See the docs at https://docs.victoriametrics.com/vmbackup.html .
} }
func newSrcFS() (*fslocal.FS, error) { func newSrcFS() (*fslocal.FS, error) {
if err := snapshot.Validate(*snapshotName); err != nil { if err := snapshotutil.Validate(*snapshotName); err != nil {
return nil, fmt.Errorf("invalid -snapshotName=%q: %w", *snapshotName, err) return nil, fmt.Errorf("invalid -snapshotName=%q: %w", *snapshotName, err)
} }
snapshotPath := filepath.Join(*storageDataPath, "snapshots", *snapshotName) snapshotPath := filepath.Join(*storageDataPath, "snapshots", *snapshotName)

View file

@ -13,7 +13,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fslocal" "github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fslocal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fsnil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fsnil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/snapshot" "github.com/VictoriaMetrics/VictoriaMetrics/lib/snapshot/snapshotutil"
"github.com/VictoriaMetrics/metrics" "github.com/VictoriaMetrics/metrics"
) )
@ -87,7 +87,7 @@ func (b *Backup) Run() error {
func storeMetadata(src *fslocal.FS, dst common.RemoteFS) error { func storeMetadata(src *fslocal.FS, dst common.RemoteFS) error {
snapshotName := filepath.Base(src.Dir) snapshotName := filepath.Base(src.Dir)
snapshotTime, err := snapshot.Time(snapshotName) snapshotTime, err := snapshotutil.Time(snapshotName)
if err != nil { if err != nil {
return fmt.Errorf("cannot decode snapshot name %q: %w", snapshotName, err) return fmt.Errorf("cannot decode snapshot name %q: %w", snapshotName, err)
} }

View file

@ -8,17 +8,11 @@ import (
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"regexp"
"strings"
"sync/atomic"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils" "github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
) )
var snapshotNameRegexp = regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`)
var ( var (
tlsInsecureSkipVerify = flag.Bool("snapshot.tlsInsecureSkipVerify", false, "Whether to skip tls verification when connecting to -snapshotCreateURL") tlsInsecureSkipVerify = flag.Bool("snapshot.tlsInsecureSkipVerify", false, "Whether to skip tls verification when connecting to -snapshotCreateURL")
tlsCertFile = flag.String("snapshot.tlsCertFile", "", "Optional path to client-side TLS certificate file to use when connecting to -snapshotCreateURL") tlsCertFile = flag.String("snapshot.tlsCertFile", "", "Optional path to client-side TLS certificate file to use when connecting to -snapshotCreateURL")
@ -119,37 +113,3 @@ func Delete(deleteSnapshotURL string, snapshotName string) error {
} }
return fmt.Errorf("Unkown status: %v", snap.Status) return fmt.Errorf("Unkown status: %v", snap.Status)
} }
// Validate validates the snapshotName
func Validate(snapshotName string) error {
_, err := Time(snapshotName)
return err
}
// Time returns snapshot creation time from the given snapshotName
func Time(snapshotName string) (time.Time, error) {
if !snapshotNameRegexp.MatchString(snapshotName) {
return time.Time{}, fmt.Errorf("unexpected snapshot name=%q; it must match %q regexp", snapshotName, snapshotNameRegexp.String())
}
n := strings.IndexByte(snapshotName, '-')
if n < 0 {
logger.Panicf("BUG: cannot find `-` in snapshotName=%q", snapshotName)
}
s := snapshotName[:n]
t, err := time.Parse("20060102150405", s)
if err != nil {
return time.Time{}, fmt.Errorf("unexpected timestamp=%q in snapshot name: %w; it must match YYYYMMDDhhmmss pattern", s, err)
}
return t, nil
}
// NewName returns new name for new snapshot
func NewName() string {
return fmt.Sprintf("%s-%08X", time.Now().UTC().Format("20060102150405"), nextSnapshotIdx())
}
func nextSnapshotIdx() uint64 {
return atomic.AddUint64(&snapshotIdx, 1)
}
var snapshotIdx = uint64(time.Now().UnixNano())

View file

@ -104,54 +104,3 @@ func TestDeleteSnapshotFailed(t *testing.T) {
t.Fatalf("Snapshot should have failed, got: %v", err) t.Fatalf("Snapshot should have failed, got: %v", err)
} }
} }
func Test_Validate(t *testing.T) {
tests := []struct {
name string
snapshotName string
want bool
}{
{
name: "empty snapshot name",
snapshotName: "",
want: false,
},
{
name: "short snapshot name",
snapshotName: "",
want: false,
},
{
name: "short first part of the snapshot name",
snapshotName: "2022050312163-16EB56ADB4110CF2",
want: false,
},
{
name: "short second part of the snapshot name",
snapshotName: "20220503121638-16EB56ADB4110CF",
want: true,
},
{
name: "correct snapshot name",
snapshotName: "20220503121638-16EB56ADB4110CF2",
want: true,
},
{
name: "invalid time part snapshot name",
snapshotName: "00000000000000-16EB56ADB4110CF2",
want: false,
},
{
name: "not enough parts of the snapshot name",
snapshotName: "2022050312163816EB56ADB4110CF2",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Validate(tt.snapshotName); (err == nil) != tt.want {
t.Errorf("checkSnapshotName() = %v, want %v", err, tt.want)
}
})
}
}

View file

@ -0,0 +1,47 @@
package snapshotutil
import (
"fmt"
"regexp"
"strings"
"sync/atomic"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
)
var snapshotNameRegexp = regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`)
// Validate validates the snapshotName
func Validate(snapshotName string) error {
_, err := Time(snapshotName)
return err
}
// Time returns snapshot creation time from the given snapshotName
func Time(snapshotName string) (time.Time, error) {
if !snapshotNameRegexp.MatchString(snapshotName) {
return time.Time{}, fmt.Errorf("unexpected snapshot name=%q; it must match %q regexp", snapshotName, snapshotNameRegexp.String())
}
n := strings.IndexByte(snapshotName, '-')
if n < 0 {
logger.Panicf("BUG: cannot find `-` in snapshotName=%q", snapshotName)
}
s := snapshotName[:n]
t, err := time.Parse("20060102150405", s)
if err != nil {
return time.Time{}, fmt.Errorf("unexpected timestamp=%q in snapshot name: %w; it must match YYYYMMDDhhmmss pattern", s, err)
}
return t, nil
}
// NewName returns new name for new snapshot
func NewName() string {
return fmt.Sprintf("%s-%08X", time.Now().UTC().Format("20060102150405"), nextSnapshotIdx())
}
func nextSnapshotIdx() uint64 {
return atomic.AddUint64(&snapshotIdx, 1)
}
var snapshotIdx = uint64(time.Now().UnixNano())

View file

@ -0,0 +1,56 @@
package snapshotutil
import (
"testing"
)
func Test_Validate(t *testing.T) {
tests := []struct {
name string
snapshotName string
want bool
}{
{
name: "empty snapshot name",
snapshotName: "",
want: false,
},
{
name: "short snapshot name",
snapshotName: "",
want: false,
},
{
name: "short first part of the snapshot name",
snapshotName: "2022050312163-16EB56ADB4110CF2",
want: false,
},
{
name: "short second part of the snapshot name",
snapshotName: "20220503121638-16EB56ADB4110CF",
want: true,
},
{
name: "correct snapshot name",
snapshotName: "20220503121638-16EB56ADB4110CF2",
want: true,
},
{
name: "invalid time part snapshot name",
snapshotName: "00000000000000-16EB56ADB4110CF2",
want: false,
},
{
name: "not enough parts of the snapshot name",
snapshotName: "2022050312163816EB56ADB4110CF2",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Validate(tt.snapshotName); (err == nil) != tt.want {
t.Errorf("checkSnapshotName() = %v, want %v", err, tt.want)
}
})
}
}

View file

@ -25,7 +25,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/memory" "github.com/VictoriaMetrics/VictoriaMetrics/lib/memory"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/querytracer" "github.com/VictoriaMetrics/VictoriaMetrics/lib/querytracer"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/snapshot" "github.com/VictoriaMetrics/VictoriaMetrics/lib/snapshot/snapshotutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/timeutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/uint64set" "github.com/VictoriaMetrics/VictoriaMetrics/lib/uint64set"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/workingsetcache" "github.com/VictoriaMetrics/VictoriaMetrics/lib/workingsetcache"
@ -342,7 +342,7 @@ func (s *Storage) CreateSnapshot(deadline uint64) (string, error) {
} }
}() }()
snapshotName := snapshot.NewName() snapshotName := snapshotutil.NewName()
srcDir := s.path srcDir := s.path
dstDir := filepath.Join(srcDir, snapshotsDirname, snapshotName) dstDir := filepath.Join(srcDir, snapshotsDirname, snapshotName)
fs.MustMkdirFailIfExist(dstDir) fs.MustMkdirFailIfExist(dstDir)
@ -409,7 +409,7 @@ func (s *Storage) ListSnapshots() ([]string, error) {
} }
snapshotNames := make([]string, 0, len(fnames)) snapshotNames := make([]string, 0, len(fnames))
for _, fname := range fnames { for _, fname := range fnames {
if err := snapshot.Validate(fname); err != nil { if err := snapshotutil.Validate(fname); err != nil {
continue continue
} }
snapshotNames = append(snapshotNames, fname) snapshotNames = append(snapshotNames, fname)
@ -420,7 +420,7 @@ func (s *Storage) ListSnapshots() ([]string, error) {
// DeleteSnapshot deletes the given snapshot. // DeleteSnapshot deletes the given snapshot.
func (s *Storage) DeleteSnapshot(snapshotName string) error { func (s *Storage) DeleteSnapshot(snapshotName string) error {
if err := snapshot.Validate(snapshotName); err != nil { if err := snapshotutil.Validate(snapshotName); err != nil {
return fmt.Errorf("invalid snapshotName %q: %w", snapshotName, err) return fmt.Errorf("invalid snapshotName %q: %w", snapshotName, err)
} }
snapshotPath := filepath.Join(s.path, snapshotsDirname, snapshotName) snapshotPath := filepath.Join(s.path, snapshotsDirname, snapshotName)
@ -446,7 +446,7 @@ func (s *Storage) DeleteStaleSnapshots(maxAge time.Duration) error {
} }
expireDeadline := time.Now().UTC().Add(-maxAge) expireDeadline := time.Now().UTC().Add(-maxAge)
for _, snapshotName := range list { for _, snapshotName := range list {
t, err := snapshot.Time(snapshotName) t, err := snapshotutil.Time(snapshotName)
if err != nil { if err != nil {
return fmt.Errorf("cannot parse snapshot date from %q: %w", snapshotName, err) return fmt.Errorf("cannot parse snapshot date from %q: %w", snapshotName, err)
} }