committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 452 additions and 0 deletions
-
302weed/shell/command_fs_meta_snapshots_create.go
-
86weed/shell/command_fs_meta_snapshots_create_scheduler.go
-
64weed/shell/command_fs_meta_snapshots_create_scheduler_test.go
@ -0,0 +1,302 @@ |
|||||
|
package shell |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"flag" |
||||
|
"fmt" |
||||
|
"github.com/seaweedfs/seaweedfs/weed/filer" |
||||
|
filer_leveldb "github.com/seaweedfs/seaweedfs/weed/filer/leveldb" |
||||
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" |
||||
|
"github.com/seaweedfs/seaweedfs/weed/util" |
||||
|
"github.com/seaweedfs/seaweedfs/weed/util/mem" |
||||
|
"google.golang.org/protobuf/proto" |
||||
|
"io" |
||||
|
"os" |
||||
|
"path/filepath" |
||||
|
"sort" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
const LevelDbPath = "snapshots.db" |
||||
|
const DateFormat = "2006-01-02" |
||||
|
const SnapshotDirPostFix = "-snapshot" |
||||
|
|
||||
|
func init() { |
||||
|
Commands = append(Commands, &commandFsMetaSnapshotsCreate{}) |
||||
|
} |
||||
|
|
||||
|
type commandFsMetaSnapshotsCreate struct { |
||||
|
} |
||||
|
|
||||
|
func (c *commandFsMetaSnapshotsCreate) Name() string { |
||||
|
return "fs.meta.snapshots.create" |
||||
|
} |
||||
|
|
||||
|
type SnapshotConfig struct { |
||||
|
dir string |
||||
|
} |
||||
|
|
||||
|
func (c SnapshotConfig) GetString(key string) string { |
||||
|
return c.dir |
||||
|
} |
||||
|
func (c SnapshotConfig) GetBool(key string) bool { |
||||
|
panic("implement me") |
||||
|
} |
||||
|
|
||||
|
func (c SnapshotConfig) GetInt(key string) int { |
||||
|
panic("implement me") |
||||
|
} |
||||
|
|
||||
|
func (c SnapshotConfig) GetStringSlice(key string) []string { |
||||
|
panic("implement me") |
||||
|
} |
||||
|
|
||||
|
func (c SnapshotConfig) SetDefault(key string, value interface{}) { |
||||
|
panic("implement me") |
||||
|
} |
||||
|
|
||||
|
func (c *commandFsMetaSnapshotsCreate) Help() string { |
||||
|
return `create snapshots of meta data from given time range. |
||||
|
|
||||
|
fs.meta.snapshots.create -interval-days=7 -count=3 -path=/your/path |
||||
|
// fs.meta.snapshots.create will generate desired number of snapshots with desired duration interval from yesterday the generated files will be saved from input path.
|
||||
|
// These snapshot maybe later used to backup the system to certain timestamp.
|
||||
|
// path input is relative to home directory.
|
||||
|
` |
||||
|
} |
||||
|
|
||||
|
func processMetaDataEvents(store *filer_leveldb.LevelDBStore, data []byte, count int, snapshotCheckPoints []time.Time, homeDir string, snapshotPath string) (SnapshotCount int, err error) { |
||||
|
var event filer_pb.SubscribeMetadataResponse |
||||
|
err = proto.Unmarshal(data, &event) |
||||
|
if err != nil { |
||||
|
return count, err |
||||
|
} |
||||
|
eventTime := event.TsNs |
||||
|
for count < len(snapshotCheckPoints) && time.Unix(0, eventTime).After(snapshotCheckPoints[count].Add(-time.Microsecond)) { |
||||
|
snapshotPath := filepath.Join(homeDir, snapshotPath, snapshotCheckPoints[count].Format(DateFormat)+SnapshotDirPostFix) |
||||
|
err = createIfNotExists(snapshotPath, 0755) |
||||
|
if err != nil { |
||||
|
return count, err |
||||
|
} |
||||
|
err = generateSnapshots(filepath.Join(homeDir, LevelDbPath), snapshotPath) |
||||
|
if err != nil { |
||||
|
return count, err |
||||
|
} |
||||
|
count++ |
||||
|
} |
||||
|
if count < 0 { |
||||
|
return count, nil |
||||
|
} |
||||
|
ctx := context.Background() |
||||
|
if filer_pb.IsEmpty(&event) { |
||||
|
return count, nil |
||||
|
} else if filer_pb.IsCreate(&event) { |
||||
|
entry := filer.FromPbEntry(event.EventNotification.NewParentPath, event.EventNotification.NewEntry) |
||||
|
return count, store.InsertEntry(ctx, entry) |
||||
|
} else if filer_pb.IsDelete(&event) { |
||||
|
return count, store.DeleteEntry(ctx, util.FullPath(event.Directory).Child(event.EventNotification.OldEntry.Name)) |
||||
|
} else if filer_pb.IsUpdate(&event) { |
||||
|
entry := filer.FromPbEntry(event.EventNotification.NewParentPath, event.EventNotification.NewEntry) |
||||
|
return count, store.UpdateEntry(ctx, entry) |
||||
|
} else { |
||||
|
if err := store.DeleteEntry(ctx, util.FullPath(event.Directory).Child(event.EventNotification.OldEntry.Name)); err != nil { |
||||
|
return count, err |
||||
|
} |
||||
|
return count, store.InsertEntry(ctx, filer.FromPbEntry(event.EventNotification.NewParentPath, event.EventNotification.NewEntry)) |
||||
|
} |
||||
|
return count, nil |
||||
|
} |
||||
|
|
||||
|
func processEntryLog(entry *filer_pb.Entry, commandEnv *CommandEnv, snapshotCount int, store *filer_leveldb.LevelDBStore, snapshotsToGenerate []time.Time, homeDirname string, snapshotPath string) (count int, err error) { |
||||
|
totalSize := filer.FileSize(entry) |
||||
|
buf := mem.Allocate(int(totalSize)) |
||||
|
if err = commandEnv.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { |
||||
|
return filer.ReadAll(buf, commandEnv.MasterClient, entry.GetChunks()) |
||||
|
}); err != nil && err != filer_pb.ErrNotFound { |
||||
|
return snapshotCount, err |
||||
|
} |
||||
|
idx := uint32(0) |
||||
|
for idx < uint32(totalSize) { |
||||
|
logEntrySize := util.BytesToUint32(buf[idx : idx+4]) |
||||
|
var logEntry filer_pb.LogEntry |
||||
|
err = proto.Unmarshal(buf[idx+4:idx+4+logEntrySize], &logEntry) |
||||
|
if err != nil { |
||||
|
return snapshotCount, err |
||||
|
} |
||||
|
idx = idx + 4 + logEntrySize |
||||
|
snapshotCount, err = processMetaDataEvents(store, logEntry.Data, snapshotCount, snapshotsToGenerate, homeDirname, snapshotPath) |
||||
|
if err != nil { |
||||
|
return snapshotCount, err |
||||
|
} |
||||
|
} |
||||
|
return snapshotCount, err |
||||
|
} |
||||
|
|
||||
|
func generateSnapshots(scrDir, dest string) error { |
||||
|
entries, err := os.ReadDir(scrDir) |
||||
|
if err := createIfNotExists(dest, 0755); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
for _, entry := range entries { |
||||
|
sourcePath := filepath.Join(scrDir, entry.Name()) |
||||
|
destPath := filepath.Join(dest, entry.Name()) |
||||
|
|
||||
|
fileInfo, err := os.Stat(sourcePath) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
switch fileInfo.Mode() & os.ModeType { |
||||
|
case os.ModeDir: |
||||
|
if err := createIfNotExists(destPath, 0755); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if err := generateSnapshots(sourcePath, destPath); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
default: |
||||
|
if err := copy(sourcePath, destPath); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func copy(srcFile, dstFile string) error { |
||||
|
out, err := os.Create(dstFile) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
defer out.Close() |
||||
|
|
||||
|
in, err := os.Open(srcFile) |
||||
|
defer in.Close() |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
_, err = io.Copy(out, in) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func exists(filePath string) bool { |
||||
|
if _, err := os.Stat(filePath); os.IsNotExist(err) { |
||||
|
return false |
||||
|
} |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
func createIfNotExists(dir string, perm os.FileMode) error { |
||||
|
if exists(dir) { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
if err := os.MkdirAll(dir, perm); err != nil { |
||||
|
return fmt.Errorf("failed to create directory: '%s', error: '%s'", dir, err.Error()) |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func setupLevelDb(levelDbPath string, levelDbBootstrapPath string) (store *filer_leveldb.LevelDBStore, err error) { |
||||
|
store = &filer_leveldb.LevelDBStore{} |
||||
|
err = os.RemoveAll(levelDbPath) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
if len(levelDbBootstrapPath) != 0 { |
||||
|
// copy the latest snapshot as starting point
|
||||
|
err = generateSnapshots(levelDbBootstrapPath, levelDbPath) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
config := SnapshotConfig{ |
||||
|
dir: levelDbPath, |
||||
|
} |
||||
|
|
||||
|
store.Initialize(config, "") |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c *commandFsMetaSnapshotsCreate) Do(args []string, commandEnv *CommandEnv, _writer io.Writer) (err error) { |
||||
|
fsMetaSnapshotsCreateCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError) |
||||
|
snapshotPath := fsMetaSnapshotsCreateCommand.String("path", "", "the path to store generated snapshot files") |
||||
|
count := fsMetaSnapshotsCreateCommand.Int("count", 3, "number of snapshots generated") |
||||
|
intervalDays := fsMetaSnapshotsCreateCommand.Int("interval-days", 7, "the duration interval between each generated snapshot") |
||||
|
if err = fsMetaSnapshotsCreateCommand.Parse(args); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
homeDirname, err := os.UserHomeDir() |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
snapshotsToRemove, snapshotsToGenerate, levelDbBootstrapPath, err := computeRequirements(homeDirname, *snapshotPath, *count, *intervalDays) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
levelDbPath := filepath.Join(homeDirname, LevelDbPath) |
||||
|
store, err := setupLevelDb(levelDbPath, filepath.Join(homeDirname, *snapshotPath, levelDbBootstrapPath)) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
// sort to make sure we are processing ascending list of snapshots to generate
|
||||
|
sort.Slice(snapshotsToGenerate, func(i, j int) bool { |
||||
|
return snapshotsToGenerate[i].Before(snapshotsToGenerate[j]) |
||||
|
}) |
||||
|
changeLogPath := filer.SystemLogDir |
||||
|
var processEntry func(entry *filer_pb.Entry, isLast bool) error |
||||
|
var levelDbBootstrapDate string |
||||
|
if levelDbBootstrapPath != "" { |
||||
|
levelDbBootstrapDate = levelDbBootstrapPath[:len(DateFormat)] |
||||
|
} |
||||
|
snapshotCount := 0 |
||||
|
processEntry = func(entry *filer_pb.Entry, isLast bool) error { |
||||
|
if entry.IsDirectory { |
||||
|
// skip logs prior to the latest previous snapshot
|
||||
|
if levelDbBootstrapDate != "" && entry.GetName() <= levelDbBootstrapDate { |
||||
|
return nil |
||||
|
} |
||||
|
return filer_pb.ReadDirAllEntries(commandEnv, util.FullPath(changeLogPath+"/"+entry.Name), "", processEntry) |
||||
|
} |
||||
|
snapshotCount, err = processEntryLog(entry, commandEnv, snapshotCount, store, snapshotsToGenerate, homeDirname, *snapshotPath) |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
err = filer_pb.ReadDirAllEntries(commandEnv, util.FullPath(changeLogPath), "", processEntry) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
// edge case
|
||||
|
// there might be unfinished snapshot left over in the duration gaps.
|
||||
|
// process meta event only triggers snapshots when there are event after the snapshot time.
|
||||
|
for snapshotCount < len(snapshotsToGenerate) { |
||||
|
generatePath := filepath.Join(homeDirname, *snapshotPath, snapshotsToGenerate[snapshotCount].Format(DateFormat)+SnapshotDirPostFix) |
||||
|
err = createIfNotExists(generatePath, 0755) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
err = generateSnapshots(levelDbPath, generatePath) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
snapshotCount++ |
||||
|
} |
||||
|
// remove previous snapshots.
|
||||
|
for _, snapshot := range snapshotsToRemove { |
||||
|
err = os.RemoveAll(snapshot) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
package shell |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
"os" |
||||
|
"path/filepath" |
||||
|
"sort" |
||||
|
"strings" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func computeRequirementsFromDirectory(previousSnapshots []string, homeDirectory string, snapshotPath string, count int, durationDays int, targetDate time.Time) (snapshotsToRemove []string, snapshotsToGenerate []time.Time, levelDbBootstrapPath string, err error) { |
||||
|
levelDbBootstrapPath = previousSnapshots[len(previousSnapshots)-1] |
||||
|
lastSnapshotDate, err := time.Parse(DateFormat, levelDbBootstrapPath[:len(DateFormat)]) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
// the snapshots cover the last nanosecond of the current date
|
||||
|
lastSnapshotDate = lastSnapshotDate.AddDate(0, 0, 1).Add(-1 * time.Nanosecond) |
||||
|
gapDuration := targetDate.Sub(lastSnapshotDate) |
||||
|
oneSnapshotInterval := 24 * time.Hour * time.Duration(durationDays) |
||||
|
totalSnapshotsInterval := 24 * time.Hour * time.Duration(durationDays*count) |
||||
|
// gap too small no snapshot will be generated
|
||||
|
if gapDuration < oneSnapshotInterval { |
||||
|
return snapshotsToRemove, snapshotsToGenerate, levelDbBootstrapPath, errors.New(fmt.Sprintf("last snapshot was generated at %v no need to generate new snapshots", lastSnapshotDate.Format(DateFormat))) |
||||
|
} else if gapDuration > totalSnapshotsInterval { |
||||
|
// gap too large generate from targetDate
|
||||
|
// and remove all previous snapshots
|
||||
|
_, snapshotsToGenerate, _, err = computeRequirementsFromEmpty(count, durationDays, targetDate) |
||||
|
for _, file := range previousSnapshots { |
||||
|
snapshotsToRemove = append(snapshotsToRemove, filepath.Join(homeDirectory, snapshotPath, file)) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
snapshotDate := lastSnapshotDate.AddDate(0, 0, durationDays) |
||||
|
for snapshotDate.Before(targetDate) || snapshotDate.Equal(targetDate) { |
||||
|
snapshotsToGenerate = append(snapshotsToGenerate, snapshotDate) |
||||
|
snapshotDate = snapshotDate.AddDate(0, 0, durationDays) |
||||
|
} |
||||
|
totalCount := len(previousSnapshots) + len(snapshotsToGenerate) |
||||
|
toRemoveIdx := 0 |
||||
|
for toRemoveIdx < len(previousSnapshots) && totalCount-toRemoveIdx > count { |
||||
|
snapshotsToRemove = append(snapshotsToRemove, filepath.Join(homeDirectory, snapshotPath, previousSnapshots[toRemoveIdx])) |
||||
|
toRemoveIdx += 1 |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func computeRequirementsFromEmpty(count int, durationDays int, targetDate time.Time) (snapshotsToRemove []string, snapshotsToGenerate []time.Time, levelDbBootstrapPath string, err error) { |
||||
|
snapshotDate := targetDate |
||||
|
for i := 0; i < count; i++ { |
||||
|
snapshotsToGenerate = append(snapshotsToGenerate, snapshotDate) |
||||
|
snapshotDate = snapshotDate.AddDate(0, 0, -1*durationDays) |
||||
|
} |
||||
|
return snapshotsToRemove, snapshotsToGenerate, "", nil |
||||
|
} |
||||
|
|
||||
|
// compute number of snapshot need to be generated and number of snapshots to remove from give directory.
|
||||
|
func computeRequirements(homeDirectory string, snapshotPath string, count int, durationDays int) (snapshotsToRemove []string, snapshotsToGenerate []time.Time, levelDbBootstrapPath string, err error) { |
||||
|
snapshotDirectory := filepath.Join(homeDirectory, snapshotPath) |
||||
|
files, _ := os.ReadDir(snapshotDirectory) |
||||
|
// sort files by name
|
||||
|
sort.Slice(files, func(i, j int) bool { |
||||
|
return files[i].Name() < files[j].Name() |
||||
|
}) |
||||
|
// filter for snapshots file name only
|
||||
|
var prevSnapshotFiles []string |
||||
|
for _, file := range files { |
||||
|
if strings.HasSuffix(file.Name(), SnapshotDirPostFix) { |
||||
|
prevSnapshotFiles = append(prevSnapshotFiles, file.Name()) |
||||
|
} |
||||
|
} |
||||
|
curDate := time.Now() |
||||
|
curDateStr := curDate.Format(DateFormat) |
||||
|
// ensure snapshot start at today 00:00 - 1ns
|
||||
|
today, err := time.Parse(DateFormat, curDateStr) |
||||
|
targetDate := today.Add(-1 * time.Nanosecond) |
||||
|
if len(prevSnapshotFiles) == 0 { |
||||
|
return computeRequirementsFromEmpty(count, durationDays, targetDate) |
||||
|
} |
||||
|
return computeRequirementsFromDirectory(prevSnapshotFiles, homeDirectory, snapshotPath, count, durationDays, targetDate) |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
package shell |
||||
|
|
||||
|
import ( |
||||
|
"github.com/stretchr/testify/assert" |
||||
|
"path/filepath" |
||||
|
"reflect" |
||||
|
"testing" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func TestComputeRequirementsFromDirectory(t *testing.T) { |
||||
|
homeDir := "home" |
||||
|
snapDir := "test" |
||||
|
// case1: we have previous snapshots, target date is relative close to the latest snapshot date, we will use previous snapshots to generate future snapshots and remove some previous snapshots.
|
||||
|
var prevSnapshots []string |
||||
|
prevSnapshots = append(prevSnapshots, "2022-01-01") |
||||
|
prevSnapshots = append(prevSnapshots, "2022-02-01") |
||||
|
prevSnapshots = append(prevSnapshots, "2022-03-01") |
||||
|
targetDate, _ := time.Parse(DateFormat, "2022-04-01") |
||||
|
targetDate = targetDate.Add(-1 * time.Nanosecond) |
||||
|
snapshotsToRemove, snapshotsToGenerate, levelDbBootstrapPath, err := computeRequirementsFromDirectory(prevSnapshots, homeDir, snapDir, 3, 15, targetDate) |
||||
|
assert.Nil(t, err) |
||||
|
assert.Equal(t, levelDbBootstrapPath, "2022-03-01", "latest previous snapshot should be 2022-03-01") |
||||
|
expectedToRemoveSnapshots := []string{filepath.Join(homeDir, snapDir, "2022-01-01"), filepath.Join(homeDir, snapDir, "2022-02-01")} |
||||
|
assert.True(t, reflect.DeepEqual(snapshotsToRemove, expectedToRemoveSnapshots)) |
||||
|
expectedSnapshotsGenerationDate := []string{"2022-03-16", "2022-03-31"} |
||||
|
for i, date := range expectedSnapshotsGenerationDate { |
||||
|
assert.Equal(t, snapshotsToGenerate[i].Format(DateFormat), date) |
||||
|
} |
||||
|
|
||||
|
// case2: we have previous snapshots, target date is too close to the latest snapshot date, no change will happen.
|
||||
|
targetDate, _ = time.Parse(DateFormat, "2022-03-02") |
||||
|
snapshotsToRemove, snapshotsToGenerate, levelDbBootstrapPath, err = computeRequirementsFromDirectory(prevSnapshots, "home", "test", 3, 15, targetDate) |
||||
|
assert.NotNil(t, err) |
||||
|
assert.Containsf(t, err.Error(), "no need to generate new snapshots", "expected error containing %q, got %s", "no need to generate new snapshots", err) |
||||
|
assert.Empty(t, snapshotsToRemove) |
||||
|
assert.Empty(t, snapshotsToGenerate) |
||||
|
assert.Equal(t, levelDbBootstrapPath, "2022-03-01", "latest previous snapshot should be 2022-03-01") |
||||
|
|
||||
|
// case3: we have previous snapshots, target date is too far out to the latest snapshot date, all previous snapshots will be removed, snapshots will be generated going backward starting on target date.
|
||||
|
targetDate, _ = time.Parse(DateFormat, "2022-12-01") |
||||
|
targetDate = targetDate.Add(-1 * time.Nanosecond) |
||||
|
snapshotsToRemove, snapshotsToGenerate, levelDbBootstrapPath, err = computeRequirementsFromDirectory(prevSnapshots, "home", "test", 3, 15, targetDate) |
||||
|
assert.Nil(t, err) |
||||
|
expectedToRemoveSnapshots = []string{filepath.Join(homeDir, snapDir, "2022-01-01"), filepath.Join(homeDir, snapDir, "2022-02-01"), filepath.Join(homeDir, snapDir, "2022-03-01")} |
||||
|
assert.True(t, reflect.DeepEqual(snapshotsToRemove, expectedToRemoveSnapshots)) |
||||
|
// we still need to skip all logs prior to 2022-03-02
|
||||
|
assert.Equal(t, levelDbBootstrapPath, "2022-03-01", "latest previous snapshot should be 2022-03-01") |
||||
|
expectedSnapshotsGenerationDate = []string{"2022-11-30", "2022-11-15", "2022-10-31"} |
||||
|
for i, date := range expectedSnapshotsGenerationDate { |
||||
|
assert.Equal(t, snapshotsToGenerate[i].Format(DateFormat), date) |
||||
|
} |
||||
|
|
||||
|
// case4: the target date is exactly n snapshots away from previous snapshot date
|
||||
|
targetDate, _ = time.Parse(DateFormat, "2022-03-04") |
||||
|
targetDate = targetDate.Add(-1 * time.Nanosecond) |
||||
|
snapshotsToRemove, snapshotsToGenerate, levelDbBootstrapPath, err = computeRequirementsFromDirectory(prevSnapshots, "home", "test", 3, 1, targetDate) |
||||
|
expectedToRemoveSnapshots = []string{filepath.Join(homeDir, snapDir, "2022-01-01"), filepath.Join(homeDir, snapDir, "2022-02-01")} |
||||
|
assert.True(t, reflect.DeepEqual(snapshotsToRemove, expectedToRemoveSnapshots)) |
||||
|
expectedSnapshotsGenerationDate = []string{"2022-03-02", "2022-03-03"} |
||||
|
for i, date := range expectedSnapshotsGenerationDate { |
||||
|
assert.Equal(t, snapshotsToGenerate[i].Format(DateFormat), date) |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue