github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/tier-last-day-stats.go (about)

     1  // Copyright (c) 2022 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  	"time"
    22  
    23  	"github.com/minio/madmin-go/v3"
    24  )
    25  
    26  //go:generate msgp -file=$GOFILE -unexported
    27  
    28  type lastDayTierStats struct {
    29  	Bins      [24]tierStats
    30  	UpdatedAt time.Time
    31  }
    32  
    33  func (l *lastDayTierStats) addStats(ts tierStats) {
    34  	now := time.Now()
    35  	l.forwardTo(now)
    36  
    37  	nowIdx := now.Hour()
    38  	l.Bins[nowIdx] = l.Bins[nowIdx].add(ts)
    39  }
    40  
    41  // forwardTo moves time to t, clearing entries between last update and t.
    42  func (l *lastDayTierStats) forwardTo(t time.Time) {
    43  	if t.IsZero() {
    44  		t = time.Now()
    45  	}
    46  
    47  	since := t.Sub(l.UpdatedAt).Hours()
    48  	// within the hour since l.UpdatedAt
    49  	if since < 1 {
    50  		return
    51  	}
    52  
    53  	idx, lastIdx := t.Hour(), l.UpdatedAt.Hour()
    54  
    55  	l.UpdatedAt = t // update to the latest time index
    56  
    57  	if since >= 24 {
    58  		l.Bins = [24]tierStats{}
    59  		return
    60  	}
    61  
    62  	for lastIdx != idx {
    63  		lastIdx = (lastIdx + 1) % 24
    64  		l.Bins[lastIdx] = tierStats{}
    65  	}
    66  }
    67  
    68  func (l *lastDayTierStats) clone() lastDayTierStats {
    69  	clone := lastDayTierStats{
    70  		UpdatedAt: l.UpdatedAt,
    71  	}
    72  	copy(clone.Bins[:], l.Bins[:])
    73  	return clone
    74  }
    75  
    76  func (l lastDayTierStats) merge(m lastDayTierStats) (merged lastDayTierStats) {
    77  	cl := l.clone()
    78  	cm := m.clone()
    79  
    80  	if cl.UpdatedAt.After(cm.UpdatedAt) {
    81  		cm.forwardTo(cl.UpdatedAt)
    82  		merged.UpdatedAt = cl.UpdatedAt
    83  	} else {
    84  		cl.forwardTo(cm.UpdatedAt)
    85  		merged.UpdatedAt = cm.UpdatedAt
    86  	}
    87  
    88  	for i := range cl.Bins {
    89  		merged.Bins[i] = cl.Bins[i].add(cm.Bins[i])
    90  	}
    91  
    92  	return merged
    93  }
    94  
    95  // DailyAllTierStats is used to aggregate last day tier stats across MinIO servers
    96  type DailyAllTierStats map[string]lastDayTierStats
    97  
    98  func (l DailyAllTierStats) merge(m DailyAllTierStats) {
    99  	for tier, st := range m {
   100  		l[tier] = l[tier].merge(st)
   101  	}
   102  }
   103  
   104  func (l DailyAllTierStats) addToTierInfo(tierInfos []madmin.TierInfo) []madmin.TierInfo {
   105  	for i := range tierInfos {
   106  		lst, ok := l[tierInfos[i].Name]
   107  		if !ok {
   108  			continue
   109  		}
   110  		for hr, st := range lst.Bins {
   111  			tierInfos[i].DailyStats.Bins[hr] = madmin.TierStats{
   112  				TotalSize:   st.TotalSize,
   113  				NumVersions: st.NumVersions,
   114  				NumObjects:  st.NumObjects,
   115  			}
   116  		}
   117  		tierInfos[i].DailyStats.UpdatedAt = lst.UpdatedAt
   118  	}
   119  	return tierInfos
   120  }