go.dedis.ch/onet/v4@v4.0.0-pre1/simul/monitor/bucket_stats.go (about) 1 package monitor 2 3 import ( 4 "strconv" 5 "strings" 6 7 "golang.org/x/xerrors" 8 ) 9 10 // bucketRule represents a filter that will tell if a measure must 11 // be added to a bucket. It follows the logic of a slice indexing 12 // so that the lower index is inclusive and the upper one is exclusive. 13 type bucketRule struct { 14 low int 15 high int 16 } 17 18 // newBucketRule takes a string and parses it to instantiate 19 // a bucket rule. 20 func newBucketRule(r string) (rule bucketRule, err error) { 21 parts := strings.Split(r, ":") 22 if len(parts) != 2 { 23 err = xerrors.New("malformed rule") 24 return 25 } 26 27 rule.low, err = strconv.Atoi(parts[0]) 28 if err != nil { 29 err = xerrors.Errorf("atoi: %v", err) 30 return 31 } 32 33 rule.high, err = strconv.Atoi(parts[1]) 34 if err != nil { 35 err = xerrors.Errorf("atoi: %v", err) 36 return 37 } 38 39 return 40 } 41 42 // Match returns true when the index is accepted by the rule, false 43 // otherwise. 44 func (r bucketRule) Match(index int) bool { 45 return index >= r.low && index < r.high 46 } 47 48 type bucketRules []bucketRule 49 50 // Match returns true when at least one of the rule accepts the host 51 // index. 52 func (rr bucketRules) Match(host int) bool { 53 if host < 0 { 54 // a value below is considered as an invalid host index 55 return false 56 } 57 58 for _, rule := range rr { 59 if rule.Match(host) { 60 return true 61 } 62 } 63 64 return false 65 } 66 67 // BucketStats splits the statistics into buckets according to network addresses 68 // and associated rules 69 type BucketStats struct { 70 rules map[int]bucketRules 71 buckets map[int]*Stats 72 } 73 74 func newBucketStats() *BucketStats { 75 return &BucketStats{ 76 rules: make(map[int]bucketRules), 77 buckets: make(map[int]*Stats), 78 } 79 } 80 81 // Set creates a new bucket at the given index that uses the rules to filter 82 // incoming measures 83 func (bs *BucketStats) Set(index int, rules []string, stats *Stats) error { 84 bs.rules[index] = make(bucketRules, len(rules)) 85 for i, str := range rules { 86 rule, err := newBucketRule(str) 87 if err != nil { 88 return xerrors.Errorf("bucket rule: %v", err) 89 } 90 91 bs.rules[index][i] = rule 92 } 93 94 bs.buckets[index] = stats 95 return nil 96 } 97 98 // Get returns the bucket at the given index if it exists, nil otherwise 99 func (bs *BucketStats) Get(index int) *Stats { 100 s := bs.buckets[index] 101 if s != nil { 102 s.Collect() 103 } 104 105 return s 106 } 107 108 // Update takes a single measure and fill the buckets that will match 109 // the host index if defined in the measure 110 func (bs *BucketStats) Update(m *singleMeasure) { 111 for i, rr := range bs.rules { 112 if rr.Match(m.Host) { 113 bs.buckets[i].Update(m) 114 } 115 } 116 }