diff --git a/nodestorage/spacestorage.go b/nodestorage/spacestorage.go index d8f9f9c..d9ff393 100644 --- a/nodestorage/spacestorage.go +++ b/nodestorage/spacestorage.go @@ -22,12 +22,25 @@ type ChangeSizeStats struct { Total int `json:"total"` } +type PerObjectSizeStats struct { + LenTotalMax int `json:"len"` + LenTotalP95 float64 `json:"lenTotalP95"` + LenTotalMedian float64 `json:"lenTotalMedian"` + SizeTotalMax int `json:"sizeTotal"` + SizeTotalP95 float64 `json:"SizeTotalP95"` + SizeTotalMedian float64 `json:"SizeTotalMedian"` + SizeMax int `json:"sizeMax"` + SizeP95 float64 `json:"sizeP95"` + SizeMedian float64 `json:"sizeMedian"` +} + type ObjectSpaceStats struct { - ObjectsCount int `json:"objectsCount,omitempty"` - DeletedObjectsCount int `json:"deletedObjectsCount"` - ChangesCount int `json:"changesCount"` - ChangeSize ChangeSizeStats `json:"changeSizeStats,omitempty"` - TreeStats []TreeStat `json:"treeStats,omitempty"` + ObjectsCount int `json:"objectsCount,omitempty"` + DeletedObjectsCount int `json:"deletedObjectsCount"` + ChangesCount int `json:"changesCount"` + ChangeSize ChangeSizeStats `json:"changeSizeStats,omitempty"` + PerObjectSize PerObjectSizeStats `json:"perObjectSizeStats,omitempty"` + TreeStats []TreeStat `json:"treeStats,omitempty"` treeMap map[string]TreeStat } @@ -37,6 +50,7 @@ type TreeStat struct { SnapshotsCount int `json:"snapshotsCount"` MaxSnapshotCounter int `json:"maxSnapshotCounter"` ChangesSumSize int `json:"payloadSize"` + ChangeMaxSize int `json:"changeMaxSize"` } type SpaceStats struct { diff --git a/nodestorage/stat.go b/nodestorage/stat.go index 9f6478a..7797a4f 100644 --- a/nodestorage/stat.go +++ b/nodestorage/stat.go @@ -4,7 +4,6 @@ import ( "cmp" "context" "fmt" - anystore "github.com/anyproto/any-store" "github.com/anyproto/any-store/query" "github.com/anyproto/any-sync/commonspace/headsync/headstorage" @@ -69,6 +68,9 @@ func (r *nodeStorage) GetSpaceStats(ctx context.Context, treeTop int) (spaceStat lengths = append(lengths, chSize) snapshotCounter := doc.Value().GetInt(objecttree.SnapshotCounterKey) treeStat.ChangesSumSize += chSize + if treeStat.ChangeMaxSize > chSize { + treeStat.ChangeMaxSize = chSize + } changesSize += chSize if snapshotCounter > treeStat.MaxSnapshotCounter { treeStat.MaxSnapshotCounter = snapshotCounter @@ -94,6 +96,7 @@ func (r *nodeStorage) GetSpaceStats(ctx context.Context, treeTop int) (spaceStat if len(lengths) > 0 { spaceStats.ChangeSize.MaxLen = lengths[len(lengths)-1] } + calculateStatsPerObject(&spaceStats) spaceStats.ChangeSize.Total = changesSize if treeTop > 0 { @@ -115,6 +118,33 @@ func (r *nodeStorage) GetSpaceStats(ctx context.Context, treeTop int) (spaceStat return } +func calculateStatsPerObject(stats *ObjectSpaceStats) { + var changesCounts []int + var changesSumSizes []int + var changesMaxSizes []int + + for _, stat := range stats.treeMap { + changesCounts = append(changesCounts, stat.ChangesCount) + changesSumSizes = append(changesSumSizes, stat.ChangesSumSize) + changesMaxSizes = append(changesMaxSizes, stat.ChangeMaxSize) + } + + slices.Sort(changesCounts) + stats.PerObjectSize.LenTotalMax = changesCounts[len(changesCounts)-1] + stats.PerObjectSize.LenTotalP95 = calcP95(changesCounts) + stats.PerObjectSize.LenTotalMedian = calcMedian(changesCounts) + + slices.Sort(changesSumSizes) + stats.PerObjectSize.SizeTotalMax = changesSumSizes[len(changesSumSizes)-1] + stats.PerObjectSize.SizeTotalP95 = calcP95(changesSumSizes) + stats.PerObjectSize.SizeTotalMedian = calcMedian(changesSumSizes) + + slices.Sort(changesMaxSizes) + stats.PerObjectSize.SizeMax = changesSumSizes[len(changesMaxSizes)-1] + stats.PerObjectSize.SizeP95 = calcP95(changesMaxSizes) + stats.PerObjectSize.SizeMedian = calcMedian(changesMaxSizes) +} + func calcMedian(sortedLengths []int) (median float64) { mid := len(sortedLengths) / 2 if len(sortedLengths)%2 == 0 {