Exemple #1
0
 /**
  * Extracts all the tags we must use to group results.
  *
  * <ul>
  *   <li>If a tag has the form {@code name=*} then we'll create one group per value we find for
  *       that tag.
  *   <li>If a tag has the form {@code name={v1,v2,..,vN}} then we'll create {@code N} groups.
  * </ul>
  *
  * In the both cases above, {@code name} will be stored in the {@code group_bys} attribute. In the
  * second case specifically, the {@code N} values would be stored in {@code group_by_values}, the
  * key in this map being {@code name}.
  *
  * @param tags The tags from which to extract the 'GROUP BY's. Each tag that represents a 'GROUP
  *     BY' will be removed from the map passed in argument.
  */
 private void findGroupBys(final Map<String, String> tags) {
   final Iterator<Map.Entry<String, String>> i = tags.entrySet().iterator();
   while (i.hasNext()) {
     final Map.Entry<String, String> tag = i.next();
     final String tagvalue = tag.getValue();
     if (tagvalue.equals("*") // 'GROUP BY' with any value.
         || tagvalue.indexOf('|', 1) >= 0) { // Multiple possible values.
       if (group_bys == null) {
         group_bys = new ArrayList<byte[]>();
       }
       group_bys.add(tsdb.tag_names.getId(tag.getKey()));
       i.remove();
       if (tagvalue.charAt(0) == '*') {
         continue; // For a 'GROUP BY' with any value, we're done.
       }
       // 'GROUP BY' with specific values.  Need to split the values
       // to group on and store their IDs in group_by_values.
       final String[] values = Tags.splitString(tagvalue, '|');
       if (group_by_values == null) {
         group_by_values = new ByteMap<byte[][]>();
       }
       final short value_width = tsdb.tag_values.width();
       final byte[][] value_ids = new byte[values.length][value_width];
       group_by_values.put(tsdb.tag_names.getId(tag.getKey()), value_ids);
       for (int j = 0; j < values.length; j++) {
         final byte[] value_id = tsdb.tag_values.getId(values[j]);
         System.arraycopy(value_id, 0, value_ids[j], 0, value_width);
       }
     }
   }
 }
Exemple #2
0
  /**
   * Creates the {@link SpanGroup}s to form the final results of this query.
   *
   * @param spans The {@link Span}s found for this query ({@link #findSpans}). Can be {@code null},
   *     in which case the array returned will be empty.
   * @return A possibly empty array of {@link SpanGroup}s built according to any 'GROUP BY'
   *     formulated in this query.
   */
  private DataPoints[] groupByAndAggregate(final TreeMap<byte[], Span> spans) {
    if (spans == null || spans.size() <= 0) {
      return NO_RESULT;
    }
    if (group_bys == null) {
      // We haven't been asked to find groups, so let's put all the spans
      // together in the same group.
      final SpanGroup group =
          new SpanGroup(
              tsdb,
              getScanStartTime(),
              getScanEndTime(),
              spans.values(),
              rate,
              this.noInterpolation,
              aggregator,
              sample_interval,
              downsampler);
      return new SpanGroup[] {group};
    }

    // Maps group value IDs to the SpanGroup for those values.  Say we've
    // been asked to group by two things: foo=* bar=* Then the keys in this
    // map will contain all the value IDs combinations we've seen.  If the
    // name IDs for `foo' and `bar' are respectively [0, 0, 7] and [0, 0, 2]
    // then we'll have group_bys=[[0, 0, 2], [0, 0, 7]] (notice it's sorted
    // by ID, so bar is first) and say we find foo=LOL bar=OMG as well as
    // foo=LOL bar=WTF and that the IDs of the tag values are:
    //   LOL=[0, 0, 1]  OMG=[0, 0, 4]  WTF=[0, 0, 3]
    // then the map will have two keys:
    //   - one for the LOL-OMG combination: [0, 0, 1, 0, 0, 4] and,
    //   - one for the LOL-WTF combination: [0, 0, 1, 0, 0, 3].
    final ByteMap<SpanGroup> groups = new ByteMap<SpanGroup>();
    final short value_width = tsdb.tag_values.width();
    final byte[] group = new byte[group_bys.size() * value_width];
    for (final Map.Entry<byte[], Span> entry : spans.entrySet()) {
      final byte[] row = entry.getKey();
      byte[] value_id = null;
      int i = 0;
      // TODO(tsuna): The following loop has a quadratic behavior.  We can
      // make it much better since both the row key and group_bys are sorted.
      for (final byte[] tag_id : group_bys) {
        value_id = Tags.getValueId(tsdb, row, tag_id);
        if (value_id == null) {
          break;
        }
        System.arraycopy(value_id, 0, group, i, value_width);
        i += value_width;
      }
      if (value_id == null) {
        LOG.error(
            "WTF?  Dropping span for row "
                + Arrays.toString(row)
                + " as it had no matching tag from the requested groups,"
                + " which is unexpected.  Query="
                + this);
        continue;
      }
      // LOG.info("Span belongs to group " + Arrays.toString(group) + ": " + Arrays.toString(row));
      SpanGroup thegroup = groups.get(group);
      if (thegroup == null) {
        thegroup =
            new SpanGroup(
                tsdb,
                getScanStartTime(),
                getScanEndTime(),
                null,
                rate,
                noInterpolation,
                aggregator,
                sample_interval,
                downsampler);
        // Copy the array because we're going to keep `group' and overwrite
        // its contents.  So we want the collection to have an immutable copy.
        final byte[] group_copy = new byte[group.length];
        System.arraycopy(group, 0, group_copy, 0, group.length);
        groups.put(group_copy, thegroup);
      }
      thegroup.add(entry.getValue());
    }
    // for (final Map.Entry<byte[], SpanGroup> entry : groups) {
    //  LOG.info("group for " + Arrays.toString(entry.getKey()) + ": " + entry.getValue());
    // }
    return groups.values().toArray(new SpanGroup[groups.size()]);
  }