Increase proliferation of the count bus to record runtime stats. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🤖 Supportability/Tests #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
187 lines
4.7 KiB
Go
187 lines
4.7 KiB
Go
package data
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/alcionai/clues"
|
|
|
|
"github.com/alcionai/corso/src/pkg/control"
|
|
"github.com/alcionai/corso/src/pkg/count"
|
|
"github.com/alcionai/corso/src/pkg/fault"
|
|
"github.com/alcionai/corso/src/pkg/path"
|
|
)
|
|
|
|
var ErrNotFound = clues.New("not found")
|
|
|
|
type CollectionState int
|
|
|
|
const (
|
|
NewState CollectionState = 0
|
|
NotMovedState CollectionState = 1
|
|
MovedState CollectionState = 2
|
|
DeletedState CollectionState = 3
|
|
)
|
|
|
|
type FetchRestoreCollection struct {
|
|
Collection
|
|
FetchItemByNamer
|
|
}
|
|
|
|
// NoFetchRestoreCollection is a wrapper for a Collection that returns
|
|
// ErrNotFound for all Fetch calls.
|
|
type NoFetchRestoreCollection struct {
|
|
Collection
|
|
}
|
|
|
|
func (c NoFetchRestoreCollection) FetchItemByName(context.Context, string) (Item, error) {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
// StateOf lets us figure out the state of the collection from the
|
|
// previous and current path
|
|
func StateOf(
|
|
prev, curr path.Path,
|
|
counter *count.Bus,
|
|
) CollectionState {
|
|
if curr == nil || len(curr.String()) == 0 {
|
|
counter.Inc(count.CollectionTombstoned)
|
|
return DeletedState
|
|
}
|
|
|
|
if prev == nil || len(prev.String()) == 0 {
|
|
counter.Inc(count.CollectionNew)
|
|
return NewState
|
|
}
|
|
|
|
if curr.String() != prev.String() {
|
|
counter.Inc(count.CollectionMoved)
|
|
return MovedState
|
|
}
|
|
|
|
counter.Inc(count.CollectionNotMoved)
|
|
|
|
return NotMovedState
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// BaseCollection
|
|
// -----------------------------------------------------------------------------
|
|
|
|
func NewBaseCollection(
|
|
curr, prev path.Path,
|
|
location *path.Builder,
|
|
ctrlOpts control.Options,
|
|
doNotMergeItems bool,
|
|
counter *count.Bus,
|
|
) BaseCollection {
|
|
return BaseCollection{
|
|
opts: ctrlOpts,
|
|
doNotMergeItems: doNotMergeItems,
|
|
fullPath: curr,
|
|
locationPath: location,
|
|
prevPath: prev,
|
|
state: StateOf(prev, curr, counter),
|
|
Counter: counter.Local(),
|
|
}
|
|
}
|
|
|
|
// BaseCollection contains basic functionality like returning path, location,
|
|
// and state information. It can be embedded in other implementations to provide
|
|
// this functionality.
|
|
//
|
|
// Functionality like how items are fetched is left to the embedding struct.
|
|
type BaseCollection struct {
|
|
opts control.Options
|
|
|
|
// FullPath is the current hierarchical path used by this collection.
|
|
fullPath path.Path
|
|
|
|
// PrevPath is the previous hierarchical path used by this collection.
|
|
// It may be the same as fullPath, if the folder was not renamed or
|
|
// moved. It will be empty on its first retrieval.
|
|
prevPath path.Path
|
|
|
|
// LocationPath contains the path with human-readable display names.
|
|
// IE: "/Inbox/Important" instead of "/abcdxyz123/algha=lgkhal=t"
|
|
locationPath *path.Builder
|
|
|
|
state CollectionState
|
|
|
|
// doNotMergeItems should only be true if the old delta token expired.
|
|
doNotMergeItems bool
|
|
|
|
Counter *count.Bus
|
|
}
|
|
|
|
// FullPath returns the BaseCollection's fullPath []string
|
|
func (col *BaseCollection) FullPath() path.Path {
|
|
return col.fullPath
|
|
}
|
|
|
|
// LocationPath produces the BaseCollection's full path, but with display names
|
|
// instead of IDs in the folders. Only populated for Calendars.
|
|
func (col *BaseCollection) LocationPath() *path.Builder {
|
|
return col.locationPath
|
|
}
|
|
|
|
func (col BaseCollection) PreviousPath() path.Path {
|
|
return col.prevPath
|
|
}
|
|
|
|
func (col BaseCollection) State() CollectionState {
|
|
return col.state
|
|
}
|
|
|
|
func (col BaseCollection) Category() path.CategoryType {
|
|
switch {
|
|
case col.FullPath() != nil:
|
|
return col.FullPath().Category()
|
|
case col.PreviousPath() != nil:
|
|
return col.PreviousPath().Category()
|
|
}
|
|
|
|
return path.UnknownCategory
|
|
}
|
|
|
|
func (col BaseCollection) DoNotMergeItems() bool {
|
|
return col.doNotMergeItems
|
|
}
|
|
|
|
func (col BaseCollection) Opts() control.Options {
|
|
return col.opts
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// tombstoneCollection
|
|
// -----------------------------------------------------------------------------
|
|
|
|
func NewTombstoneCollection(
|
|
prev path.Path,
|
|
opts control.Options,
|
|
counter *count.Bus,
|
|
) *tombstoneCollection {
|
|
return &tombstoneCollection{
|
|
BaseCollection: NewBaseCollection(
|
|
nil,
|
|
prev,
|
|
nil,
|
|
opts,
|
|
false,
|
|
counter),
|
|
}
|
|
}
|
|
|
|
// tombstoneCollection is a collection that marks a folder (and folders under it
|
|
// if they aren't explicitly noted in other collecteds) as deleted. It doesn't
|
|
// contain any items.
|
|
type tombstoneCollection struct {
|
|
BaseCollection
|
|
}
|
|
|
|
// Items never returns any data for tombstone collections because the collection
|
|
// only denotes the deletion of the current folder and possibly subfolders. All
|
|
// items contained in the deleted folder are also deleted.
|
|
func (col *tombstoneCollection) Items(context.Context, *fault.Bus) <-chan Item {
|
|
return nil
|
|
}
|