Repository: nsqio/nsq
File: internal/quantile/aggregate.go (Go)

Code before:
		percentiles[i]["max"] = n
		percentiles[i]["average"] = n
		percentiles[i]["quantile"] = q
		percentiles[i]["count"] = float64(count)
	}

	return &E2eProcessingLatencyAggregate{
		Count:       count,
		Percentiles: percentiles,
		Topic:       topic,
		Channel:     channel,
		Addr:        host,
	}
}

func (e *E2eProcessingLatencyAggregate) Len() int { return len(e.Percentiles) }
func (e *E2eProcessingLatencyAggregate) Swap(i, j int) {
	e.Percentiles[i], e.Percentiles[j] = e.Percentiles[j], e.Percentiles[i]
}
func (e *E2eProcessingLatencyAggregate) Less(i, j int) bool {
	return e.Percentiles[i]["percentile"] > e.Percentiles[j]["percentile"]
}

// Add merges two E2eProcessingLatencyAggregate by averaging the percentiles
//
// It is side-effect free and does not modify the receiver or the parameter
func (e *E2eProcessingLatencyAggregate) Add(e2 *E2eProcessingLatencyAggregate, N int) *E2eProcessingLatencyAggregate {
	if e == nil {
		e = &E2eProcessingLatencyAggregate{}
	} else {
		e = &(*e)
	}
	e.Addr = "*"

	p := e.Percentiles
	e.Count += e2.Count
	for _, value := range e2.Percentiles {
		i := -1
		for j, v := range p {
			if value["quantile"] == v["quantile"] {
				i = j
				break
			}
		}
		if i == -1 {
			i = len(p)
			e.Percentiles = append(p, make(map[string]float64))
			p = e.Percentiles
			p[i]["quantile"] = value["quantile"]
		}
		p[i]["max"] = math.Max(value["max"], p[i]["max"])

Review comment (bug):
Sorry for this bug. Probably what I meant to do is

``` go
if e == nil {
  e = &E2eProcessingLatencyAggregate{}
  *e = *e2
} else {
  ...
```

But I also didn't realize that this function was not supposed to modify the receiver. It looked like a `math/big`-style API.


Code after:
		percentiles[i]["max"] = n
		percentiles[i]["average"] = n
		percentiles[i]["quantile"] = q
		percentiles[i]["count"] = float64(count)
	}

	return &E2eProcessingLatencyAggregate{
		Count:       count,
		Percentiles: percentiles,
		Topic:       topic,
		Channel:     channel,
		Addr:        host,
	}
}

func (e *E2eProcessingLatencyAggregate) Len() int { return len(e.Percentiles) }
func (e *E2eProcessingLatencyAggregate) Swap(i, j int) {
	e.Percentiles[i], e.Percentiles[j] = e.Percentiles[j], e.Percentiles[i]
}
func (e *E2eProcessingLatencyAggregate) Less(i, j int) bool {
	return e.Percentiles[i]["percentile"] > e.Percentiles[j]["percentile"]
}

// Add merges e2 into e by averaging the percentiles
func (e *E2eProcessingLatencyAggregate) Add(e2 *E2eProcessingLatencyAggregate) {
	e.Addr = "*"
	p := e.Percentiles
	e.Count += e2.Count
	for _, value := range e2.Percentiles {
		i := -1
		for j, v := range p {
			if value["quantile"] == v["quantile"] {
				i = j
				break
			}
		}
		if i == -1 {
			i = len(p)
			e.Percentiles = append(p, make(map[string]float64))
			p = e.Percentiles
			p[i]["quantile"] = value["quantile"]
		}
		p[i]["max"] = math.Max(value["max"], p[i]["max"])
		p[i]["min"] = math.Min(value["max"], p[i]["max"])

		p[i]["count"] += value["count"]
		delta := value["average"] - p[i]["average"]
		R := delta * value["count"] / p[i]["count"]
		p[i]["average"] = p[i]["average"] + R
	}
	sort.Sort(e)