Exemple #1
0
 /** Returns a human readable string representation of the object. */
 public String toString() {
   // The argument passed to StringBuilder is a pretty good estimate of the
   // length of the final string based on the row key and number of elements.
   final String metric = metricName();
   final int size = size();
   final StringBuilder buf = new StringBuilder(80 + metric.length() + key.length * 4 + size * 16);
   final long base_time = baseTime();
   buf.append("RowSeq(")
       .append(key == null ? "<null>" : Arrays.toString(key))
       .append(" (metric=")
       .append(metric)
       .append("), base_time=")
       .append(base_time)
       .append(" (")
       .append(base_time > 0 ? new Date(base_time * 1000) : "no date")
       .append("), [");
   for (short i = 0; i < size; i++) {
     final short qual = Bytes.getShort(qualifiers, i * 2);
     buf.append('+').append((qual & 0xFFFF) >>> Const.FLAG_BITS);
     if (isInteger(i)) {
       buf.append(":long(").append(longValue(i));
     } else {
       buf.append(":float(").append(doubleValue(i));
     }
     buf.append(')');
     if (i != size - 1) {
       buf.append(", ");
     }
   }
   buf.append("])");
   return buf.toString();
 }
Exemple #2
0
 public DataPoint next() {
   if (!hasNext()) {
     throw new NoSuchElementException("no more elements");
   }
   qualifier = Bytes.getShort(qualifiers, qual_index);
   qual_index += 2;
   final byte flags = (byte) qualifier;
   value_index += (flags & Const.LENGTH_MASK) + 1;
   // LOG.debug("next -> now=" + toStringSummary());
   return this;
 }
Exemple #3
0
 /**
  * Extracts the value of a cell containing a data point.
  *
  * @param values The contents of a cell in HBase.
  * @param value_idx The offset inside {@code values} at which the value starts.
  * @param flags The flags for this value.
  * @return The value of the cell.
  */
 static long extractIntegerValue(final byte[] values, final int value_idx, final byte flags) {
   switch (flags & Const.LENGTH_MASK) {
     case 7:
       return Bytes.getLong(values, value_idx);
     case 3:
       return Bytes.getInt(values, value_idx);
     case 1:
       return Bytes.getShort(values, value_idx);
     case 0:
       return values[value_idx] & 0xFF;
   }
   throw new IllegalDataException(
       "Integer value @ " + value_idx + " not on 8/4/2/1 bytes in " + Arrays.toString(values));
 }
Exemple #4
0
 public void seek(final long timestamp) {
   if ((timestamp & 0xFFFFFFFF00000000L) != 0) { // negative or not 32 bits
     throw new IllegalArgumentException("invalid timestamp: " + timestamp);
   }
   qual_index = 0;
   value_index = 0;
   final int len = qualifiers.length;
   while (qual_index < len && peekNextTimestamp() < timestamp) {
     qual_index += 2;
     final byte flags = (byte) qualifier;
     value_index += (flags & Const.LENGTH_MASK) + 1;
   }
   if (qual_index > 0) {
     qualifier = Bytes.getShort(qualifiers, qual_index - 2);
   }
   // LOG.debug("seek to " + timestamp + " -> now=" + toStringSummary());
 }
Exemple #5
0
  /**
   * Merges another HBase row into this one. When two continuous rows in HBase have data points that
   * are close enough together that they could be stored into the same row, it makes sense to merge
   * them into the same {@link RowSeq} instance in memory in order to save RAM.
   *
   * @param row The compacted HBase row to merge into this instance.
   * @throws IllegalStateException if {@link #setRow} wasn't called first.
   * @throws IllegalArgumentException if the data points in the argument aren't close enough to
   *     those in this instance time-wise to be all merged together.
   */
  void addRow(final KeyValue row) {
    if (this.key == null) {
      throw new IllegalStateException("setRow was never called on " + this);
    }

    final byte[] key = row.getRow();
    final long base_time = Bytes.getUnsignedInt(key, UniqueIds.metrics().width());
    final int time_adj = (int) (base_time - baseTime());
    if (time_adj <= 0) {
      // Corner case: if the time difference is 0 and the key is the same, it
      // means we've already added this row, possibly parts of it.  This
      // doesn't normally happen but can happen if the scanner we're using
      // timed out (its lease expired for whatever reason), in which case
      // asynchbase will transparently re-open the scanner and start scanning
      // from the row key we were on at the time the timeout happened.  In
      // that case, the easiest thing to do is to discard everything we know
      // about this row and start over, since we're going to get the full row
      // again anyway.
      if (time_adj != 0 || !Bytes.equals(this.key, key)) {
        throw new IllegalDataException(
            "Attempt to add a row with a base_time="
                + base_time
                + " <= baseTime()="
                + baseTime()
                + "; Row added="
                + row
                + ", this="
                + this);
      }
      this.key = null; // To keep setRow happy.
      this.qualifiers = null; // Throw away our previous work.
      this.values = null; // free();
      setRow(row);
      return;
    }

    final byte[] qual = row.getQualifier();
    final int len = qual.length;
    int last_delta = Bytes.getUnsignedShort(qualifiers, qualifiers.length - 2);
    last_delta >>= Const.FLAG_BITS;

    final int old_qual_len = qualifiers.length;
    final byte[] newquals = new byte[old_qual_len + len];
    System.arraycopy(qualifiers, 0, newquals, 0, old_qual_len);
    // Adjust the delta in all the qualifiers.
    for (int i = 0; i < len; i += 2) {
      short qualifier = Bytes.getShort(qual, i);
      final int time_delta = time_adj + ((qualifier & 0xFFFF) >>> Const.FLAG_BITS);
      if (!canTimeDeltaFit(time_delta)) {
        throw new IllegalDataException(
            "time_delta at index "
                + i
                + " is too large: "
                + time_delta
                + " (qualifier=0x"
                + Integer.toHexString(qualifier & 0xFFFF)
                + " baseTime()="
                + baseTime()
                + ", base_time="
                + base_time
                + ", time_adj="
                + time_adj
                + ") for "
                + row
                + " to be added to "
                + this);
      }
      if (last_delta >= time_delta) {
        LOG.error(
            "new timestamp = "
                + (baseTime() + time_delta)
                + " (index="
                + i
                + ") is < previous="
                + (baseTime() + last_delta)
                + " in addRow with row="
                + row
                + " in this="
                + this);
        return; // Ignore this row, it came out of order.
      }
      qualifier = (short) ((time_delta << Const.FLAG_BITS) | (qualifier & Const.FLAGS_MASK));
      Bytes.setShort(newquals, qualifier, old_qual_len + i);
    }
    this.qualifiers = newquals;

    final byte[] val = row.getValue();
    // If both the current `values' and the new `val' are single values, then
    // we neither of them has a meta data byte so we need to add one to be
    // consistent with what we expect from compacted values.  Otherwise, we
    // need to subtract 1 from the value length.
    final int old_val_len = values.length - (old_qual_len == 2 ? 0 : 1);
    final byte[] newvals =
        new byte
            [old_val_len
                + val.length
                // Only add a meta-data byte if the new values don't have it.
                + (len == 2 ? 1 : 0)];
    System.arraycopy(values, 0, newvals, 0, old_val_len);
    System.arraycopy(val, 0, newvals, old_val_len, val.length);
    assert newvals[newvals.length - 1] == 0
        : "Incorrect meta data byte after merge of "
            + row
            + " resulting qualifiers="
            + Arrays.toString(qualifiers)
            + ", values="
            + Arrays.toString(newvals)
            + ", old values="
            + Arrays.toString(values);
    this.values = newvals;
  }