diff --git a/pkg/uploader/block/snapshot.go b/pkg/uploader/block/snapshot.go index 595a80fd5..a0823de8c 100644 --- a/pkg/uploader/block/snapshot.go +++ b/pkg/uploader/block/snapshot.go @@ -110,10 +110,10 @@ func snapshotSource( bitmap := cbt.NewBitmap(blockSize, uint64(source.size), cbtSource.Snapshot, parentBackup.changeID, parentBackup.volumeID) - err := cbt.SetBitmapOrFull(ctx, cbtService, bitmap) + err := cbt.SetBitmapOrFull(ctx, cbtService, bitmap, false) if err != nil { parentBackup.parentObject = "" - log.WithError(err).Warnf("Failed to create CBT with source %v, fallback to real full backup", cbtSource) + log.WithError(err).Warnf("Failed to create CBT with source %v", cbtSource) } snap, backupSize, err := u.Backup(source, parentBackup.parentObject, bitmap.Iterator(), uploaderCfg) @@ -218,16 +218,12 @@ func Restore(ctx context.Context, blkUp Uploader, rep udmrepo.BackupRepo, snapsh if incremental { if snapshot.Tags == nil { log.Warnf("No tag from snapshot %s, fallback to full restore", snapshotID) - incremental = false } else if snapshot.Tags[uploader.CBTChangeIDTag] == "" { log.Warnf("No ChangeID tag from snapshot %s, fallback to full restore", snapshotID) - incremental = false } else if snapshot.Tags[uploader.CBTVolumeIDTag] == "" { log.Warnf("No VolumeID tag from snapshot %s, fallback to full restore", snapshotID) - incremental = false } else if snapshot.Tags[uploader.CBTVolumeIDTag] != cbtSource.VolumeID { log.Warnf("VolumeID %s from snapshot %s is not expected as %s, fallback to full restore", snapshot.Tags[uploader.CBTVolumeIDTag], snapshotID, cbtSource.VolumeID) - incremental = false } else { volumeSnapshot = cbtSource.Snapshot changeID = snapshot.Tags[uploader.CBTChangeIDTag] @@ -237,8 +233,8 @@ func Restore(ctx context.Context, blkUp Uploader, rep udmrepo.BackupRepo, snapsh bitmap := cbt.NewBitmap(blockSize, uint64(snapshot.TotalSize), volumeSnapshot, changeID, volumeID) if incremental { - if err = cbt.SetBitmapOrFull(ctx, cbtService, bitmap); err != nil { - log.WithError(err).Warnf("Failed to create CBT with source %v, fallback to full restore", cbtSource) + if err = cbt.SetBitmapOrFull(ctx, cbtService, bitmap, true); err != nil { + log.WithError(err).Warnf("Failed to create CBT with source %v", cbtSource) } } else { bitmap.SetFull() diff --git a/pkg/uploader/cbt/bitmap.go b/pkg/uploader/cbt/bitmap.go index f26cb22b7..f1b4b3c7d 100644 --- a/pkg/uploader/cbt/bitmap.go +++ b/pkg/uploader/cbt/bitmap.go @@ -36,6 +36,7 @@ type bitmapImpl struct { snapshot string changeID string volumeID string + cbtError error } type bitmapIterator struct { @@ -89,6 +90,14 @@ func (c *bitmapImpl) VolumeID() string { return c.volumeID } +func (c *bitmapImpl) SetError(err error) { + c.cbtError = err +} + +func (c *bitmapImpl) Error() error { + return c.cbtError +} + func (c *bitmapImpl) Iterator() types.Iterator { if c.bitmap == nil { return nil @@ -115,3 +124,7 @@ func (c *bitmapIterator) Count() uint64 { func (c *bitmapIterator) BlockSize() uint { return c.blockSize } + +func (c *bitmapIterator) Error() error { + return c.cbtError +} diff --git a/pkg/uploader/cbt/set.go b/pkg/uploader/cbt/set.go index 11361cf77..be039d0c7 100644 --- a/pkg/uploader/cbt/set.go +++ b/pkg/uploader/cbt/set.go @@ -26,36 +26,70 @@ import ( ) // SetBitmapOrFull translates the allocated/changed blocks from CBT service to the given bitmap or set the bitmap to full when error happens -func SetBitmapOrFull(ctx context.Context, service cbtservice.Service, bitmap types.Bitmap) (err error) { +func SetBitmapOrFull(ctx context.Context, service cbtservice.Service, bitmap types.Bitmap, incOnly bool) (ret error) { + setFull := false + defer func() { - if err != nil { + bitmap.SetError(ret) + + if setFull { bitmap.SetFull() } }() if service == nil { - return errors.New("CBT service is absent") + setFull = true + return errors.New("CBT service is absent, fallback to real full") } if bitmap.Snapshot() == "" { - return errors.New("invalid snapshot") + setFull = true + return errors.New("invalid snapshot, fallback to real full") } - if bitmap.ChangeID() == "" { - return errors.Wrapf(service.GetAllocatedBlocks(ctx, bitmap.Snapshot(), func(blocks []cbtservice.Range) error { + if incOnly && bitmap.ChangeID() == "" { + setFull = true + return errors.New("invalid changeID, fallback to real full") + } + + var changedErr error + if bitmap.ChangeID() != "" { + err := service.GetChangedBlocks(ctx, bitmap.Snapshot(), bitmap.ChangeID(), func(blocks []cbtservice.Range) error { for _, b := range blocks { bitmap.Set(b.Offset, b.Length) } return nil - }), "error getting allocated blocks from CBT service") + }) + + if err == nil { + return nil + } + + if incOnly { + setFull = true + return errors.Wrap(err, "error getting changed blocks from CBT service, fallback to real full") + } + + changedErr = err } - return errors.Wrapf(service.GetChangedBlocks(ctx, bitmap.Snapshot(), bitmap.ChangeID(), func(blocks []cbtservice.Range) error { + err := service.GetAllocatedBlocks(ctx, bitmap.Snapshot(), func(blocks []cbtservice.Range) error { for _, b := range blocks { bitmap.Set(b.Offset, b.Length) } return nil - }), "error getting changed blocks from CBT service") + }) + + if err != nil { + setFull = true + return errors.Wrap(err, "error getting allocated blocks from CBT service, fallback to real full") + } + + if changedErr != nil { + return errors.Wrap(changedErr, "error getting changed blocks from CBT service, fallback to full") + } + + return nil } diff --git a/pkg/uploader/cbt/types/types.go b/pkg/uploader/cbt/types/types.go index 9b13669b2..447c3f9f3 100644 --- a/pkg/uploader/cbt/types/types.go +++ b/pkg/uploader/cbt/types/types.go @@ -35,6 +35,12 @@ type Bitmap interface { // Iterator returns the iterator for the CBT Bitmap Iterator() Iterator + + // SetError sets CBT error when preparing this bitmap + SetError(error) + + // Error returns the CBT error when preparing this bitmap + Error() error } // Iterator defines the methods to iterate the CBT bitmap and query the associated information @@ -56,4 +62,7 @@ type Iterator interface { // Next returns the offset of the next set block and whether it comes to the end of the iteration Next() (uint64, bool) + + // Error returns the CBT error when preparing this bitmap + Error() error }