Search in sources :

Example 1 with IntersectKeySets

use of zipkin2.storage.cassandra.internal.call.IntersectKeySets in project zipkin by openzipkin.

the class CassandraSpanStore method getTraces.

/**
 * This fans out into a number of requests corresponding to query input. In simplest case, there
 * is less than a day of data queried, and only one expression. This implies one call to fetch
 * trace IDs and another to retrieve the span details.
 *
 * <p>The amount of backend calls increase in dimensions of query complexity, days of data, and
 * limit of traces requested. For example, a query like "http.path=/foo and error" will be two
 * select statements for the expression, possibly follow-up calls for pagination (when over 5K
 * rows match). Once IDs are parsed, there's one call for each 5K rows of span data. This means
 * "http.path=/foo and error" is minimally 3 network calls, the first two in parallel.
 */
@Override
public Call<List<List<Span>>> getTraces(QueryRequest request) {
    if (!searchEnabled)
        return Call.emptyList();
    TimestampRange timestampRange = timestampRange(request);
    // If we have to make multiple queries, over fetch on indexes as they don't return distinct
    // (trace id, timestamp) rows. This mitigates intersection resulting in < limit traces
    final int traceIndexFetchSize = request.limit() * indexFetchMultiplier;
    List<Call<Map<String, Long>>> callsToIntersect = new ArrayList<>();
    List<String> annotationKeys = CassandraUtil.annotationKeys(request);
    for (String annotationKey : annotationKeys) {
        if (spanTable == null) {
            throw new IllegalArgumentException(request.annotationQueryString() + " query unsupported due to missing annotation_query index");
        }
        callsToIntersect.add(spanTable.newCall(request.serviceName(), annotationKey, timestampRange, traceIndexFetchSize));
    }
    // Bucketed calls can be expensive when service name isn't specified. This guards against abuse.
    if (request.remoteServiceName() != null || request.spanName() != null || request.minDuration() != null || callsToIntersect.isEmpty()) {
        callsToIntersect.add(newBucketedTraceIdCall(request, timestampRange, traceIndexFetchSize));
    }
    if (callsToIntersect.size() == 1) {
        return callsToIntersect.get(0).map(traceIdsSortedByDescTimestamp()).flatMap(spans.newFlatMapper(request));
    }
    // We achieve the AND goal, by intersecting each of the key sets.
    IntersectKeySets intersectedTraceIds = new IntersectKeySets(callsToIntersect);
    // @xxx the sorting by timestamp desc is broken here^
    return intersectedTraceIds.flatMap(spans.newFlatMapper(request));
}
Also used : Call(zipkin2.Call) ArrayList(java.util.ArrayList) IntersectKeySets(zipkin2.storage.cassandra.internal.call.IntersectKeySets)

Aggregations

ArrayList (java.util.ArrayList)1 Call (zipkin2.Call)1 IntersectKeySets (zipkin2.storage.cassandra.internal.call.IntersectKeySets)1