@Override public int compare(KeyValue o1, KeyValue o2) { int d; if ((d = Bytes.memcmp(o1.key(), o2.key())) != 0) { return d; } else if ((d = Bytes.memcmp(o1.family(), o2.family())) != 0) { return d; } else if ((d = Bytes.memcmp(o1.qualifier(), o2.qualifier())) != 0) { return d; } else if ((d = Long.signum(o2.timestamp() - o1.timestamp())) != 0) { return d; } else { d = Bytes.memcmp(o1.value(), o2.value()); } return d; }
/** * Finds all the {@link Span}s that match this query. This is what actually scans the HBase table * and loads the data into {@link Span}s. * * @return A map from HBase row key to the {@link Span} for that row key. Since a {@link Span} * actually contains multiple HBase rows, the row key stored in the map has its timestamp * zero'ed out. * @throws HBaseException if there was a problem communicating with HBase to perform the search. * @throws IllegalArgumentException if bad data was retreived from HBase. */ private TreeMap<byte[], Span> findSpans() throws HBaseException { final short metric_width = tsdb.metrics.width(); final TreeMap<byte[], Span> spans = // The key is a row key from HBase. new TreeMap<byte[], Span>(new SpanCmp(metric_width)); int nrows = 0; int hbase_time = 0; // milliseconds. long starttime = System.nanoTime(); final Scanner scanner = getScanner(); try { ArrayList<ArrayList<KeyValue>> rows; while ((rows = scanner.nextRows().joinUninterruptibly()) != null) { hbase_time += (System.nanoTime() - starttime) / 1000000; for (final ArrayList<KeyValue> row : rows) { final byte[] key = row.get(0).key(); if (Bytes.memcmp(metric, key, 0, metric_width) != 0) { throw new IllegalDataException( "HBase returned a row that doesn't match" + " our scanner (" + scanner + ")! " + row + " does not start" + " with " + Arrays.toString(metric)); } Span datapoints = spans.get(key); if (datapoints == null) { datapoints = new Span(tsdb); spans.put(key, datapoints); } datapoints.addRow(tsdb.compact(row)); nrows++; starttime = System.nanoTime(); } } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException("Should never be here", e); } finally { hbase_time += (System.nanoTime() - starttime) / 1000000; scanlatency.add(hbase_time); } LOG.info(this + " matched " + nrows + " rows in " + spans.size() + " spans"); if (nrows == 0) { return null; } return spans; }
/** * Helper comparison function to compare tag name IDs. * * @param name_width Number of bytes used by a tag name ID. * @param tag A tag (array containing a tag name ID and a tag value ID). * @param group_by A tag name ID. * @return {@code true} number if {@code tag} should be used next (because it contains a smaller * ID), {@code false} otherwise. */ private boolean isTagNext(final short name_width, final byte[] tag, final byte[] group_by) { if (tag == null) { return false; } else if (group_by == null) { return true; } final int cmp = Bytes.memcmp(tag, group_by, 0, name_width); if (cmp == 0) { throw new AssertionError( "invariant violation: tag ID " + Arrays.toString(group_by) + " is both in 'tags' and" + " 'group_bys' in " + this); } return cmp < 0; }
@Override public Deferred<Object> call(final ArrayList<KeyValue> row) throws Exception { if (row == null || row.isEmpty()) { return Deferred.fromResult(null); } final ArrayList<byte[]> qualifiers = new ArrayList<byte[]>(row.size()); for (KeyValue column : row) { if (column.qualifier().length > RULE_PREFIX.length && Bytes.memcmp(RULE_PREFIX, column.qualifier(), 0, RULE_PREFIX.length) == 0) { qualifiers.add(column.qualifier()); } } final DeleteRequest delete = new DeleteRequest( tsdb.treeTable(), Tree.idToBytes(tree_id), Tree.TREE_FAMILY(), qualifiers.toArray(new byte[qualifiers.size()][])); return tsdb.getClient().delete(delete); }