## Description In order for corso to track recoverable errors, we need to pass a fault.Errors struct into the items stream. As long as we're doing that, we might as well pass along the available ctx as well. ## Does this PR need a docs update or release note? - [x] ⛔ No ## Type of change - [x] 🧹 Tech Debt/Cleanup ## Issue(s) * #1970 ## Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
140 lines
4.7 KiB
Go
140 lines
4.7 KiB
Go
package data
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
|
"github.com/alcionai/corso/src/pkg/fault"
|
|
"github.com/alcionai/corso/src/pkg/path"
|
|
)
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// standard ifaces
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
var ErrNotFound = errors.New("not found")
|
|
|
|
type CollectionState int
|
|
|
|
const (
|
|
NewState = CollectionState(iota)
|
|
NotMovedState
|
|
MovedState
|
|
DeletedState
|
|
)
|
|
|
|
// A Collection represents the set of data within a single logical location
|
|
// denoted by FullPath.
|
|
type Collection interface {
|
|
// Items returns a channel from which items in the collection can be read.
|
|
// Each returned struct contains the next item in the collection
|
|
// The channel is closed when there are no more items in the collection or if
|
|
// an unrecoverable error caused an early termination in the sender.
|
|
Items(ctx context.Context, errs *fault.Errors) <-chan Stream
|
|
// FullPath returns a path struct that acts as a metadata tag for this
|
|
// Collection.
|
|
FullPath() path.Path
|
|
}
|
|
|
|
// BackupCollection is an extension of Collection that is used during backups.
|
|
type BackupCollection interface {
|
|
Collection
|
|
// PreviousPath returns the path.Path this collection used to reside at
|
|
// (according to the M365 ID for the container) if the collection was moved or
|
|
// renamed. Returns nil if the collection is new.
|
|
PreviousPath() path.Path
|
|
// State represents changes to the Collection compared to the last backup
|
|
// involving the Collection. State changes are based on the M365 ID of the
|
|
// Collection, not just the path the collection resides at. Collections that
|
|
// are in the same location as they were in the previous backup should be
|
|
// marked as NotMovedState. Renaming or reparenting the Collection counts as
|
|
// Moved. Collections marked as Deleted will be removed from the current
|
|
// backup along with all items and Collections below them in the hierarchy
|
|
// unless said items/Collections were moved.
|
|
State() CollectionState
|
|
// DoNotMergeItems informs kopia that the collection is rebuilding its contents
|
|
// from scratch, and that any items currently stored at the previousPath should
|
|
// be skipped during the process of merging historical data into the new backup.
|
|
// This flag is normally expected to be false. It should only be flagged under
|
|
// specific circumstances. Example: if the link token used for incremental queries
|
|
// expires or otherwise becomes unusable, thus requiring the backup producer to
|
|
// re-discover all data in the container. This flag only affects the path of the
|
|
// collection, and does not cascade to subfolders.
|
|
DoNotMergeItems() bool
|
|
}
|
|
|
|
// RestoreCollection is an extension of Collection that is used during restores.
|
|
type RestoreCollection interface {
|
|
Collection
|
|
// Fetch retrieves an item with the given name from the Collection if it
|
|
// exists. Items retrieved with Fetch may still appear in the channel returned
|
|
// by Items().
|
|
Fetch(ctx context.Context, name string) (Stream, error)
|
|
}
|
|
|
|
// NotFoundRestoreCollection is a wrapper for a Collection that returns
|
|
// ErrNotFound for all Fetch calls.
|
|
type NotFoundRestoreCollection struct {
|
|
Collection
|
|
}
|
|
|
|
func (c NotFoundRestoreCollection) Fetch(context.Context, string) (Stream, error) {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
// Stream represents a single item within a Collection
|
|
// that can be consumed as a stream (it embeds io.Reader)
|
|
type Stream interface {
|
|
// ToReader returns an io.Reader for the DataStream
|
|
ToReader() io.ReadCloser
|
|
// UUID provides a unique identifier for this data
|
|
UUID() string
|
|
// Deleted returns true if the item represented by this Stream has been
|
|
// deleted and should be removed from the current in-progress backup.
|
|
Deleted() bool
|
|
}
|
|
|
|
// LocationPather provides a LocationPath describing the path with Display Names
|
|
// instead of canonical IDs
|
|
type LocationPather interface {
|
|
LocationPath() path.Path
|
|
}
|
|
|
|
// StreamInfo is used to provide service specific
|
|
// information about the Stream
|
|
type StreamInfo interface {
|
|
Info() details.ItemInfo
|
|
}
|
|
|
|
// StreamSize is used to provide size
|
|
// information about the Stream
|
|
type StreamSize interface {
|
|
Size() int64
|
|
}
|
|
|
|
// StreamModTime is used to provide the modified time of the stream's data.
|
|
type StreamModTime interface {
|
|
ModTime() time.Time
|
|
}
|
|
|
|
// StateOf lets us figure out the state of the collection from the
|
|
// previous and current path
|
|
func StateOf(prev, curr path.Path) CollectionState {
|
|
if curr == nil || len(curr.String()) == 0 {
|
|
return DeletedState
|
|
}
|
|
|
|
if prev == nil || len(prev.String()) == 0 {
|
|
return NewState
|
|
}
|
|
|
|
if curr.Folder(false) != prev.Folder(false) {
|
|
return MovedState
|
|
}
|
|
|
|
return NotMovedState
|
|
}
|