public long timestamp(final int i) { checkIndex(i); // Important: Span.addRow assumes this method to work in O(1). return baseTime() + (Bytes.getUnsignedShort(qualifiers, i * 2) >>> Const.FLAG_BITS); }
/** * Look a head to see the next timestamp. * * @throws IndexOutOfBoundsException if we reached the end already. */ long peekNextTimestamp() { return base_time + (Bytes.getUnsignedShort(qualifiers, qual_index) >>> Const.FLAG_BITS); }
/** * 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; }