This commit is contained in:
2026-06-13 19:53:27 +03:00
parent 5778782737
commit 1d1fdb1f0b
19 changed files with 1508 additions and 858 deletions

View File

@@ -11,18 +11,18 @@ import (
)
var (
reChanges = regexp.MustCompile(`(\d+)\.changes`)
reChanges = regexp.MustCompile(`(\d+)\.wal`)
reSnapshot = regexp.MustCompile(`(\d+)\.snapshot`)
)
func joinChangesFileName(dir string, logNumber int) string {
return filepath.Join(dir, fmt.Sprintf("%d.changes", logNumber))
func joinWALFileName(dir string, snapshotNumber int) string {
return filepath.Join(dir, fmt.Sprintf("%d.wal", snapshotNumber))
}
type RecoveryRecipe struct {
Snapshot string
Changes []string
LogNumber int
SnapshotNumber int
ToDelete []string
CompleteSnapshot bool // флаг - что нужно завершить создание снапшота
}
@@ -52,8 +52,8 @@ func NewRecoveryAdvisor(opt RecoveryAdvisorOptions) (*RecoveryAdvisor, error) {
type SnapshotChangesPair struct {
SnapshotFileName string
ChangesFileName string
LogNumber int
WALFileName string
SnapshotNumber int
}
func (s *RecoveryAdvisor) getSnapshotChangesPairs() (*SnapshotChangesPair, *SnapshotChangesPair, error) {
@@ -89,21 +89,21 @@ func (s *RecoveryAdvisor) getSnapshotChangesPairs() (*SnapshotChangesPair, *Snap
}
}
for logNumber := range numSet {
for snapshotNumber := range numSet {
var (
snapshotFileName string
changesFileName string
)
if changesSet[logNumber] {
changesFileName = joinChangesFileName(s.dir, logNumber)
if changesSet[snapshotNumber] {
changesFileName = joinWALFileName(s.dir, snapshotNumber)
}
if snapshotsSet[logNumber] {
snapshotFileName = filepath.Join(s.dir, fmt.Sprintf("%d.snapshot", logNumber))
if snapshotsSet[snapshotNumber] {
snapshotFileName = filepath.Join(s.dir, fmt.Sprintf("%d.snapshot", snapshotNumber))
}
pairs = append(pairs, SnapshotChangesPair{
ChangesFileName: changesFileName,
WALFileName: changesFileName,
SnapshotFileName: snapshotFileName,
LogNumber: logNumber,
SnapshotNumber: snapshotNumber,
})
}
@@ -112,22 +112,22 @@ func (s *RecoveryAdvisor) getSnapshotChangesPairs() (*SnapshotChangesPair, *Snap
}
sort.Slice(pairs, func(i, j int) bool {
return pairs[i].LogNumber > pairs[j].LogNumber
return pairs[i].SnapshotNumber > pairs[j].SnapshotNumber
})
pair := pairs[0]
if pair.ChangesFileName == "" {
if pair.WALFileName == "" {
return nil, nil, fmt.Errorf("has %d.shapshot file, but %d.changes file not found",
pair.LogNumber, pair.LogNumber)
pair.SnapshotNumber, pair.SnapshotNumber)
}
if len(pairs) > 1 {
prevPair := pairs[1]
if prevPair.SnapshotFileName == "" && prevPair.LogNumber != 1 {
if prevPair.SnapshotFileName == "" && prevPair.SnapshotNumber != 1 {
return &pair, nil, nil
}
if prevPair.ChangesFileName == "" && pair.SnapshotFileName == "" {
if prevPair.WALFileName == "" && pair.SnapshotFileName == "" {
return &pair, nil, nil
}
return &pair, &prevPair, nil
@@ -157,14 +157,14 @@ func (s *RecoveryAdvisor) GetRecipe() (*RecoveryRecipe, error) {
recipe := &RecoveryRecipe{
Snapshot: pair.SnapshotFileName,
Changes: []string{
pair.ChangesFileName,
pair.WALFileName,
},
LogNumber: pair.LogNumber,
SnapshotNumber: pair.SnapshotNumber,
}
if prevPair != nil {
if prevPair.ChangesFileName != "" {
recipe.ToDelete = append(recipe.ToDelete, prevPair.ChangesFileName)
if prevPair.WALFileName != "" {
recipe.ToDelete = append(recipe.ToDelete, prevPair.WALFileName)
}
if prevPair.SnapshotFileName != "" {
recipe.ToDelete = append(recipe.ToDelete, prevPair.SnapshotFileName)
@@ -175,55 +175,55 @@ func (s *RecoveryAdvisor) GetRecipe() (*RecoveryRecipe, error) {
if prevPair != nil {
return s.tryPrevPair(pair, prevPair)
}
return nil, fmt.Errorf("%d.shapshot is corrupted", pair.LogNumber)
return nil, fmt.Errorf("%d.shapshot is corrupted", pair.SnapshotNumber)
} else {
if prevPair != nil {
return s.tryPrevPair(pair, prevPair)
} else {
if pair.LogNumber == 1 {
if pair.SnapshotNumber == 1 {
return &RecoveryRecipe{
Changes: []string{
pair.ChangesFileName,
pair.WALFileName,
},
LogNumber: pair.LogNumber,
SnapshotNumber: pair.SnapshotNumber,
}, nil
} else {
return nil, fmt.Errorf("%d.snapshot not found", pair.LogNumber)
return nil, fmt.Errorf("%d.snapshot not found", pair.SnapshotNumber)
}
}
}
}
func (s *RecoveryAdvisor) tryPrevPair(pair, prevPair *SnapshotChangesPair) (*RecoveryRecipe, error) {
if prevPair.ChangesFileName == "" {
if prevPair.WALFileName == "" {
if pair.SnapshotFileName != "" {
return nil, fmt.Errorf("%d.shapshot is corrupted and %d.changes not found",
pair.LogNumber, prevPair.LogNumber)
pair.SnapshotNumber, prevPair.SnapshotNumber)
} else {
return nil, fmt.Errorf("%d.changes not found", prevPair.LogNumber)
return nil, fmt.Errorf("%d.changes not found", prevPair.SnapshotNumber)
}
}
if prevPair.SnapshotFileName == "" {
if prevPair.LogNumber == 1 {
if prevPair.SnapshotNumber == 1 {
recipe := &RecoveryRecipe{
Changes: []string{
prevPair.ChangesFileName,
pair.ChangesFileName,
prevPair.WALFileName,
pair.WALFileName,
},
LogNumber: pair.LogNumber,
SnapshotNumber: pair.SnapshotNumber,
CompleteSnapshot: true,
ToDelete: []string{
prevPair.ChangesFileName,
prevPair.WALFileName,
},
}
return recipe, nil
} else {
if pair.SnapshotFileName != "" {
return nil, fmt.Errorf("%d.shapshot is corrupted and %d.snapshot not found",
pair.LogNumber, prevPair.LogNumber)
pair.SnapshotNumber, prevPair.SnapshotNumber)
} else {
return nil, fmt.Errorf("%d.snapshot not found", pair.LogNumber)
return nil, fmt.Errorf("%d.snapshot not found", pair.SnapshotNumber)
}
}
}
@@ -235,19 +235,19 @@ func (s *RecoveryAdvisor) tryPrevPair(pair, prevPair *SnapshotChangesPair) (*Rec
}
if !isVerified {
return nil, fmt.Errorf("%d.shapshot is corrupted", prevPair.LogNumber)
return nil, fmt.Errorf("%d.shapshot is corrupted", prevPair.SnapshotNumber)
}
recipe := &RecoveryRecipe{
Snapshot: prevPair.SnapshotFileName,
Changes: []string{
prevPair.ChangesFileName,
pair.ChangesFileName,
prevPair.WALFileName,
pair.WALFileName,
},
LogNumber: pair.LogNumber,
SnapshotNumber: pair.SnapshotNumber,
CompleteSnapshot: true,
ToDelete: []string{
prevPair.ChangesFileName,
prevPair.WALFileName,
prevPair.SnapshotFileName,
},
}