github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/data-usage-cache.go (about)

     1  // Copyright (c) 2015-2023 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"bytes"
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"io"
    26  	"math/rand"
    27  	"net/http"
    28  	"path"
    29  	"path/filepath"
    30  	"sort"
    31  	"strings"
    32  	"time"
    33  
    34  	"github.com/cespare/xxhash/v2"
    35  	"github.com/dustin/go-humanize"
    36  	"github.com/klauspost/compress/zstd"
    37  	"github.com/minio/madmin-go/v3"
    38  	"github.com/minio/minio/internal/bucket/lifecycle"
    39  	"github.com/minio/minio/internal/hash"
    40  	"github.com/minio/minio/internal/logger"
    41  	"github.com/tinylib/msgp/msgp"
    42  	"github.com/valyala/bytebufferpool"
    43  )
    44  
    45  //go:generate msgp -file $GOFILE -unexported
    46  
    47  // dataUsageHash is the hash type used.
    48  type dataUsageHash string
    49  
    50  // sizeHistogramV1 is size histogram V1, which has fewer intervals esp. between
    51  // 1024B and 1MiB.
    52  type sizeHistogramV1 [dataUsageBucketLenV1]uint64
    53  
    54  // sizeHistogram is a size histogram.
    55  type sizeHistogram [dataUsageBucketLen]uint64
    56  
    57  // versionsHistogram is a histogram of number of versions in an object.
    58  type versionsHistogram [dataUsageVersionLen]uint64
    59  
    60  type dataUsageEntry struct {
    61  	Children dataUsageHashMap `msg:"ch"`
    62  	// These fields do no include any children.
    63  	Size             int64                `msg:"sz"`
    64  	Objects          uint64               `msg:"os"`
    65  	Versions         uint64               `msg:"vs"` // Versions that are not delete markers.
    66  	DeleteMarkers    uint64               `msg:"dms"`
    67  	ObjSizes         sizeHistogram        `msg:"szs"`
    68  	ObjVersions      versionsHistogram    `msg:"vh"`
    69  	ReplicationStats *replicationAllStats `msg:"rs,omitempty"`
    70  	AllTierStats     *allTierStats        `msg:"ats,omitempty"`
    71  	Compacted        bool                 `msg:"c"`
    72  }
    73  
    74  // allTierStats is a collection of per-tier stats across all configured remote
    75  // tiers.
    76  type allTierStats struct {
    77  	Tiers map[string]tierStats `msg:"ts"`
    78  }
    79  
    80  func newAllTierStats() *allTierStats {
    81  	return &allTierStats{
    82  		Tiers: make(map[string]tierStats),
    83  	}
    84  }
    85  
    86  func (ats *allTierStats) addSizes(tiers map[string]tierStats) {
    87  	for tier, st := range tiers {
    88  		ats.Tiers[tier] = ats.Tiers[tier].add(st)
    89  	}
    90  }
    91  
    92  func (ats *allTierStats) merge(other *allTierStats) {
    93  	for tier, st := range other.Tiers {
    94  		ats.Tiers[tier] = ats.Tiers[tier].add(st)
    95  	}
    96  }
    97  
    98  func (ats *allTierStats) clone() *allTierStats {
    99  	if ats == nil {
   100  		return nil
   101  	}
   102  	dst := *ats
   103  	dst.Tiers = make(map[string]tierStats, len(ats.Tiers))
   104  	for tier, st := range ats.Tiers {
   105  		dst.Tiers[tier] = st
   106  	}
   107  	return &dst
   108  }
   109  
   110  func (ats *allTierStats) populateStats(stats map[string]madmin.TierStats) {
   111  	if ats == nil {
   112  		return
   113  	}
   114  
   115  	// Update stats for tiers as they become available.
   116  	for tier, st := range ats.Tiers {
   117  		stats[tier] = madmin.TierStats{
   118  			TotalSize:   st.TotalSize,
   119  			NumVersions: st.NumVersions,
   120  			NumObjects:  st.NumObjects,
   121  		}
   122  	}
   123  	return
   124  }
   125  
   126  // tierStats holds per-tier stats of a remote tier.
   127  type tierStats struct {
   128  	TotalSize   uint64 `msg:"ts"`
   129  	NumVersions int    `msg:"nv"`
   130  	NumObjects  int    `msg:"no"`
   131  }
   132  
   133  func (ts tierStats) add(u tierStats) tierStats {
   134  	return tierStats{
   135  		TotalSize:   ts.TotalSize + u.TotalSize,
   136  		NumVersions: ts.NumVersions + u.NumVersions,
   137  		NumObjects:  ts.NumObjects + u.NumObjects,
   138  	}
   139  }
   140  
   141  //msgp:tuple replicationStatsV1
   142  type replicationStatsV1 struct {
   143  	PendingSize          uint64
   144  	ReplicatedSize       uint64
   145  	FailedSize           uint64
   146  	ReplicaSize          uint64
   147  	FailedCount          uint64
   148  	PendingCount         uint64
   149  	MissedThresholdSize  uint64
   150  	AfterThresholdSize   uint64
   151  	MissedThresholdCount uint64
   152  	AfterThresholdCount  uint64
   153  }
   154  
   155  func (rsv1 replicationStatsV1) Empty() bool {
   156  	return rsv1.ReplicatedSize == 0 &&
   157  		rsv1.FailedSize == 0 &&
   158  		rsv1.FailedCount == 0
   159  }
   160  
   161  //msgp:tuple replicationStats
   162  type replicationStats struct {
   163  	PendingSize          uint64
   164  	ReplicatedSize       uint64
   165  	FailedSize           uint64
   166  	FailedCount          uint64
   167  	PendingCount         uint64
   168  	MissedThresholdSize  uint64
   169  	AfterThresholdSize   uint64
   170  	MissedThresholdCount uint64
   171  	AfterThresholdCount  uint64
   172  	ReplicatedCount      uint64
   173  }
   174  
   175  func (rs replicationStats) Empty() bool {
   176  	return rs.ReplicatedSize == 0 &&
   177  		rs.FailedSize == 0 &&
   178  		rs.FailedCount == 0
   179  }
   180  
   181  type replicationAllStats struct {
   182  	Targets      map[string]replicationStats `msg:"t,omitempty"`
   183  	ReplicaSize  uint64                      `msg:"r,omitempty"`
   184  	ReplicaCount uint64                      `msg:"rc,omitempty"`
   185  }
   186  
   187  //msgp:tuple replicationAllStatsV1
   188  type replicationAllStatsV1 struct {
   189  	Targets      map[string]replicationStats
   190  	ReplicaSize  uint64 `msg:"ReplicaSize,omitempty"`
   191  	ReplicaCount uint64 `msg:"ReplicaCount,omitempty"`
   192  }
   193  
   194  // empty returns true if the replicationAllStats is empty (contains no entries).
   195  func (r *replicationAllStats) empty() bool {
   196  	if r == nil {
   197  		return true
   198  	}
   199  	if r.ReplicaSize != 0 || r.ReplicaCount != 0 {
   200  		return false
   201  	}
   202  	for _, v := range r.Targets {
   203  		if !v.Empty() {
   204  			return false
   205  		}
   206  	}
   207  	return true
   208  }
   209  
   210  // clone creates a deep-copy clone.
   211  func (r *replicationAllStats) clone() *replicationAllStats {
   212  	if r == nil {
   213  		return nil
   214  	}
   215  
   216  	// Shallow copy
   217  	dst := *r
   218  
   219  	// Copy individual targets.
   220  	dst.Targets = make(map[string]replicationStats, len(r.Targets))
   221  	for k, v := range r.Targets {
   222  		dst.Targets[k] = v
   223  	}
   224  
   225  	return &dst
   226  }
   227  
   228  //msgp:encode ignore dataUsageEntryV2 dataUsageEntryV3 dataUsageEntryV4 dataUsageEntryV5 dataUsageEntryV6 dataUsageEntryV7
   229  //msgp:marshal ignore dataUsageEntryV2 dataUsageEntryV3 dataUsageEntryV4 dataUsageEntryV5 dataUsageEntryV6 dataUsageEntryV7
   230  
   231  //msgp:tuple dataUsageEntryV2
   232  type dataUsageEntryV2 struct {
   233  	// These fields do no include any children.
   234  	Size     int64
   235  	Objects  uint64
   236  	ObjSizes sizeHistogram
   237  	Children dataUsageHashMap
   238  }
   239  
   240  //msgp:tuple dataUsageEntryV3
   241  type dataUsageEntryV3 struct {
   242  	// These fields do no include any children.
   243  	Size                   int64
   244  	ReplicatedSize         uint64
   245  	ReplicationPendingSize uint64
   246  	ReplicationFailedSize  uint64
   247  	ReplicaSize            uint64
   248  	Objects                uint64
   249  	ObjSizes               sizeHistogram
   250  	Children               dataUsageHashMap
   251  }
   252  
   253  //msgp:tuple dataUsageEntryV4
   254  type dataUsageEntryV4 struct {
   255  	Children dataUsageHashMap
   256  	// These fields do no include any children.
   257  	Size             int64
   258  	Objects          uint64
   259  	ObjSizes         sizeHistogram
   260  	ReplicationStats replicationStatsV1
   261  }
   262  
   263  //msgp:tuple dataUsageEntryV5
   264  type dataUsageEntryV5 struct {
   265  	Children dataUsageHashMap
   266  	// These fields do no include any children.
   267  	Size             int64
   268  	Objects          uint64
   269  	Versions         uint64 // Versions that are not delete markers.
   270  	ObjSizes         sizeHistogram
   271  	ReplicationStats *replicationStatsV1
   272  	Compacted        bool
   273  }
   274  
   275  //msgp:tuple dataUsageEntryV6
   276  type dataUsageEntryV6 struct {
   277  	Children dataUsageHashMap
   278  	// These fields do no include any children.
   279  	Size             int64
   280  	Objects          uint64
   281  	Versions         uint64 // Versions that are not delete markers.
   282  	ObjSizes         sizeHistogram
   283  	ReplicationStats *replicationAllStatsV1
   284  	Compacted        bool
   285  }
   286  
   287  type dataUsageEntryV7 struct {
   288  	Children dataUsageHashMap `msg:"ch"`
   289  	// These fields do no include any children.
   290  	Size             int64                `msg:"sz"`
   291  	Objects          uint64               `msg:"os"`
   292  	Versions         uint64               `msg:"vs"` // Versions that are not delete markers.
   293  	DeleteMarkers    uint64               `msg:"dms"`
   294  	ObjSizes         sizeHistogramV1      `msg:"szs"`
   295  	ObjVersions      versionsHistogram    `msg:"vh"`
   296  	ReplicationStats *replicationAllStats `msg:"rs,omitempty"`
   297  	AllTierStats     *allTierStats        `msg:"ats,omitempty"`
   298  	Compacted        bool                 `msg:"c"`
   299  }
   300  
   301  // dataUsageCache contains a cache of data usage entries latest version.
   302  type dataUsageCache struct {
   303  	Info  dataUsageCacheInfo
   304  	Cache map[string]dataUsageEntry
   305  }
   306  
   307  //msgp:encode ignore dataUsageCacheV2 dataUsageCacheV3 dataUsageCacheV4 dataUsageCacheV5 dataUsageCacheV6 dataUsageCacheV7
   308  //msgp:marshal ignore dataUsageCacheV2 dataUsageCacheV3 dataUsageCacheV4 dataUsageCacheV5 dataUsageCacheV6 dataUsageCacheV7
   309  
   310  // dataUsageCacheV2 contains a cache of data usage entries version 2.
   311  type dataUsageCacheV2 struct {
   312  	Info  dataUsageCacheInfo
   313  	Cache map[string]dataUsageEntryV2
   314  }
   315  
   316  // dataUsageCacheV3 contains a cache of data usage entries version 3.
   317  type dataUsageCacheV3 struct {
   318  	Info  dataUsageCacheInfo
   319  	Cache map[string]dataUsageEntryV3
   320  }
   321  
   322  // dataUsageCacheV4 contains a cache of data usage entries version 4.
   323  type dataUsageCacheV4 struct {
   324  	Info  dataUsageCacheInfo
   325  	Cache map[string]dataUsageEntryV4
   326  }
   327  
   328  // dataUsageCacheV5 contains a cache of data usage entries version 5.
   329  type dataUsageCacheV5 struct {
   330  	Info  dataUsageCacheInfo
   331  	Cache map[string]dataUsageEntryV5
   332  }
   333  
   334  // dataUsageCacheV6 contains a cache of data usage entries version 6.
   335  type dataUsageCacheV6 struct {
   336  	Info  dataUsageCacheInfo
   337  	Cache map[string]dataUsageEntryV6
   338  }
   339  
   340  // dataUsageCacheV7 contains a cache of data usage entries version 7.
   341  type dataUsageCacheV7 struct {
   342  	Info  dataUsageCacheInfo
   343  	Cache map[string]dataUsageEntryV7
   344  }
   345  
   346  //msgp:ignore dataUsageEntryInfo
   347  type dataUsageEntryInfo struct {
   348  	Name   string
   349  	Parent string
   350  	Entry  dataUsageEntry
   351  }
   352  
   353  type dataUsageCacheInfo struct {
   354  	// Name of the bucket. Also root element.
   355  	Name       string
   356  	NextCycle  uint32
   357  	LastUpdate time.Time
   358  	// indicates if the disk is being healed and scanner
   359  	// should skip healing the disk
   360  	SkipHealing bool
   361  
   362  	// Active lifecycle, if any on the bucket
   363  	lifeCycle *lifecycle.Lifecycle `msg:"-"`
   364  
   365  	// optional updates channel.
   366  	// If set updates will be sent regularly to this channel.
   367  	// Will not be closed when returned.
   368  	updates     chan<- dataUsageEntry `msg:"-"`
   369  	replication replicationConfig     `msg:"-"`
   370  }
   371  
   372  func (e *dataUsageEntry) addSizes(summary sizeSummary) {
   373  	e.Size += summary.totalSize
   374  	e.Versions += summary.versions
   375  	e.DeleteMarkers += summary.deleteMarkers
   376  	e.ObjSizes.add(summary.totalSize)
   377  	e.ObjVersions.add(summary.versions)
   378  
   379  	if e.ReplicationStats == nil {
   380  		e.ReplicationStats = &replicationAllStats{
   381  			Targets: make(map[string]replicationStats),
   382  		}
   383  	} else if e.ReplicationStats.Targets == nil {
   384  		e.ReplicationStats.Targets = make(map[string]replicationStats)
   385  	}
   386  	e.ReplicationStats.ReplicaSize += uint64(summary.replicaSize)
   387  	e.ReplicationStats.ReplicaCount += uint64(summary.replicaCount)
   388  
   389  	for arn, st := range summary.replTargetStats {
   390  		tgtStat, ok := e.ReplicationStats.Targets[arn]
   391  		if !ok {
   392  			tgtStat = replicationStats{}
   393  		}
   394  		tgtStat.PendingSize += uint64(st.pendingSize)
   395  		tgtStat.FailedSize += uint64(st.failedSize)
   396  		tgtStat.ReplicatedSize += uint64(st.replicatedSize)
   397  		tgtStat.ReplicatedCount += uint64(st.replicatedCount)
   398  		tgtStat.FailedCount += st.failedCount
   399  		tgtStat.PendingCount += st.pendingCount
   400  		e.ReplicationStats.Targets[arn] = tgtStat
   401  	}
   402  	if len(summary.tiers) != 0 {
   403  		if e.AllTierStats == nil {
   404  			e.AllTierStats = newAllTierStats()
   405  		}
   406  		e.AllTierStats.addSizes(summary.tiers)
   407  	}
   408  }
   409  
   410  // merge other data usage entry into this, excluding children.
   411  func (e *dataUsageEntry) merge(other dataUsageEntry) {
   412  	e.Objects += other.Objects
   413  	e.Versions += other.Versions
   414  	e.DeleteMarkers += other.DeleteMarkers
   415  	e.Size += other.Size
   416  	if other.ReplicationStats != nil {
   417  		if e.ReplicationStats == nil {
   418  			e.ReplicationStats = &replicationAllStats{Targets: make(map[string]replicationStats)}
   419  		} else if e.ReplicationStats.Targets == nil {
   420  			e.ReplicationStats.Targets = make(map[string]replicationStats)
   421  		}
   422  		e.ReplicationStats.ReplicaSize += other.ReplicationStats.ReplicaSize
   423  		e.ReplicationStats.ReplicaCount += other.ReplicationStats.ReplicaCount
   424  		for arn, stat := range other.ReplicationStats.Targets {
   425  			st := e.ReplicationStats.Targets[arn]
   426  			e.ReplicationStats.Targets[arn] = replicationStats{
   427  				PendingSize:     stat.PendingSize + st.PendingSize,
   428  				FailedSize:      stat.FailedSize + st.FailedSize,
   429  				ReplicatedSize:  stat.ReplicatedSize + st.ReplicatedSize,
   430  				PendingCount:    stat.PendingCount + st.PendingCount,
   431  				FailedCount:     stat.FailedCount + st.FailedCount,
   432  				ReplicatedCount: stat.ReplicatedCount + st.ReplicatedCount,
   433  			}
   434  		}
   435  	}
   436  
   437  	for i, v := range other.ObjSizes[:] {
   438  		e.ObjSizes[i] += v
   439  	}
   440  
   441  	for i, v := range other.ObjVersions[:] {
   442  		e.ObjVersions[i] += v
   443  	}
   444  
   445  	if other.AllTierStats != nil && len(other.AllTierStats.Tiers) != 0 {
   446  		if e.AllTierStats == nil {
   447  			e.AllTierStats = newAllTierStats()
   448  		}
   449  		e.AllTierStats.merge(other.AllTierStats)
   450  	}
   451  }
   452  
   453  // mod returns true if the hash mod cycles == cycle.
   454  // If cycles is 0 false is always returned.
   455  // If cycles is 1 true is always returned (as expected).
   456  func (h dataUsageHash) mod(cycle uint32, cycles uint32) bool {
   457  	if cycles <= 1 {
   458  		return cycles == 1
   459  	}
   460  	return uint32(xxhash.Sum64String(string(h)))%cycles == cycle%cycles
   461  }
   462  
   463  // modAlt returns true if the hash mod cycles == cycle.
   464  // This is out of sync with mod.
   465  // If cycles is 0 false is always returned.
   466  // If cycles is 1 true is always returned (as expected).
   467  func (h dataUsageHash) modAlt(cycle uint32, cycles uint32) bool {
   468  	if cycles <= 1 {
   469  		return cycles == 1
   470  	}
   471  	return uint32(xxhash.Sum64String(string(h))>>32)%(cycles) == cycle%cycles
   472  }
   473  
   474  // addChild will add a child based on its hash.
   475  // If it already exists it will not be added again.
   476  func (e *dataUsageEntry) addChild(hash dataUsageHash) {
   477  	if _, ok := e.Children[hash.Key()]; ok {
   478  		return
   479  	}
   480  	if e.Children == nil {
   481  		e.Children = make(dataUsageHashMap, 1)
   482  	}
   483  	e.Children[hash.Key()] = struct{}{}
   484  }
   485  
   486  // Create a clone of the entry.
   487  func (e dataUsageEntry) clone() dataUsageEntry {
   488  	// We operate on a copy from the receiver.
   489  	if e.Children != nil {
   490  		ch := make(dataUsageHashMap, len(e.Children))
   491  		for k, v := range e.Children {
   492  			ch[k] = v
   493  		}
   494  		e.Children = ch
   495  	}
   496  	if e.ReplicationStats != nil {
   497  		// Clone ReplicationStats
   498  		e.ReplicationStats = e.ReplicationStats.clone()
   499  	}
   500  	if e.AllTierStats != nil {
   501  		e.AllTierStats = e.AllTierStats.clone()
   502  	}
   503  	return e
   504  }
   505  
   506  // find a path in the cache.
   507  // Returns nil if not found.
   508  func (d *dataUsageCache) find(path string) *dataUsageEntry {
   509  	due, ok := d.Cache[hashPath(path).Key()]
   510  	if !ok {
   511  		return nil
   512  	}
   513  	return &due
   514  }
   515  
   516  // isCompacted returns whether an entry is compacted.
   517  // Returns false if not found.
   518  func (d *dataUsageCache) isCompacted(h dataUsageHash) bool {
   519  	due, ok := d.Cache[h.Key()]
   520  	if !ok {
   521  		return false
   522  	}
   523  	return due.Compacted
   524  }
   525  
   526  // findChildrenCopy returns a copy of the children of the supplied hash.
   527  func (d *dataUsageCache) findChildrenCopy(h dataUsageHash) dataUsageHashMap {
   528  	ch := d.Cache[h.String()].Children
   529  	res := make(dataUsageHashMap, len(ch))
   530  	for k := range ch {
   531  		res[k] = struct{}{}
   532  	}
   533  	return res
   534  }
   535  
   536  // searchParent will search for the parent of h.
   537  // This is an O(N*N) operation if there is no parent or it cannot be guessed.
   538  func (d *dataUsageCache) searchParent(h dataUsageHash) *dataUsageHash {
   539  	want := h.Key()
   540  	if idx := strings.LastIndexByte(want, '/'); idx >= 0 {
   541  		if v := d.find(want[:idx]); v != nil {
   542  			_, ok := v.Children[want]
   543  			if ok {
   544  				found := hashPath(want[:idx])
   545  				return &found
   546  			}
   547  		}
   548  	}
   549  	for k, v := range d.Cache {
   550  		_, ok := v.Children[want]
   551  		if ok {
   552  			found := dataUsageHash(k)
   553  			return &found
   554  		}
   555  	}
   556  	return nil
   557  }
   558  
   559  // deleteRecursive will delete an entry recursively, but not change its parent.
   560  func (d *dataUsageCache) deleteRecursive(h dataUsageHash) {
   561  	if existing, ok := d.Cache[h.String()]; ok {
   562  		// Delete first if there should be a loop.
   563  		delete(d.Cache, h.Key())
   564  		for child := range existing.Children {
   565  			d.deleteRecursive(dataUsageHash(child))
   566  		}
   567  	}
   568  }
   569  
   570  // dui converts the flattened version of the path to madmin.DataUsageInfo.
   571  // As a side effect d will be flattened, use a clone if this is not ok.
   572  func (d *dataUsageCache) dui(path string, buckets []BucketInfo) DataUsageInfo {
   573  	e := d.find(path)
   574  	if e == nil {
   575  		// No entry found, return empty.
   576  		return DataUsageInfo{}
   577  	}
   578  	flat := d.flatten(*e)
   579  	dui := DataUsageInfo{
   580  		LastUpdate:              d.Info.LastUpdate,
   581  		ObjectsTotalCount:       flat.Objects,
   582  		VersionsTotalCount:      flat.Versions,
   583  		DeleteMarkersTotalCount: flat.DeleteMarkers,
   584  		ObjectsTotalSize:        uint64(flat.Size),
   585  		BucketsCount:            uint64(len(e.Children)),
   586  		BucketsUsage:            d.bucketsUsageInfo(buckets),
   587  		TierStats:               d.tiersUsageInfo(buckets),
   588  	}
   589  	return dui
   590  }
   591  
   592  // replace will add or replace an entry in the cache.
   593  // If a parent is specified it will be added to that if not already there.
   594  // If the parent does not exist, it will be added.
   595  func (d *dataUsageCache) replace(path, parent string, e dataUsageEntry) {
   596  	hash := hashPath(path)
   597  	if d.Cache == nil {
   598  		d.Cache = make(map[string]dataUsageEntry, 100)
   599  	}
   600  	d.Cache[hash.Key()] = e
   601  	if parent != "" {
   602  		phash := hashPath(parent)
   603  		p := d.Cache[phash.Key()]
   604  		p.addChild(hash)
   605  		d.Cache[phash.Key()] = p
   606  	}
   607  }
   608  
   609  // replaceHashed add or replaces an entry to the cache based on its hash.
   610  // If a parent is specified it will be added to that if not already there.
   611  // If the parent does not exist, it will be added.
   612  func (d *dataUsageCache) replaceHashed(hash dataUsageHash, parent *dataUsageHash, e dataUsageEntry) {
   613  	if d.Cache == nil {
   614  		d.Cache = make(map[string]dataUsageEntry, 100)
   615  	}
   616  	d.Cache[hash.Key()] = e
   617  	if parent != nil {
   618  		p := d.Cache[parent.Key()]
   619  		p.addChild(hash)
   620  		d.Cache[parent.Key()] = p
   621  	}
   622  }
   623  
   624  // copyWithChildren will copy entry with hash from src if it exists along with any children.
   625  // If a parent is specified it will be added to that if not already there.
   626  // If the parent does not exist, it will be added.
   627  func (d *dataUsageCache) copyWithChildren(src *dataUsageCache, hash dataUsageHash, parent *dataUsageHash) {
   628  	if d.Cache == nil {
   629  		d.Cache = make(map[string]dataUsageEntry, 100)
   630  	}
   631  	e, ok := src.Cache[hash.String()]
   632  	if !ok {
   633  		return
   634  	}
   635  	d.Cache[hash.Key()] = e
   636  	for ch := range e.Children {
   637  		if ch == hash.Key() {
   638  			logger.LogIf(GlobalContext, errors.New("dataUsageCache.copyWithChildren: Circular reference"))
   639  			return
   640  		}
   641  		d.copyWithChildren(src, dataUsageHash(ch), &hash)
   642  	}
   643  	if parent != nil {
   644  		p := d.Cache[parent.Key()]
   645  		p.addChild(hash)
   646  		d.Cache[parent.Key()] = p
   647  	}
   648  }
   649  
   650  // reduceChildrenOf will reduce the recursive number of children to the limit
   651  // by compacting the children with the least number of objects.
   652  func (d *dataUsageCache) reduceChildrenOf(path dataUsageHash, limit int, compactSelf bool) {
   653  	e, ok := d.Cache[path.Key()]
   654  	if !ok {
   655  		return
   656  	}
   657  	if e.Compacted {
   658  		return
   659  	}
   660  	// If direct children have more, compact all.
   661  	if len(e.Children) > limit && compactSelf {
   662  		flat := d.sizeRecursive(path.Key())
   663  		flat.Compacted = true
   664  		d.deleteRecursive(path)
   665  		d.replaceHashed(path, nil, *flat)
   666  		return
   667  	}
   668  	total := d.totalChildrenRec(path.Key())
   669  	if total < limit {
   670  		return
   671  	}
   672  
   673  	// Appears to be printed with _MINIO_SERVER_DEBUG=off
   674  	// console.Debugf(" %d children found, compacting %v\n", total, path)
   675  
   676  	leaves := make([]struct {
   677  		objects uint64
   678  		path    dataUsageHash
   679  	}, total)
   680  	// Collect current leaves that have children.
   681  	leaves = leaves[:0]
   682  	remove := total - limit
   683  	var add func(path dataUsageHash)
   684  	add = func(path dataUsageHash) {
   685  		e, ok := d.Cache[path.Key()]
   686  		if !ok {
   687  			return
   688  		}
   689  		if len(e.Children) == 0 {
   690  			return
   691  		}
   692  		sz := d.sizeRecursive(path.Key())
   693  		leaves = append(leaves, struct {
   694  			objects uint64
   695  			path    dataUsageHash
   696  		}{objects: sz.Objects, path: path})
   697  		for ch := range e.Children {
   698  			add(dataUsageHash(ch))
   699  		}
   700  	}
   701  
   702  	// Add path recursively.
   703  	add(path)
   704  	sort.Slice(leaves, func(i, j int) bool {
   705  		return leaves[i].objects < leaves[j].objects
   706  	})
   707  	for remove > 0 && len(leaves) > 0 {
   708  		// Remove top entry.
   709  		e := leaves[0]
   710  		candidate := e.path
   711  		if candidate == path && !compactSelf {
   712  			// We should be the biggest,
   713  			// if we cannot compact ourself, we are done.
   714  			break
   715  		}
   716  		removing := d.totalChildrenRec(candidate.Key())
   717  		flat := d.sizeRecursive(candidate.Key())
   718  		if flat == nil {
   719  			leaves = leaves[1:]
   720  			continue
   721  		}
   722  		// Appears to be printed with _MINIO_SERVER_DEBUG=off
   723  		// console.Debugf("compacting %v, removing %d children\n", candidate, removing)
   724  
   725  		flat.Compacted = true
   726  		d.deleteRecursive(candidate)
   727  		d.replaceHashed(candidate, nil, *flat)
   728  
   729  		// Remove top entry and subtract removed children.
   730  		remove -= removing
   731  		leaves = leaves[1:]
   732  	}
   733  }
   734  
   735  // StringAll returns a detailed string representation of all entries in the cache.
   736  func (d *dataUsageCache) StringAll() string {
   737  	// Remove bloom filter from print.
   738  	s := fmt.Sprintf("info:%+v\n", d.Info)
   739  	for k, v := range d.Cache {
   740  		s += fmt.Sprintf("\t%v: %+v\n", k, v)
   741  	}
   742  	return strings.TrimSpace(s)
   743  }
   744  
   745  // String returns a human readable representation of the string.
   746  func (h dataUsageHash) String() string {
   747  	return string(h)
   748  }
   749  
   750  // Key returns the key.
   751  func (h dataUsageHash) Key() string {
   752  	return string(h)
   753  }
   754  
   755  func (d *dataUsageCache) flattenChildrens(root dataUsageEntry) (m map[string]dataUsageEntry) {
   756  	m = make(map[string]dataUsageEntry)
   757  	for id := range root.Children {
   758  		e := d.Cache[id]
   759  		if len(e.Children) > 0 {
   760  			e = d.flatten(e)
   761  		}
   762  		m[id] = e
   763  	}
   764  	return m
   765  }
   766  
   767  // flatten all children of the root into the root element and return it.
   768  func (d *dataUsageCache) flatten(root dataUsageEntry) dataUsageEntry {
   769  	for id := range root.Children {
   770  		e := d.Cache[id]
   771  		if len(e.Children) > 0 {
   772  			e = d.flatten(e)
   773  		}
   774  		root.merge(e)
   775  	}
   776  	root.Children = nil
   777  	return root
   778  }
   779  
   780  // add a size to the histogram.
   781  func (h *sizeHistogram) add(size int64) {
   782  	// Fetch the histogram interval corresponding
   783  	// to the passed object size.
   784  	for i, interval := range ObjectsHistogramIntervals[:] {
   785  		if size >= interval.start && size <= interval.end {
   786  			h[i]++
   787  			break
   788  		}
   789  	}
   790  }
   791  
   792  // mergeV1 is used to migrate data usage cache from sizeHistogramV1 to
   793  // sizeHistogram
   794  func (h *sizeHistogram) mergeV1(v sizeHistogramV1) {
   795  	var oidx, nidx int
   796  	for oidx < len(v) {
   797  		intOld, intNew := ObjectsHistogramIntervalsV1[oidx], ObjectsHistogramIntervals[nidx]
   798  		// skip intervals that aren't common to both histograms
   799  		if intOld.start != intNew.start || intOld.end != intNew.end {
   800  			nidx++
   801  			continue
   802  		}
   803  		h[nidx] += v[oidx]
   804  		oidx++
   805  		nidx++
   806  	}
   807  }
   808  
   809  // toMap returns the map to a map[string]uint64.
   810  func (h *sizeHistogram) toMap() map[string]uint64 {
   811  	res := make(map[string]uint64, dataUsageBucketLen)
   812  	var splCount uint64
   813  	for i, count := range h {
   814  		szInt := ObjectsHistogramIntervals[i]
   815  		switch {
   816  		case humanize.KiByte == szInt.start && szInt.end == humanize.MiByte-1:
   817  			// spl interval: [1024B, 1MiB)
   818  			res[szInt.name] = splCount
   819  		case humanize.KiByte <= szInt.start && szInt.end <= humanize.MiByte-1:
   820  			// intervals that fall within the spl interval above; they
   821  			// appear earlier in this array of intervals, see
   822  			// ObjectsHistogramIntervals
   823  			splCount += count
   824  			fallthrough
   825  		default:
   826  			res[szInt.name] = count
   827  		}
   828  	}
   829  	return res
   830  }
   831  
   832  // add a version count to the histogram.
   833  func (h *versionsHistogram) add(versions uint64) {
   834  	// Fetch the histogram interval corresponding
   835  	// to the passed object size.
   836  	for i, interval := range ObjectsVersionCountIntervals[:] {
   837  		if versions >= uint64(interval.start) && versions <= uint64(interval.end) {
   838  			h[i]++
   839  			break
   840  		}
   841  	}
   842  }
   843  
   844  // toMap returns the map to a map[string]uint64.
   845  func (h *versionsHistogram) toMap() map[string]uint64 {
   846  	res := make(map[string]uint64, dataUsageVersionLen)
   847  	for i, count := range h {
   848  		res[ObjectsVersionCountIntervals[i].name] = count
   849  	}
   850  	return res
   851  }
   852  
   853  func (d *dataUsageCache) tiersUsageInfo(buckets []BucketInfo) *allTierStats {
   854  	dst := newAllTierStats()
   855  	for _, bucket := range buckets {
   856  		e := d.find(bucket.Name)
   857  		if e == nil {
   858  			continue
   859  		}
   860  		flat := d.flatten(*e)
   861  		if flat.AllTierStats == nil {
   862  			continue
   863  		}
   864  		dst.merge(flat.AllTierStats)
   865  	}
   866  	if len(dst.Tiers) == 0 {
   867  		return nil
   868  	}
   869  	return dst
   870  }
   871  
   872  // bucketsUsageInfo returns the buckets usage info as a map, with
   873  // key as bucket name
   874  func (d *dataUsageCache) bucketsUsageInfo(buckets []BucketInfo) map[string]BucketUsageInfo {
   875  	dst := make(map[string]BucketUsageInfo, len(buckets))
   876  	for _, bucket := range buckets {
   877  		e := d.find(bucket.Name)
   878  		if e == nil {
   879  			continue
   880  		}
   881  		flat := d.flatten(*e)
   882  		bui := BucketUsageInfo{
   883  			Size:                    uint64(flat.Size),
   884  			VersionsCount:           flat.Versions,
   885  			ObjectsCount:            flat.Objects,
   886  			DeleteMarkersCount:      flat.DeleteMarkers,
   887  			ObjectSizesHistogram:    flat.ObjSizes.toMap(),
   888  			ObjectVersionsHistogram: flat.ObjVersions.toMap(),
   889  		}
   890  		if flat.ReplicationStats != nil {
   891  			bui.ReplicaSize = flat.ReplicationStats.ReplicaSize
   892  			bui.ReplicaCount = flat.ReplicationStats.ReplicaCount
   893  
   894  			bui.ReplicationInfo = make(map[string]BucketTargetUsageInfo, len(flat.ReplicationStats.Targets))
   895  			for arn, stat := range flat.ReplicationStats.Targets {
   896  				bui.ReplicationInfo[arn] = BucketTargetUsageInfo{
   897  					ReplicationPendingSize:  stat.PendingSize,
   898  					ReplicatedSize:          stat.ReplicatedSize,
   899  					ReplicationFailedSize:   stat.FailedSize,
   900  					ReplicationPendingCount: stat.PendingCount,
   901  					ReplicationFailedCount:  stat.FailedCount,
   902  					ReplicatedCount:         stat.ReplicatedCount,
   903  				}
   904  			}
   905  		}
   906  		dst[bucket.Name] = bui
   907  	}
   908  	return dst
   909  }
   910  
   911  // sizeRecursive returns the path as a flattened entry.
   912  func (d *dataUsageCache) sizeRecursive(path string) *dataUsageEntry {
   913  	root := d.find(path)
   914  	if root == nil || len(root.Children) == 0 {
   915  		return root
   916  	}
   917  	flat := d.flatten(*root)
   918  	if flat.ReplicationStats.empty() {
   919  		flat.ReplicationStats = nil
   920  	}
   921  	return &flat
   922  }
   923  
   924  // totalChildrenRec returns the total number of children recorded.
   925  func (d *dataUsageCache) totalChildrenRec(path string) int {
   926  	root := d.find(path)
   927  	if root == nil || len(root.Children) == 0 {
   928  		return 0
   929  	}
   930  	n := len(root.Children)
   931  	for ch := range root.Children {
   932  		n += d.totalChildrenRec(ch)
   933  	}
   934  	return n
   935  }
   936  
   937  // root returns the root of the cache.
   938  func (d *dataUsageCache) root() *dataUsageEntry {
   939  	return d.find(d.Info.Name)
   940  }
   941  
   942  // rootHash returns the root of the cache.
   943  func (d *dataUsageCache) rootHash() dataUsageHash {
   944  	return hashPath(d.Info.Name)
   945  }
   946  
   947  // clone returns a copy of the cache with no references to the existing.
   948  func (d *dataUsageCache) clone() dataUsageCache {
   949  	clone := dataUsageCache{
   950  		Info:  d.Info,
   951  		Cache: make(map[string]dataUsageEntry, len(d.Cache)),
   952  	}
   953  	for k, v := range d.Cache {
   954  		clone.Cache[k] = v.clone()
   955  	}
   956  	return clone
   957  }
   958  
   959  // merge root of other into d.
   960  // children of root will be flattened before being merged.
   961  // Last update time will be set to the last updated.
   962  func (d *dataUsageCache) merge(other dataUsageCache) {
   963  	existingRoot := d.root()
   964  	otherRoot := other.root()
   965  	if existingRoot == nil && otherRoot == nil {
   966  		return
   967  	}
   968  	if otherRoot == nil {
   969  		return
   970  	}
   971  	if existingRoot == nil {
   972  		*d = other.clone()
   973  		return
   974  	}
   975  	if other.Info.LastUpdate.After(d.Info.LastUpdate) {
   976  		d.Info.LastUpdate = other.Info.LastUpdate
   977  	}
   978  	existingRoot.merge(*otherRoot)
   979  	eHash := d.rootHash()
   980  	for key := range otherRoot.Children {
   981  		entry := other.Cache[key]
   982  		flat := other.flatten(entry)
   983  		existing := d.Cache[key]
   984  		// If not found, merging simply adds.
   985  		existing.merge(flat)
   986  		d.replaceHashed(dataUsageHash(key), &eHash, existing)
   987  	}
   988  }
   989  
   990  type objectIO interface {
   991  	GetObjectNInfo(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, opts ObjectOptions) (reader *GetObjectReader, err error)
   992  	PutObject(ctx context.Context, bucket, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error)
   993  }
   994  
   995  // load the cache content with name from minioMetaBackgroundOpsBucket.
   996  // Only backend errors are returned as errors.
   997  // The loader is optimistic and has no locking, but tries 5 times before giving up.
   998  // If the object is not found, a nil error with empty data usage cache is returned.
   999  func (d *dataUsageCache) load(ctx context.Context, store objectIO, name string) error {
  1000  	// By default, empty data usage cache
  1001  	*d = dataUsageCache{}
  1002  
  1003  	load := func(name string, timeout time.Duration) (bool, error) {
  1004  		// Abandon if more than time.Minute, so we don't hold up scanner.
  1005  		// drive timeout by default is 2 minutes, we do not need to wait longer.
  1006  		ctx, cancel := context.WithTimeout(ctx, timeout)
  1007  		defer cancel()
  1008  
  1009  		r, err := store.GetObjectNInfo(ctx, dataUsageBucket, name, nil, http.Header{}, ObjectOptions{NoLock: true})
  1010  		if err != nil {
  1011  			switch err.(type) {
  1012  			case ObjectNotFound, BucketNotFound:
  1013  				return false, nil
  1014  			case InsufficientReadQuorum, StorageErr:
  1015  				return true, nil
  1016  			}
  1017  			return false, err
  1018  		}
  1019  		err = d.deserialize(r)
  1020  		r.Close()
  1021  		return err != nil, nil
  1022  	}
  1023  
  1024  	// Caches are read+written without locks,
  1025  	retries := 0
  1026  	for retries < 5 {
  1027  		retry, err := load(name, time.Minute)
  1028  		if err != nil {
  1029  			return toObjectErr(err, dataUsageBucket, name)
  1030  		}
  1031  		if !retry {
  1032  			break
  1033  		}
  1034  		retry, err = load(name+".bkp", 30*time.Second)
  1035  		if err == nil && !retry {
  1036  			// Only return when we have valid data from the backup
  1037  			break
  1038  		}
  1039  		retries++
  1040  		time.Sleep(time.Duration(rand.Int63n(int64(time.Second))))
  1041  	}
  1042  
  1043  	if retries == 5 {
  1044  		logger.LogOnceIf(ctx, fmt.Errorf("maximum retry reached to load the data usage cache `%s`", name), "retry-loading-data-usage-cache")
  1045  	}
  1046  
  1047  	return nil
  1048  }
  1049  
  1050  // Maximum running concurrent saves on server.
  1051  var maxConcurrentScannerSaves = make(chan struct{}, 4)
  1052  
  1053  // save the content of the cache to minioMetaBackgroundOpsBucket with the provided name.
  1054  // Note that no locking is done when saving.
  1055  func (d *dataUsageCache) save(ctx context.Context, store objectIO, name string) error {
  1056  	select {
  1057  	case <-ctx.Done():
  1058  		return ctx.Err()
  1059  	case maxConcurrentScannerSaves <- struct{}{}:
  1060  	}
  1061  
  1062  	buf := bytebufferpool.Get()
  1063  	defer func() {
  1064  		<-maxConcurrentScannerSaves
  1065  		buf.Reset()
  1066  		bytebufferpool.Put(buf)
  1067  	}()
  1068  
  1069  	if err := d.serializeTo(buf); err != nil {
  1070  		return err
  1071  	}
  1072  
  1073  	save := func(name string, timeout time.Duration) error {
  1074  		hr, err := hash.NewReader(ctx, bytes.NewReader(buf.Bytes()), int64(buf.Len()), "", "", int64(buf.Len()))
  1075  		if err != nil {
  1076  			return err
  1077  		}
  1078  
  1079  		// Abandon if more than a minute, so we don't hold up scanner.
  1080  		ctx, cancel := context.WithTimeout(ctx, timeout)
  1081  		defer cancel()
  1082  
  1083  		_, err = store.PutObject(ctx,
  1084  			dataUsageBucket,
  1085  			name,
  1086  			NewPutObjReader(hr),
  1087  			ObjectOptions{NoLock: true})
  1088  		if isErrBucketNotFound(err) {
  1089  			return nil
  1090  		}
  1091  		return err
  1092  	}
  1093  	defer save(name+".bkp", 5*time.Second) // Keep a backup as well
  1094  
  1095  	// drive timeout by default is 2 minutes, we do not need to wait longer.
  1096  	return save(name, time.Minute)
  1097  }
  1098  
  1099  // dataUsageCacheVer indicates the cache version.
  1100  // Bumping the cache version will drop data from previous versions
  1101  // and write new data with the new version.
  1102  const (
  1103  	dataUsageCacheVerCurrent = 8
  1104  	dataUsageCacheVerV7      = 7
  1105  	dataUsageCacheVerV6      = 6
  1106  	dataUsageCacheVerV5      = 5
  1107  	dataUsageCacheVerV4      = 4
  1108  	dataUsageCacheVerV3      = 3
  1109  	dataUsageCacheVerV2      = 2
  1110  	dataUsageCacheVerV1      = 1
  1111  )
  1112  
  1113  // serialize the contents of the cache.
  1114  func (d *dataUsageCache) serializeTo(dst io.Writer) error {
  1115  	// Add version and compress.
  1116  	_, err := dst.Write([]byte{dataUsageCacheVerCurrent})
  1117  	if err != nil {
  1118  		return err
  1119  	}
  1120  	enc, err := zstd.NewWriter(dst,
  1121  		zstd.WithEncoderLevel(zstd.SpeedFastest),
  1122  		zstd.WithWindowSize(1<<20),
  1123  		zstd.WithEncoderConcurrency(2))
  1124  	if err != nil {
  1125  		return err
  1126  	}
  1127  	mEnc := msgp.NewWriter(enc)
  1128  	err = d.EncodeMsg(mEnc)
  1129  	if err != nil {
  1130  		return err
  1131  	}
  1132  	err = mEnc.Flush()
  1133  	if err != nil {
  1134  		return err
  1135  	}
  1136  	err = enc.Close()
  1137  	if err != nil {
  1138  		return err
  1139  	}
  1140  	return nil
  1141  }
  1142  
  1143  // deserialize the supplied byte slice into the cache.
  1144  func (d *dataUsageCache) deserialize(r io.Reader) error {
  1145  	var b [1]byte
  1146  	n, _ := r.Read(b[:])
  1147  	if n != 1 {
  1148  		return io.ErrUnexpectedEOF
  1149  	}
  1150  	ver := int(b[0])
  1151  	switch ver {
  1152  	case dataUsageCacheVerV1:
  1153  		return errors.New("cache version deprecated (will autoupdate)")
  1154  	case dataUsageCacheVerV2:
  1155  		// Zstd compressed.
  1156  		dec, err := zstd.NewReader(r, zstd.WithDecoderConcurrency(2))
  1157  		if err != nil {
  1158  			return err
  1159  		}
  1160  		defer dec.Close()
  1161  
  1162  		dold := &dataUsageCacheV2{}
  1163  		if err = dold.DecodeMsg(msgp.NewReader(dec)); err != nil {
  1164  			return err
  1165  		}
  1166  		d.Info = dold.Info
  1167  		d.Cache = make(map[string]dataUsageEntry, len(dold.Cache))
  1168  		for k, v := range dold.Cache {
  1169  			d.Cache[k] = dataUsageEntry{
  1170  				Size:      v.Size,
  1171  				Objects:   v.Objects,
  1172  				ObjSizes:  v.ObjSizes,
  1173  				Children:  v.Children,
  1174  				Compacted: len(v.Children) == 0 && k != d.Info.Name,
  1175  			}
  1176  		}
  1177  		return nil
  1178  	case dataUsageCacheVerV3:
  1179  		// Zstd compressed.
  1180  		dec, err := zstd.NewReader(r, zstd.WithDecoderConcurrency(2))
  1181  		if err != nil {
  1182  			return err
  1183  		}
  1184  		defer dec.Close()
  1185  		dold := &dataUsageCacheV3{}
  1186  		if err = dold.DecodeMsg(msgp.NewReader(dec)); err != nil {
  1187  			return err
  1188  		}
  1189  		d.Info = dold.Info
  1190  		d.Cache = make(map[string]dataUsageEntry, len(dold.Cache))
  1191  		for k, v := range dold.Cache {
  1192  			due := dataUsageEntry{
  1193  				Size:     v.Size,
  1194  				Objects:  v.Objects,
  1195  				ObjSizes: v.ObjSizes,
  1196  				Children: v.Children,
  1197  			}
  1198  			if v.ReplicatedSize > 0 || v.ReplicaSize > 0 || v.ReplicationFailedSize > 0 || v.ReplicationPendingSize > 0 {
  1199  				cfg, _ := getReplicationConfig(GlobalContext, d.Info.Name)
  1200  				if cfg != nil && cfg.RoleArn != "" {
  1201  					due.ReplicationStats = &replicationAllStats{
  1202  						Targets: make(map[string]replicationStats),
  1203  					}
  1204  					due.ReplicationStats.ReplicaSize = v.ReplicaSize
  1205  					due.ReplicationStats.Targets[cfg.RoleArn] = replicationStats{
  1206  						ReplicatedSize: v.ReplicatedSize,
  1207  						FailedSize:     v.ReplicationFailedSize,
  1208  						PendingSize:    v.ReplicationPendingSize,
  1209  					}
  1210  				}
  1211  			}
  1212  			due.Compacted = len(due.Children) == 0 && k != d.Info.Name
  1213  
  1214  			d.Cache[k] = due
  1215  		}
  1216  		return nil
  1217  	case dataUsageCacheVerV4:
  1218  		// Zstd compressed.
  1219  		dec, err := zstd.NewReader(r, zstd.WithDecoderConcurrency(2))
  1220  		if err != nil {
  1221  			return err
  1222  		}
  1223  		defer dec.Close()
  1224  		dold := &dataUsageCacheV4{}
  1225  		if err = dold.DecodeMsg(msgp.NewReader(dec)); err != nil {
  1226  			return err
  1227  		}
  1228  		d.Info = dold.Info
  1229  		d.Cache = make(map[string]dataUsageEntry, len(dold.Cache))
  1230  		for k, v := range dold.Cache {
  1231  			due := dataUsageEntry{
  1232  				Size:     v.Size,
  1233  				Objects:  v.Objects,
  1234  				ObjSizes: v.ObjSizes,
  1235  				Children: v.Children,
  1236  			}
  1237  			empty := replicationStatsV1{}
  1238  
  1239  			if v.ReplicationStats != empty {
  1240  				cfg, _ := getReplicationConfig(GlobalContext, d.Info.Name)
  1241  				if cfg != nil && cfg.RoleArn != "" {
  1242  					due.ReplicationStats = &replicationAllStats{
  1243  						Targets: make(map[string]replicationStats),
  1244  					}
  1245  					due.ReplicationStats.Targets[cfg.RoleArn] = replicationStats{
  1246  						ReplicatedSize: v.ReplicationStats.ReplicatedSize,
  1247  						FailedSize:     v.ReplicationStats.FailedSize,
  1248  						FailedCount:    v.ReplicationStats.FailedCount,
  1249  						PendingSize:    v.ReplicationStats.PendingSize,
  1250  						PendingCount:   v.ReplicationStats.PendingCount,
  1251  					}
  1252  					due.ReplicationStats.ReplicaSize = v.ReplicationStats.ReplicaSize
  1253  				}
  1254  			}
  1255  			due.Compacted = len(due.Children) == 0 && k != d.Info.Name
  1256  
  1257  			d.Cache[k] = due
  1258  		}
  1259  
  1260  		// Populate compacted value and remove unneeded replica stats.
  1261  		for k, e := range d.Cache {
  1262  			if e.ReplicationStats != nil && len(e.ReplicationStats.Targets) == 0 {
  1263  				e.ReplicationStats = nil
  1264  			}
  1265  			d.Cache[k] = e
  1266  		}
  1267  		return nil
  1268  	case dataUsageCacheVerV5:
  1269  		// Zstd compressed.
  1270  		dec, err := zstd.NewReader(r, zstd.WithDecoderConcurrency(2))
  1271  		if err != nil {
  1272  			return err
  1273  		}
  1274  		defer dec.Close()
  1275  		dold := &dataUsageCacheV5{}
  1276  		if err = dold.DecodeMsg(msgp.NewReader(dec)); err != nil {
  1277  			return err
  1278  		}
  1279  		d.Info = dold.Info
  1280  		d.Cache = make(map[string]dataUsageEntry, len(dold.Cache))
  1281  		for k, v := range dold.Cache {
  1282  			due := dataUsageEntry{
  1283  				Size:     v.Size,
  1284  				Objects:  v.Objects,
  1285  				ObjSizes: v.ObjSizes,
  1286  				Children: v.Children,
  1287  			}
  1288  			if v.ReplicationStats != nil && !v.ReplicationStats.Empty() {
  1289  				cfg, _ := getReplicationConfig(GlobalContext, d.Info.Name)
  1290  				if cfg != nil && cfg.RoleArn != "" {
  1291  					due.ReplicationStats = &replicationAllStats{
  1292  						Targets: make(map[string]replicationStats),
  1293  					}
  1294  					d.Info.replication = replicationConfig{Config: cfg}
  1295  
  1296  					due.ReplicationStats.Targets[cfg.RoleArn] = replicationStats{
  1297  						ReplicatedSize: v.ReplicationStats.ReplicatedSize,
  1298  						FailedSize:     v.ReplicationStats.FailedSize,
  1299  						FailedCount:    v.ReplicationStats.FailedCount,
  1300  						PendingSize:    v.ReplicationStats.PendingSize,
  1301  						PendingCount:   v.ReplicationStats.PendingCount,
  1302  					}
  1303  					due.ReplicationStats.ReplicaSize = v.ReplicationStats.ReplicaSize
  1304  				}
  1305  			}
  1306  			due.Compacted = len(due.Children) == 0 && k != d.Info.Name
  1307  
  1308  			d.Cache[k] = due
  1309  		}
  1310  
  1311  		// Populate compacted value and remove unneeded replica stats.
  1312  		for k, e := range d.Cache {
  1313  			if e.ReplicationStats != nil && len(e.ReplicationStats.Targets) == 0 {
  1314  				e.ReplicationStats = nil
  1315  			}
  1316  			d.Cache[k] = e
  1317  		}
  1318  		return nil
  1319  	case dataUsageCacheVerV6:
  1320  		// Zstd compressed.
  1321  		dec, err := zstd.NewReader(r, zstd.WithDecoderConcurrency(2))
  1322  		if err != nil {
  1323  			return err
  1324  		}
  1325  		defer dec.Close()
  1326  		dold := &dataUsageCacheV6{}
  1327  		if err = dold.DecodeMsg(msgp.NewReader(dec)); err != nil {
  1328  			return err
  1329  		}
  1330  		d.Info = dold.Info
  1331  		d.Cache = make(map[string]dataUsageEntry, len(dold.Cache))
  1332  		for k, v := range dold.Cache {
  1333  			var replicationStats *replicationAllStats
  1334  			if v.ReplicationStats != nil {
  1335  				replicationStats = &replicationAllStats{
  1336  					Targets:      v.ReplicationStats.Targets,
  1337  					ReplicaSize:  v.ReplicationStats.ReplicaSize,
  1338  					ReplicaCount: v.ReplicationStats.ReplicaCount,
  1339  				}
  1340  			}
  1341  			due := dataUsageEntry{
  1342  				Children:         v.Children,
  1343  				Size:             v.Size,
  1344  				Objects:          v.Objects,
  1345  				Versions:         v.Versions,
  1346  				ObjSizes:         v.ObjSizes,
  1347  				ReplicationStats: replicationStats,
  1348  				Compacted:        v.Compacted,
  1349  			}
  1350  			d.Cache[k] = due
  1351  		}
  1352  		return nil
  1353  	case dataUsageCacheVerV7:
  1354  		// Zstd compressed.
  1355  		dec, err := zstd.NewReader(r, zstd.WithDecoderConcurrency(2))
  1356  		if err != nil {
  1357  			return err
  1358  		}
  1359  		defer dec.Close()
  1360  		dold := &dataUsageCacheV7{}
  1361  		if err = dold.DecodeMsg(msgp.NewReader(dec)); err != nil {
  1362  			return err
  1363  		}
  1364  		d.Info = dold.Info
  1365  		d.Cache = make(map[string]dataUsageEntry, len(dold.Cache))
  1366  		for k, v := range dold.Cache {
  1367  			var szHist sizeHistogram
  1368  			szHist.mergeV1(v.ObjSizes)
  1369  			d.Cache[k] = dataUsageEntry{
  1370  				Children:         v.Children,
  1371  				Size:             v.Size,
  1372  				Objects:          v.Objects,
  1373  				Versions:         v.Versions,
  1374  				ObjSizes:         szHist,
  1375  				ReplicationStats: v.ReplicationStats,
  1376  				Compacted:        v.Compacted,
  1377  			}
  1378  		}
  1379  
  1380  		return nil
  1381  	case dataUsageCacheVerCurrent:
  1382  		// Zstd compressed.
  1383  		dec, err := zstd.NewReader(r, zstd.WithDecoderConcurrency(2))
  1384  		if err != nil {
  1385  			return err
  1386  		}
  1387  		defer dec.Close()
  1388  		return d.DecodeMsg(msgp.NewReader(dec))
  1389  	default:
  1390  		return fmt.Errorf("dataUsageCache: unknown version: %d", ver)
  1391  	}
  1392  }
  1393  
  1394  // Trim this from start+end of hashes.
  1395  var hashPathCutSet = dataUsageRoot
  1396  
  1397  func init() {
  1398  	if dataUsageRoot != string(filepath.Separator) {
  1399  		hashPathCutSet = dataUsageRoot + string(filepath.Separator)
  1400  	}
  1401  }
  1402  
  1403  // hashPath calculates a hash of the provided string.
  1404  func hashPath(data string) dataUsageHash {
  1405  	if data != dataUsageRoot {
  1406  		data = strings.Trim(data, hashPathCutSet)
  1407  	}
  1408  	return dataUsageHash(path.Clean(data))
  1409  }
  1410  
  1411  //msgp:ignore dataUsageHashMap
  1412  type dataUsageHashMap map[string]struct{}
  1413  
  1414  // DecodeMsg implements msgp.Decodable
  1415  func (z *dataUsageHashMap) DecodeMsg(dc *msgp.Reader) (err error) {
  1416  	var zb0002 uint32
  1417  	zb0002, err = dc.ReadArrayHeader()
  1418  	if err != nil {
  1419  		err = msgp.WrapError(err)
  1420  		return
  1421  	}
  1422  	if zb0002 == 0 {
  1423  		*z = nil
  1424  		return
  1425  	}
  1426  	*z = make(dataUsageHashMap, zb0002)
  1427  	for i := uint32(0); i < zb0002; i++ {
  1428  		{
  1429  			var zb0003 string
  1430  			zb0003, err = dc.ReadString()
  1431  			if err != nil {
  1432  				err = msgp.WrapError(err)
  1433  				return
  1434  			}
  1435  			(*z)[zb0003] = struct{}{}
  1436  		}
  1437  	}
  1438  	return
  1439  }
  1440  
  1441  // EncodeMsg implements msgp.Encodable
  1442  func (z dataUsageHashMap) EncodeMsg(en *msgp.Writer) (err error) {
  1443  	err = en.WriteArrayHeader(uint32(len(z)))
  1444  	if err != nil {
  1445  		err = msgp.WrapError(err)
  1446  		return
  1447  	}
  1448  	for zb0004 := range z {
  1449  		err = en.WriteString(zb0004)
  1450  		if err != nil {
  1451  			err = msgp.WrapError(err, zb0004)
  1452  			return
  1453  		}
  1454  	}
  1455  	return
  1456  }
  1457  
  1458  // MarshalMsg implements msgp.Marshaler
  1459  func (z dataUsageHashMap) MarshalMsg(b []byte) (o []byte, err error) {
  1460  	o = msgp.Require(b, z.Msgsize())
  1461  	o = msgp.AppendArrayHeader(o, uint32(len(z)))
  1462  	for zb0004 := range z {
  1463  		o = msgp.AppendString(o, zb0004)
  1464  	}
  1465  	return
  1466  }
  1467  
  1468  // UnmarshalMsg implements msgp.Unmarshaler
  1469  func (z *dataUsageHashMap) UnmarshalMsg(bts []byte) (o []byte, err error) {
  1470  	var zb0002 uint32
  1471  	zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts)
  1472  	if err != nil {
  1473  		err = msgp.WrapError(err)
  1474  		return
  1475  	}
  1476  	if zb0002 == 0 {
  1477  		*z = nil
  1478  		return bts, nil
  1479  	}
  1480  	*z = make(dataUsageHashMap, zb0002)
  1481  	for i := uint32(0); i < zb0002; i++ {
  1482  		{
  1483  			var zb0003 string
  1484  			zb0003, bts, err = msgp.ReadStringBytes(bts)
  1485  			if err != nil {
  1486  				err = msgp.WrapError(err)
  1487  				return
  1488  			}
  1489  			(*z)[zb0003] = struct{}{}
  1490  		}
  1491  	}
  1492  	o = bts
  1493  	return
  1494  }
  1495  
  1496  // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
  1497  func (z dataUsageHashMap) Msgsize() (s int) {
  1498  	s = msgp.ArrayHeaderSize
  1499  	for zb0004 := range z {
  1500  		s += msgp.StringPrefixSize + len(zb0004)
  1501  	}
  1502  	return
  1503  }
  1504  
  1505  //msgp:encode ignore currentScannerCycle
  1506  //msgp:decode ignore currentScannerCycle
  1507  
  1508  type currentScannerCycle struct {
  1509  	current        uint64
  1510  	next           uint64
  1511  	started        time.Time
  1512  	cycleCompleted []time.Time
  1513  }
  1514  
  1515  // clone returns a clone.
  1516  func (z currentScannerCycle) clone() currentScannerCycle {
  1517  	z.cycleCompleted = append(make([]time.Time, 0, len(z.cycleCompleted)), z.cycleCompleted...)
  1518  	return z
  1519  }