2024-05-12 16:33:29 +02:00
|
|
|
package logstorage
|
|
|
|
|
|
|
|
import (
|
2024-05-22 21:01:20 +02:00
|
|
|
"fmt"
|
2024-05-12 16:33:29 +02:00
|
|
|
"slices"
|
|
|
|
"strconv"
|
2024-05-22 21:01:20 +02:00
|
|
|
"strings"
|
2024-05-12 16:33:29 +02:00
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
type statsAvg struct {
|
2024-05-22 21:01:20 +02:00
|
|
|
fields []string
|
2024-05-12 16:33:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (sa *statsAvg) String() string {
|
2024-05-22 21:01:20 +02:00
|
|
|
return "avg(" + statsFuncFieldsToString(sa.fields) + ")"
|
2024-05-12 16:33:29 +02:00
|
|
|
}
|
|
|
|
|
2024-05-20 04:08:30 +02:00
|
|
|
func (sa *statsAvg) updateNeededFields(neededFields fieldsSet) {
|
2024-05-22 21:01:20 +02:00
|
|
|
updateNeededFieldsForStatsFunc(neededFields, sa.fields)
|
2024-05-12 16:33:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (sa *statsAvg) newStatsProcessor() (statsProcessor, int) {
|
|
|
|
sap := &statsAvgProcessor{
|
|
|
|
sa: sa,
|
|
|
|
}
|
|
|
|
return sap, int(unsafe.Sizeof(*sap))
|
|
|
|
}
|
|
|
|
|
|
|
|
type statsAvgProcessor struct {
|
|
|
|
sa *statsAvg
|
|
|
|
|
|
|
|
sum float64
|
|
|
|
count uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sap *statsAvgProcessor) updateStatsForAllRows(br *blockResult) int {
|
2024-05-22 21:01:20 +02:00
|
|
|
fields := sap.sa.fields
|
|
|
|
if len(fields) == 0 {
|
2024-05-12 16:33:29 +02:00
|
|
|
// Scan all the columns
|
|
|
|
for _, c := range br.getColumns() {
|
|
|
|
f, count := c.sumValues(br)
|
|
|
|
sap.sum += f
|
|
|
|
sap.count += uint64(count)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Scan the requested columns
|
2024-05-22 21:01:20 +02:00
|
|
|
for _, field := range fields {
|
2024-05-12 16:33:29 +02:00
|
|
|
c := br.getColumnByName(field)
|
|
|
|
f, count := c.sumValues(br)
|
|
|
|
sap.sum += f
|
|
|
|
sap.count += uint64(count)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sap *statsAvgProcessor) updateStatsForRow(br *blockResult, rowIdx int) int {
|
2024-05-22 21:01:20 +02:00
|
|
|
fields := sap.sa.fields
|
|
|
|
if len(fields) == 0 {
|
2024-05-12 16:33:29 +02:00
|
|
|
// Scan all the fields for the given row
|
|
|
|
for _, c := range br.getColumns() {
|
2024-05-20 04:08:30 +02:00
|
|
|
f, ok := c.getFloatValueAtRow(br, rowIdx)
|
|
|
|
if ok {
|
2024-05-12 16:33:29 +02:00
|
|
|
sap.sum += f
|
|
|
|
sap.count++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Scan only the given fields for the given row
|
2024-05-22 21:01:20 +02:00
|
|
|
for _, field := range fields {
|
2024-05-12 16:33:29 +02:00
|
|
|
c := br.getColumnByName(field)
|
2024-05-20 04:08:30 +02:00
|
|
|
f, ok := c.getFloatValueAtRow(br, rowIdx)
|
|
|
|
if ok {
|
2024-05-12 16:33:29 +02:00
|
|
|
sap.sum += f
|
|
|
|
sap.count++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sap *statsAvgProcessor) mergeState(sfp statsProcessor) {
|
|
|
|
src := sfp.(*statsAvgProcessor)
|
|
|
|
sap.sum += src.sum
|
|
|
|
sap.count += src.count
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sap *statsAvgProcessor) finalizeStats() string {
|
|
|
|
avg := sap.sum / float64(sap.count)
|
|
|
|
return strconv.FormatFloat(avg, 'f', -1, 64)
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseStatsAvg(lex *lexer) (*statsAvg, error) {
|
2024-05-22 21:01:20 +02:00
|
|
|
fields, err := parseStatsFuncFields(lex, "avg")
|
2024-05-12 16:33:29 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
sa := &statsAvg{
|
2024-05-22 21:01:20 +02:00
|
|
|
fields: fields,
|
2024-05-12 16:33:29 +02:00
|
|
|
}
|
|
|
|
return sa, nil
|
|
|
|
}
|
2024-05-22 21:01:20 +02:00
|
|
|
|
|
|
|
func parseStatsFuncFields(lex *lexer, funcName string) ([]string, error) {
|
|
|
|
if !lex.isKeyword(funcName) {
|
|
|
|
return nil, fmt.Errorf("unexpected func; got %q; want %q", lex.token, funcName)
|
|
|
|
}
|
|
|
|
lex.nextToken()
|
|
|
|
fields, err := parseFieldNamesInParens(lex)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot parse %q args: %w", funcName, err)
|
|
|
|
}
|
|
|
|
if len(fields) == 0 || slices.Contains(fields, "*") {
|
|
|
|
fields = nil
|
|
|
|
}
|
|
|
|
return fields, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func statsFuncFieldsToString(fields []string) string {
|
|
|
|
if len(fields) == 0 {
|
|
|
|
return "*"
|
|
|
|
}
|
|
|
|
return fieldsToString(fields)
|
|
|
|
}
|
|
|
|
|
|
|
|
func fieldsToString(fields []string) string {
|
|
|
|
a := make([]string, len(fields))
|
|
|
|
for i, f := range fields {
|
|
|
|
a[i] = quoteTokenIfNeeded(f)
|
|
|
|
}
|
|
|
|
return strings.Join(a, ", ")
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateNeededFieldsForStatsFunc(neededFields fieldsSet, fields []string) {
|
|
|
|
if len(fields) == 0 {
|
|
|
|
neededFields.add("*")
|
|
|
|
}
|
|
|
|
neededFields.addFields(fields)
|
|
|
|
}
|