From 35f5fb69578dc70c896bd9fd94da902837cf5923 Mon Sep 17 00:00:00 2001 From: Vishal Sharma Date: Tue, 27 Dec 2022 21:09:36 +0530 Subject: [PATCH] fix: respect durationSort feature flag on getSpanFilters API (#1900) * fix: respect durationSort feature flag on getSpanFilters API * chore: update DB query --- .../app/clickhouseReader/reader.go | 71 ++++++++++++------- pkg/query-service/model/response.go | 5 ++ 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go index ab07dbbd23..c7f1e45816 100644 --- a/pkg/query-service/app/clickhouseReader/reader.go +++ b/pkg/query-service/app/clickhouseReader/reader.go @@ -1177,33 +1177,54 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode traceFilterReponse.Status = map[string]uint64{"ok": 0, "error": 0} } case constants.Duration: - finalQuery := fmt.Sprintf("SELECT durationNano as numTotal FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.durationTable) - finalQuery += query - finalQuery += " ORDER BY durationNano LIMIT 1" - var dBResponse []model.DBResponseTotal - err := r.db.Select(ctx, &dBResponse, finalQuery, args...) - zap.S().Info(finalQuery) + err := r.featureFlags.CheckFeature(constants.DurationSort) + durationSortEnabled := err == nil + finalQuery := "" + if !durationSortEnabled { + // if duration sort is not enabled, we need to get the min and max duration from the index table + finalQuery = fmt.Sprintf("SELECT min(durationNano) as min, max(durationNano) as max FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.indexTable) + finalQuery += query + var dBResponse []model.DBResponseMinMax + err = r.db.Select(ctx, &dBResponse, finalQuery, args...) + zap.S().Info(finalQuery) + if err != nil { + zap.S().Debug("Error in processing sql query: ", err) + return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("Error in processing sql query: %s", err)} + } + if len(dBResponse) > 0 { + traceFilterReponse.Duration = map[string]uint64{"minDuration": dBResponse[0].Min, "maxDuration": dBResponse[0].Max} + } + } else { + // when duration sort is enabled, we need to get the min and max duration from the duration table + finalQuery = fmt.Sprintf("SELECT durationNano as numTotal FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.durationTable) + finalQuery += query + finalQuery += " ORDER BY durationNano LIMIT 1" + var dBResponse []model.DBResponseTotal + err = r.db.Select(ctx, &dBResponse, finalQuery, args...) + zap.S().Info(finalQuery) - if err != nil { - zap.S().Debug("Error in processing sql query: ", err) - return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("Error in processing sql query: %s", err)} - } - finalQuery = fmt.Sprintf("SELECT durationNano as numTotal FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.durationTable) - finalQuery += query - finalQuery += " ORDER BY durationNano DESC LIMIT 1" - var dBResponse2 []model.DBResponseTotal - err = r.db.Select(ctx, &dBResponse2, finalQuery, args...) - zap.S().Info(finalQuery) + if err != nil { + zap.S().Debug("Error in processing sql query: ", err) + return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("Error in processing sql query: %s", err)} + } - if err != nil { - zap.S().Debug("Error in processing sql query: ", err) - return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("Error in processing sql query: %s", err)} - } - if len(dBResponse) > 0 { - traceFilterReponse.Duration["minDuration"] = dBResponse[0].NumTotal - } - if len(dBResponse2) > 0 { - traceFilterReponse.Duration["maxDuration"] = dBResponse2[0].NumTotal + finalQuery = fmt.Sprintf("SELECT durationNano as numTotal FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.durationTable) + finalQuery += query + finalQuery += " ORDER BY durationNano DESC LIMIT 1" + var dBResponse2 []model.DBResponseTotal + err = r.db.Select(ctx, &dBResponse2, finalQuery, args...) + zap.S().Info(finalQuery) + + if err != nil { + zap.S().Debug("Error in processing sql query: ", err) + return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("Error in processing sql query: %s", err)} + } + if len(dBResponse) > 0 { + traceFilterReponse.Duration["minDuration"] = dBResponse[0].NumTotal + } + if len(dBResponse2) > 0 { + traceFilterReponse.Duration["maxDuration"] = dBResponse2[0].NumTotal + } } case constants.RPCMethod: finalQuery := fmt.Sprintf("SELECT rpcMethod, count() as count FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.indexTable) diff --git a/pkg/query-service/model/response.go b/pkg/query-service/model/response.go index 7ae79be456..d80a56c642 100644 --- a/pkg/query-service/model/response.go +++ b/pkg/query-service/model/response.go @@ -399,6 +399,11 @@ type DBResponseTotal struct { NumTotal uint64 `ch:"numTotal"` } +type DBResponseMinMax struct { + Min uint64 `ch:"min"` + Max uint64 `ch:"max"` +} + type SpanFiltersResponse struct { ServiceName map[string]uint64 `json:"serviceName"` Status map[string]uint64 `json:"status"`