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 }