func NewTopOrBottomAggregator(name string, v *parser.Value, isTop bool, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, fmt.Sprintf("function %s() requires at exactly 2 arguments", name)) } if v.Elems[1].Type != parser.ValueInt { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("function %s() second parameter expect int", name)) } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } limit, err := strconv.ParseInt(v.Elems[1].Name, 10, 64) if err != nil { return nil, err } if limit < 1 { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("function %s() second parameter must be > 0", name)) } return &TopOrBottomAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, name: name, isTop: isTop, defaultValue: wrappedDefaultValue, alias: v.Alias, limit: limit}, nil }
func NewCountAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function count() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function count() doesn't work with wildcards") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } if v.Elems[0].Type != parser.ValueSimpleName { innerName := strings.ToLower(v.Elems[0].Name) init := registeredAggregators[innerName] if init == nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", innerName)) } inner, err := init(q, v.Elems[0], defaultValue) if err != nil { return nil, err } return NewCompositeAggregator(&CountAggregator{AbstractAggregator{}, wrappedDefaultValue, v.Alias}, inner) } return &CountAggregator{AbstractAggregator{}, wrappedDefaultValue, v.Alias}, nil }
func NewPercentileAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) != 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function percentile() requires exactly two arguments") } if value.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.WrongNumberOfArguments, "wildcard cannot be used with percentile") } percentile, err := strconv.ParseFloat(value.Elems[1].Name, 64) if err != nil || percentile <= 0 || percentile >= 100 { return nil, common.NewQueryError(common.InvalidArgument, "function percentile() requires a numeric second argument between 0 and 100") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } functionName := "percentile" if value.Alias != "" { functionName = value.Alias } return &PercentileAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, functionName: functionName, percentile: percentile, defaultValue: wrappedDefaultValue, }, nil }
func NewDerivativeAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function derivative() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function derivative() doesn't work with wildcards") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } da := &DerivativeAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, defaultValue: wrappedDefaultValue, alias: v.Alias, } da.duration, _, err = q.GetGroupByClause().GetGroupByTime() if err != nil { return nil, err } return da, nil }
func (self *QueryEngine) executeCountQueryWithGroupBy(query *parser.SelectQuery, yield func(*protocol.Series) error) error { self.aggregateYield = yield duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return err } self.isAggregateQuery = true self.duration = duration self.aggregators = []Aggregator{} for _, value := range query.GetColumnNames() { if !value.IsFunctionCall() { continue } lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("%s", err)) } self.aggregators = append(self.aggregators, aggregator) } for _, elem := range query.GetGroupByClause().Elems { if elem.IsFunctionCall() { continue } self.elems = append(self.elems, elem) } self.fillWithZero = query.GetGroupByClause().FillWithZero // This is a special case for issue #426. If the start time is // specified and there's a group by clause and fill with zero, then // we need to fill the entire range from start time to end time if query.IsStartTimeSpecified() && self.duration != nil && self.fillWithZero { self.startTimeSpecified = true self.startTime = query.GetStartTime().Truncate(*self.duration).UnixNano() / 1000 self.endTime = query.GetEndTime().Truncate(*self.duration).UnixNano() / 1000 } self.initializeFields() err = self.distributeQuery(query, func(series *protocol.Series) error { if len(series.Points) == 0 { return nil } return self.aggregateValuesForSeries(series) }) return err }
func NewAggregatorEngine(query *parser.SelectQuery, next Processor) (*AggregatorEngine, error) { ae := &AggregatorEngine{ next: next, seriesStates: make(map[string]*SeriesState), ascending: query.Ascending, } var err error ae.duration, ae.irregularInterval, err = query.GetGroupByClause().GetGroupByTime() if err != nil { return nil, err } ae.aggregators = []Aggregator{} for _, value := range query.GetColumnNames() { if !value.IsFunctionCall() { continue } lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("%s", err)) } ae.aggregators = append(ae.aggregators, aggregator) } for _, elem := range query.GetGroupByClause().Elems { if elem.IsFunctionCall() { continue } ae.elems = append(ae.elems, elem) } ae.isFillQuery = query.GetGroupByClause().FillWithZero // This is a special case for issue #426. If the start time is // specified and there's a group by clause and fill with zero, then // we need to fill the entire range from start time to end time if query.IsStartTimeSpecified() && ae.duration != nil && ae.isFillQuery { ae.startTimeSpecified = true ae.startTime = query.GetStartTime().Truncate(*ae.duration).UnixNano() / 1000 ae.endTime = query.GetEndTime().Truncate(*ae.duration).UnixNano() / 1000 } ae.initializeFields() return ae, nil }
func (self *QueryEngine) executeCountQueryWithGroupBy(query *parser.SelectQuery, yield func(*protocol.Series) error) error { self.aggregateYield = yield duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return err } self.isAggregateQuery = true self.duration = duration self.aggregators = []Aggregator{} for _, value := range query.GetColumnNames() { if !value.IsFunctionCall() { continue } lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("%s", err)) } self.aggregators = append(self.aggregators, aggregator) } for _, elem := range query.GetGroupByClause().Elems { if elem.IsFunctionCall() { continue } self.elems = append(self.elems, elem) } self.fillWithZero = query.GetGroupByClause().FillWithZero self.initializeFields() err = self.distributeQuery(query, func(series *protocol.Series) error { if len(series.Points) == 0 { return nil } return self.aggregateValuesForSeries(series) }) return err }
// Process responses from the given channel. Returns true if // processing should stop for other channels. False otherwise. func (p *MergeChannelProcessor) processChannel(channel <-chan *protocol.Response) bool { for response := range channel { log4go.Debug("%s received %s", p, response) switch rt := response.GetType(); rt { // all these types end the stream case protocol.Response_HEARTBEAT, protocol.Response_END_STREAM: p.e <- nil return false case protocol.Response_ERROR: err := common.NewQueryError(common.InvalidArgument, response.GetErrorMessage()) p.e <- err return false case protocol.Response_QUERY: for _, s := range response.MultiSeries { log4go.Debug("Yielding to %s: %s", p.next.Name(), s) _, err := p.next.Yield(s) if err != nil { p.e <- err return true } } default: panic(fmt.Errorf("Unknown response type: %s", rt)) } } panic(errors.New("Reached end of method")) }
func NewMedianAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function median() requires exactly one argument") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } functionName := "median" if value.Alias != "" { functionName = value.Alias } aggregator := &PercentileAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, functionName: functionName, percentile: 50.0, defaultValue: wrappedDefaultValue, alias: value.Alias, } return aggregator, nil }
func NewModeAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) < 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mode() requires at least one argument") } // TODO: Mode can in fact take two argument, the second specifies // the "size", but it's not clear if size is set to 2 whether to // return at least 2 elements, or return the most common values and // the second most common values. The difference will be apparent if // the data set is multimodel and there are two most common // values. In the first case, the two most common values will be // returned, but in the second case the two most common values and // the second most common values will be returned if len(value.Elems) > 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mode() takes at most one arguments") } size := 1 if len(value.Elems) == 2 { switch value.Elems[1].Type { case parser.ValueInt: var err error size, err = strconv.Atoi(value.Elems[1].Name) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into an int", value.Elems[1].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a int", value.Elems[1].Name) } } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &ModeAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, defaultValue: wrappedDefaultValue, alias: value.Alias, size: size, }, nil }
func HashPassword(password string) ([]byte, error) { if length := len(password); length < 4 || length > 56 { return nil, common.NewQueryError(common.InvalidArgument, "Password must be more than 4 and less than 56 characters") } // The second arg is the cost of the hashing, higher is slower but makes it harder // to brute force, since it will be really slow and impractical return bcrypt.GenerateFromPassword([]byte(password), 10) }
func (self *CoordinatorImpl) runQuerySpec(querySpec *parser.QuerySpec, seriesWriter SeriesWriter) error { shards, processor, seriesClosed, err := self.getShardsAndProcessor(querySpec, seriesWriter) if err != nil { return err } if len(shards) == 0 { return fmt.Errorf("Couldn't look up columns") } defer func() { if processor != nil { processor.Close() <-seriesClosed } else { seriesWriter.Close() } }() shardConcurrentLimit := self.config.ConcurrentShardQueryLimit if self.shouldQuerySequentially(shards, querySpec) { log.Debug("Querying shards sequentially") shardConcurrentLimit = 1 } log.Debug("Shard concurrent limit: %d", shardConcurrentLimit) errors := make(chan error, shardConcurrentLimit) for i := 0; i < shardConcurrentLimit; i++ { errors <- nil } responseChannels := make(chan (<-chan *protocol.Response), shardConcurrentLimit) go self.readFromResponseChannels(processor, seriesWriter, querySpec.IsExplainQuery(), errors, responseChannels) err = self.queryShards(querySpec, shards, errors, responseChannels) // make sure we read the rest of the errors and responses for _err := range errors { if err == nil { err = _err } } for responsechan := range responseChannels { for response := range responsechan { if response.GetType() != endStreamResponse { continue } if response.ErrorMessage != nil && err == nil { err = common.NewQueryError(common.InvalidArgument, *response.ErrorMessage) } break } } return err }
func NewHistogramAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) < 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() requires at least one arguments") } if len(v.Elems) > 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() takes at most two arguments") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function histogram() doesn't work with wildcards") } bucketSize := 1.0 if len(v.Elems) == 2 { switch v.Elems[1].Type { case parser.ValueInt, parser.ValueFloat: var err error bucketSize, err = strconv.ParseFloat(v.Elems[1].Name, 64) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } } columnNames := []string{"bucket_start", "count"} if v.Alias != "" { columnNames[0] = fmt.Sprintf("%s_bucket_start", v.Alias) columnNames[1] = fmt.Sprintf("%s_count", v.Alias) } return &HistogramAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, bucketSize: bucketSize, columnNames: columnNames, }, nil }
func (self *CoordinatorImpl) readFromResponseChannels(processor cluster.QueryProcessor, writer SeriesWriter, isExplainQuery bool, errors chan<- error, responseChannels <-chan (<-chan *protocol.Response)) { defer close(errors) for responseChan := range responseChannels { for response := range responseChan { //log.Debug("GOT RESPONSE: ", response.Type, response.Series) log.Debug("GOT RESPONSE: %v", response.Type) if *response.Type == endStreamResponse || *response.Type == accessDeniedResponse { if response.ErrorMessage == nil { break } err := common.NewQueryError(common.InvalidArgument, *response.ErrorMessage) log.Error("Error while executing query: %s", err) errors <- err return } if response.Series == nil || len(response.Series.Points) == 0 { log.Debug("Series has no points, continue") continue } // if we don't have a processor, yield the point to the writer // this happens if shard took care of the query // otherwise client will get points from passthrough engine if processor != nil { // if the data wasn't aggregated at the shard level, aggregate // the data here log.Debug("YIELDING: %d points with %d columns for %s", len(response.Series.Points), len(response.Series.Fields), response.Series.GetName()) processor.YieldSeries(response.Series) continue } // If we have EXPLAIN query, we don't write actual points (of // response.Type Query) to the client if !(*response.Type == queryResponse && isExplainQuery) { writer.Write(response.Series) } } // once we're done with a response channel signal queryShards to // start querying a new shard errors <- nil } return }
func NewStandardDeviationAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function stddev() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function stddev() doesn't work with wildcards") } value, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &StandardDeviationAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, defaultValue: value, alias: v.Alias, }, nil }
func (self GroupByClause) GetGroupByTime() (*time.Duration, error) { for _, groupBy := range self.Elems { if groupBy.IsFunctionCall() && strings.ToLower(groupBy.Name) == "time" { // TODO: check the number of arguments and return an error if len(groupBy.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "time function only accepts one argument") } if groupBy.Elems[0].Type != ValueDuration { log.Debug("Get a time function without a duration argument %v", groupBy.Elems[0].Type) } arg := groupBy.Elems[0].Name durationInt, err := common.ParseTimeDuration(arg) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("invalid argument %s to the time function", arg)) } duration := time.Duration(durationInt) return &duration, nil } } return nil, nil }
func NewMeanAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mean() requires exactly one argument") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &MeanAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, defaultValue: wrappedDefaultValue, alias: value.Alias, }, nil }
func NewFirstOrLastAggregator(name string, v *parser.Value, isFirst bool, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, fmt.Sprintf("function %s() requires exactly one argument", name)) } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } if v.Alias != "" { name = v.Alias } return &FirstOrLastAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, name: name, isFirst: isFirst, defaultValue: wrappedDefaultValue, }, nil }
func NewCumulativeArithmeticAggregator(name string, value *parser.Value, initialValue float64, defaultValue *parser.Value, operation Operation) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function max() requires only one argument") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } if value.Alias != "" { name = value.Alias } return &CumulativeArithmeticAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, name: name, operation: operation, initialValue: initialValue, defaultValue: wrappedDefaultValue, }, nil }
func NewHistogramAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) < 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() requires at least one arguments") } if len(v.Elems) > 4 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() takes at most four arguments") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function histogram() doesn't work with wildcards") } bucketSize := 1.0 bucketStart := 0.0 explicitBucketStart := false bucketStop := 0.0 bucketStopIdx := -1 if len(v.Elems) > 1 { switch v.Elems[1].Type { case parser.ValueInt, parser.ValueFloat: var err error bucketSize, err = strconv.ParseFloat(v.Elems[1].Name, 64) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } if len(v.Elems) > 2 { switch v.Elems[2].Type { case parser.ValueInt, parser.ValueFloat: var err error bucketStart, err = strconv.ParseFloat(v.Elems[2].Name, 64) explicitBucketStart = true if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[2].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[2].Name) } if len(v.Elems) == 4 { switch v.Elems[3].Type { case parser.ValueInt, parser.ValueFloat: var err error bucketStop, err = strconv.ParseFloat(v.Elems[3].Name, 64) bucketStopIdx = int(math.Floor((bucketStop - bucketStart) / bucketSize)) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[3].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[3].Name) } } } } columnNames := []string{"bucket_start", "count"} if v.Alias != "" { columnNames[0] = fmt.Sprintf("%s_bucket_start", v.Alias) columnNames[1] = fmt.Sprintf("%s_count", v.Alias) } return &HistogramAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, bucketSize: bucketSize, bucketStart: bucketStart, explicitBucketStart: explicitBucketStart, bucketStopIdx: bucketStopIdx, columnNames: columnNames, }, nil }