Search in sources :

Example 1 with Deferred

use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.

the class TSDB method shutdown.

/**
   * Gracefully shuts down this TSD instance.
   * <p>
   * The method must call {@code shutdown()} on all plugins as well as flush the
   * compaction queue.
   * @return A {@link Deferred} that will be called once all the un-committed
   * data has been successfully and durably stored, and all resources used by
   * this instance have been released.  The value of the deferred object
   * return is meaningless and unspecified, and can be {@code null}.
   * @throws HBaseException (deferred) if there was a problem sending
   * un-committed data to HBase.  Please refer to the {@link HBaseException}
   * hierarchy to handle the possible failures.  Some of them are easily
   * recoverable by retrying, some are not.
   */
public Deferred<Object> shutdown() {
    final ArrayList<Deferred<Object>> deferreds = new ArrayList<Deferred<Object>>();
    final class FinalShutdown implements Callback<Object, Object> {

        @Override
        public Object call(Object result) throws Exception {
            if (result instanceof Exception) {
                LOG.error("A previous shutdown failed", (Exception) result);
            }
            final Set<Timeout> timeouts = timer.stop();
            // TODO - at some point we should clean these up.
            if (timeouts.size() > 0) {
                LOG.warn("There were " + timeouts.size() + " timer tasks queued");
            }
            LOG.info("Completed shutting down the TSDB");
            return Deferred.fromResult(null);
        }
    }
    final class SEHShutdown implements Callback<Object, Object> {

        @Override
        public Object call(Object result) throws Exception {
            if (result instanceof Exception) {
                LOG.error("Shutdown of the HBase client failed", (Exception) result);
            }
            LOG.info("Shutting down storage exception handler plugin: " + storage_exception_handler.getClass().getCanonicalName());
            return storage_exception_handler.shutdown().addBoth(new FinalShutdown());
        }

        @Override
        public String toString() {
            return "SEHShutdown";
        }
    }
    final class HClientShutdown implements Callback<Deferred<Object>, ArrayList<Object>> {

        public Deferred<Object> call(final ArrayList<Object> args) {
            if (storage_exception_handler != null) {
                return client.shutdown().addBoth(new SEHShutdown());
            }
            return client.shutdown().addBoth(new FinalShutdown());
        }

        public String toString() {
            return "shutdown HBase client";
        }
    }
    final class ShutdownErrback implements Callback<Object, Exception> {

        public Object call(final Exception e) {
            final Logger LOG = LoggerFactory.getLogger(ShutdownErrback.class);
            if (e instanceof DeferredGroupException) {
                final DeferredGroupException ge = (DeferredGroupException) e;
                for (final Object r : ge.results()) {
                    if (r instanceof Exception) {
                        LOG.error("Failed to shutdown the TSD", (Exception) r);
                    }
                }
            } else {
                LOG.error("Failed to shutdown the TSD", e);
            }
            return new HClientShutdown().call(null);
        }

        public String toString() {
            return "shutdown HBase client after error";
        }
    }
    final class CompactCB implements Callback<Object, ArrayList<Object>> {

        public Object call(ArrayList<Object> compactions) throws Exception {
            return null;
        }
    }
    if (config.enable_compactions()) {
        LOG.info("Flushing compaction queue");
        deferreds.add(compactionq.flush().addCallback(new CompactCB()));
    }
    if (startup != null) {
        LOG.info("Shutting down startup plugin: " + startup.getClass().getCanonicalName());
        deferreds.add(startup.shutdown());
    }
    if (search != null) {
        LOG.info("Shutting down search plugin: " + search.getClass().getCanonicalName());
        deferreds.add(search.shutdown());
    }
    if (rt_publisher != null) {
        LOG.info("Shutting down RT plugin: " + rt_publisher.getClass().getCanonicalName());
        deferreds.add(rt_publisher.shutdown());
    }
    if (meta_cache != null) {
        LOG.info("Shutting down meta cache plugin: " + meta_cache.getClass().getCanonicalName());
        deferreds.add(meta_cache.shutdown());
    }
    if (storage_exception_handler != null) {
        LOG.info("Shutting down storage exception handler plugin: " + storage_exception_handler.getClass().getCanonicalName());
        deferreds.add(storage_exception_handler.shutdown());
    }
    if (ts_filter != null) {
        LOG.info("Shutting down time series filter plugin: " + ts_filter.getClass().getCanonicalName());
        deferreds.add(ts_filter.shutdown());
    }
    if (uid_filter != null) {
        LOG.info("Shutting down UID filter plugin: " + uid_filter.getClass().getCanonicalName());
        deferreds.add(uid_filter.shutdown());
    }
    // wait for plugins to shutdown before we close the client
    return deferreds.size() > 0 ? Deferred.group(deferreds).addCallbackDeferring(new HClientShutdown()).addErrback(new ShutdownErrback()) : new HClientShutdown().call(null);
}
Also used : Timeout(org.jboss.netty.util.Timeout) Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) Logger(org.slf4j.Logger) DeferredGroupException(com.stumbleupon.async.DeferredGroupException) InvocationTargetException(java.lang.reflect.InvocationTargetException) HBaseException(org.hbase.async.HBaseException) IOException(java.io.IOException) Callback(com.stumbleupon.async.Callback) DeferredGroupException(com.stumbleupon.async.DeferredGroupException)

Example 2 with Deferred

use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.

the class TsdbQuery method findSpans.

/**
   * 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 retrieved from HBase.
   */
private Deferred<TreeMap<byte[], Span>> findSpans() throws HBaseException {
    final short metric_width = tsdb.metrics.width();
    final // The key is a row key from HBase.
    TreeMap<byte[], Span> spans = new TreeMap<byte[], Span>(new SpanCmp((short) (Const.SALT_WIDTH() + metric_width)));
    // Copy only the filters that should trigger a tag resolution. If this list
    // is empty due to literals or a wildcard star, then we'll save a TON of
    // UID lookups
    final List<TagVFilter> scanner_filters;
    if (filters != null) {
        scanner_filters = new ArrayList<TagVFilter>(filters.size());
        for (final TagVFilter filter : filters) {
            if (filter.postScan()) {
                scanner_filters.add(filter);
            }
        }
    } else {
        scanner_filters = null;
    }
    if (Const.SALT_WIDTH() > 0) {
        final List<Scanner> scanners = new ArrayList<Scanner>(Const.SALT_BUCKETS());
        for (int i = 0; i < Const.SALT_BUCKETS(); i++) {
            scanners.add(getScanner(i));
        }
        scan_start_time = DateTime.nanoTime();
        return new SaltScanner(tsdb, metric, scanners, spans, scanner_filters, delete, query_stats, query_index).scan();
    }
    scan_start_time = DateTime.nanoTime();
    final Scanner scanner = getScanner();
    if (query_stats != null) {
        query_stats.addScannerId(query_index, 0, scanner.toString());
    }
    final Deferred<TreeMap<byte[], Span>> results = new Deferred<TreeMap<byte[], Span>>();
    /**
    * Scanner callback executed recursively each time we get a set of data
    * from storage. This is responsible for determining what columns are
    * returned and issuing requests to load leaf objects.
    * When the scanner returns a null set of rows, the method initiates the
    * final callback.
    */
    final class ScannerCB implements Callback<Object, ArrayList<ArrayList<KeyValue>>> {

        int nrows = 0;

        boolean seenAnnotation = false;

        long scanner_start = DateTime.nanoTime();

        long timeout = tsdb.getConfig().getLong("tsd.query.timeout");

        private final Set<String> skips = new HashSet<String>();

        private final Set<String> keepers = new HashSet<String>();

        // only used for salted scanners
        private final int index = 0;

        /** nanosecond timestamps */
        // reset each time we send an RPC to HBase
        private long fetch_start = 0;

        // cumulation of time waiting on HBase
        private long fetch_time = 0;

        // cumulation of time resolving UIDs
        private long uid_resolve_time = 0;

        private long uids_resolved = 0;

        // cumulation of time compacting
        private long compaction_time = 0;

        private long dps_pre_filter = 0;

        private long rows_pre_filter = 0;

        private long dps_post_filter = 0;

        private long rows_post_filter = 0;

        /** Error callback that will capture an exception from AsyncHBase and store
       * it so we can bubble it up to the caller.
       */
        class ErrorCB implements Callback<Object, Exception> {

            @Override
            public Object call(final Exception e) throws Exception {
                LOG.error("Scanner " + scanner + " threw an exception", e);
                close(e);
                return null;
            }
        }

        /**
      * Starts the scanner and is called recursively to fetch the next set of
      * rows from the scanner.
      * @return The map of spans if loaded successfully, null if no data was
      * found
      */
        public Object scan() {
            fetch_start = DateTime.nanoTime();
            return scanner.nextRows().addCallback(this).addErrback(new ErrorCB());
        }

        /**
      * Loops through each row of the scanner results and parses out data
      * points and optional meta data
      * @return null if no rows were found, otherwise the TreeMap with spans
      */
        @Override
        public Object call(final ArrayList<ArrayList<KeyValue>> rows) throws Exception {
            fetch_time += DateTime.nanoTime() - fetch_start;
            try {
                if (rows == null) {
                    scanlatency.add((int) DateTime.msFromNano(fetch_time));
                    LOG.info(TsdbQuery.this + " matched " + nrows + " rows in " + spans.size() + " spans in " + DateTime.msFromNano(fetch_time) + "ms");
                    close(null);
                    return null;
                }
                if (timeout > 0 && DateTime.msFromNanoDiff(DateTime.nanoTime(), scanner_start) > timeout) {
                    throw new InterruptedException("Query timeout exceeded!");
                }
                rows_pre_filter += rows.size();
                // used for UID resolution if a filter is involved
                final List<Deferred<Object>> lookups = filters != null && !filters.isEmpty() ? new ArrayList<Deferred<Object>>(rows.size()) : null;
                for (final ArrayList<KeyValue> row : rows) {
                    final byte[] key = row.get(0).key();
                    if (Bytes.memcmp(metric, key, 0, metric_width) != 0) {
                        scanner.close();
                        throw new IllegalDataException("HBase returned a row that doesn't match" + " our scanner (" + scanner + ")! " + row + " does not start" + " with " + Arrays.toString(metric));
                    }
                    // columns.
                    for (final KeyValue kv : row) {
                        if (kv.qualifier().length % 2 == 0) {
                            if (kv.qualifier().length == 2 || kv.qualifier().length == 4) {
                                ++dps_pre_filter;
                            } else {
                                // same precision. This is likely incorrect.
                                if (Internal.inMilliseconds(kv.qualifier())) {
                                    dps_pre_filter += (kv.qualifier().length / 4);
                                } else {
                                    dps_pre_filter += (kv.qualifier().length / 2);
                                }
                            }
                        } else if (kv.qualifier()[0] == AppendDataPoints.APPEND_COLUMN_PREFIX) {
                            // with appends we don't have a good rough estimate as the length
                            // can vary widely with the value length variability. Therefore we
                            // have to iterate.
                            int idx = 0;
                            int qlength = 0;
                            while (idx < kv.value().length) {
                                qlength = Internal.getQualifierLength(kv.value(), idx);
                                idx += qlength + Internal.getValueLengthFromQualifier(kv.value(), idx);
                                ++dps_pre_filter;
                            }
                        }
                    }
                    // TODO - byte set instead of a string for the uid may be faster
                    if (scanner_filters != null && !scanner_filters.isEmpty()) {
                        lookups.clear();
                        final String tsuid = UniqueId.uidToString(UniqueId.getTSUIDFromKey(key, TSDB.metrics_width(), Const.TIMESTAMP_BYTES));
                        if (skips.contains(tsuid)) {
                            continue;
                        }
                        if (!keepers.contains(tsuid)) {
                            final long uid_start = DateTime.nanoTime();
                            /** CB to called after all of the UIDs have been resolved */
                            class MatchCB implements Callback<Object, ArrayList<Boolean>> {

                                @Override
                                public Object call(final ArrayList<Boolean> matches) throws Exception {
                                    for (final boolean matched : matches) {
                                        if (!matched) {
                                            skips.add(tsuid);
                                            return null;
                                        }
                                    }
                                    // matched all, good data
                                    keepers.add(tsuid);
                                    processRow(key, row);
                                    return null;
                                }
                            }
                            /** Resolves all of the row key UIDs to their strings for filtering */
                            class GetTagsCB implements Callback<Deferred<ArrayList<Boolean>>, Map<String, String>> {

                                @Override
                                public Deferred<ArrayList<Boolean>> call(final Map<String, String> tags) throws Exception {
                                    uid_resolve_time += (DateTime.nanoTime() - uid_start);
                                    uids_resolved += tags.size();
                                    final List<Deferred<Boolean>> matches = new ArrayList<Deferred<Boolean>>(scanner_filters.size());
                                    for (final TagVFilter filter : scanner_filters) {
                                        matches.add(filter.match(tags));
                                    }
                                    return Deferred.group(matches);
                                }
                            }
                            lookups.add(Tags.getTagsAsync(tsdb, key).addCallbackDeferring(new GetTagsCB()).addBoth(new MatchCB()));
                        } else {
                            processRow(key, row);
                        }
                    } else {
                        processRow(key, row);
                    }
                }
                // if we don't have filters.
                if (lookups != null && lookups.size() > 0) {
                    class GroupCB implements Callback<Object, ArrayList<Object>> {

                        @Override
                        public Object call(final ArrayList<Object> group) throws Exception {
                            return scan();
                        }
                    }
                    return Deferred.group(lookups).addCallback(new GroupCB());
                } else {
                    return scan();
                }
            } catch (Exception e) {
                close(e);
                return null;
            }
        }

        /**
        * Finds or creates the span for this row, compacts it and stores it.
        * @param key The row key to use for fetching the span
        * @param row The row to add
        */
        void processRow(final byte[] key, final ArrayList<KeyValue> row) {
            ++rows_post_filter;
            if (delete) {
                final DeleteRequest del = new DeleteRequest(tsdb.dataTable(), key);
                tsdb.getClient().delete(del);
            }
            // columns.
            for (final KeyValue kv : row) {
                if (kv.qualifier().length % 2 == 0) {
                    if (kv.qualifier().length == 2 || kv.qualifier().length == 4) {
                        ++dps_post_filter;
                    } else {
                        // same precision. This is likely incorrect.
                        if (Internal.inMilliseconds(kv.qualifier())) {
                            dps_post_filter += (kv.qualifier().length / 4);
                        } else {
                            dps_post_filter += (kv.qualifier().length / 2);
                        }
                    }
                } else if (kv.qualifier()[0] == AppendDataPoints.APPEND_COLUMN_PREFIX) {
                    // with appends we don't have a good rough estimate as the length
                    // can vary widely with the value length variability. Therefore we
                    // have to iterate.
                    int idx = 0;
                    int qlength = 0;
                    while (idx < kv.value().length) {
                        qlength = Internal.getQualifierLength(kv.value(), idx);
                        idx += qlength + Internal.getValueLengthFromQualifier(kv.value(), idx);
                        ++dps_post_filter;
                    }
                }
            }
            Span datapoints = spans.get(key);
            if (datapoints == null) {
                datapoints = new Span(tsdb);
                spans.put(key, datapoints);
            }
            final long compaction_start = DateTime.nanoTime();
            final KeyValue compacted = tsdb.compact(row, datapoints.getAnnotations());
            compaction_time += (DateTime.nanoTime() - compaction_start);
            seenAnnotation |= !datapoints.getAnnotations().isEmpty();
            if (compacted != null) {
                // Can be null if we ignored all KVs.
                datapoints.addRow(compacted);
                ++nrows;
            }
        }

        void close(final Exception e) {
            scanner.close();
            if (query_stats != null) {
                query_stats.addScannerStat(query_index, index, QueryStat.SCANNER_TIME, DateTime.nanoTime() - scan_start_time);
                // Scanner Stats
                /* Uncomment when AsyncHBase has this feature:
           query_stats.addScannerStat(query_index, index, 
               QueryStat.ROWS_FROM_STORAGE, scanner.getRowsFetched());
           query_stats.addScannerStat(query_index, index, 
               QueryStat.COLUMNS_FROM_STORAGE, scanner.getColumnsFetched());
           query_stats.addScannerStat(query_index, index, 
               QueryStat.BYTES_FROM_STORAGE, scanner.getBytesFetched()); */
                query_stats.addScannerStat(query_index, index, QueryStat.HBASE_TIME, fetch_time);
                query_stats.addScannerStat(query_index, index, QueryStat.SUCCESSFUL_SCAN, e == null ? 1 : 0);
                // Post Scan stats
                query_stats.addScannerStat(query_index, index, QueryStat.ROWS_PRE_FILTER, rows_pre_filter);
                query_stats.addScannerStat(query_index, index, QueryStat.DPS_PRE_FILTER, dps_pre_filter);
                query_stats.addScannerStat(query_index, index, QueryStat.ROWS_POST_FILTER, rows_post_filter);
                query_stats.addScannerStat(query_index, index, QueryStat.DPS_POST_FILTER, dps_post_filter);
                query_stats.addScannerStat(query_index, index, QueryStat.SCANNER_UID_TO_STRING_TIME, uid_resolve_time);
                query_stats.addScannerStat(query_index, index, QueryStat.UID_PAIRS_RESOLVED, uids_resolved);
                query_stats.addScannerStat(query_index, index, QueryStat.COMPACTION_TIME, compaction_time);
            }
            if (e != null) {
                results.callback(e);
            } else if (nrows < 1 && !seenAnnotation) {
                results.callback(null);
            } else {
                results.callback(spans);
            }
        }
    }
    new ScannerCB().scan();
    return results;
}
Also used : Scanner(org.hbase.async.Scanner) HashSet(java.util.HashSet) Set(java.util.Set) KeyValue(org.hbase.async.KeyValue) Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) TagVFilter(net.opentsdb.query.filter.TagVFilter) TreeMap(java.util.TreeMap) DeferredGroupException(com.stumbleupon.async.DeferredGroupException) HBaseException(org.hbase.async.HBaseException) Callback(com.stumbleupon.async.Callback) Map(java.util.Map) ByteMap(org.hbase.async.Bytes.ByteMap) TreeMap(java.util.TreeMap) DeleteRequest(org.hbase.async.DeleteRequest)

Example 3 with Deferred

use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.

the class TsdbQuery method configureFromQuery.

@Override
public Deferred<Object> configureFromQuery(final TSQuery query, final int index) {
    if (query.getQueries() == null || query.getQueries().isEmpty()) {
        throw new IllegalArgumentException("Missing sub queries");
    }
    if (index < 0 || index > query.getQueries().size()) {
        throw new IllegalArgumentException("Query index was out of range");
    }
    final TSSubQuery sub_query = query.getQueries().get(index);
    setStartTime(query.startTime());
    setEndTime(query.endTime());
    setDelete(query.getDelete());
    query_index = index;
    query_stats = query.getQueryStats();
    // set common options
    aggregator = sub_query.aggregator();
    rate = sub_query.getRate();
    rate_options = sub_query.getRateOptions();
    if (rate_options == null) {
        rate_options = new RateOptions();
    }
    downsampler = sub_query.downsamplingSpecification();
    filters = sub_query.getFilters();
    explicit_tags = sub_query.getExplicitTags();
    // if we have tsuids set, that takes precedence
    if (sub_query.getTsuids() != null && !sub_query.getTsuids().isEmpty()) {
        tsuids = new ArrayList<String>(sub_query.getTsuids());
        String first_metric = "";
        for (final String tsuid : tsuids) {
            if (first_metric.isEmpty()) {
                first_metric = tsuid.substring(0, TSDB.metrics_width() * 2).toUpperCase();
                continue;
            }
            final String metric = tsuid.substring(0, TSDB.metrics_width() * 2).toUpperCase();
            if (!first_metric.equals(metric)) {
                throw new IllegalArgumentException("One or more TSUIDs did not share the same metric [" + first_metric + "] [" + metric + "]");
            }
        }
        return Deferred.fromResult(null);
    } else {
        /** Triggers the group by resolution if we had filters to resolve */
        class FilterCB implements Callback<Object, ArrayList<byte[]>> {

            @Override
            public Object call(final ArrayList<byte[]> results) throws Exception {
                findGroupBys();
                return null;
            }
        }
        /** Resolve and group by tags after resolving the metric */
        class MetricCB implements Callback<Deferred<Object>, byte[]> {

            @Override
            public Deferred<Object> call(final byte[] uid) throws Exception {
                metric = uid;
                if (filters != null) {
                    final List<Deferred<byte[]>> deferreds = new ArrayList<Deferred<byte[]>>(filters.size());
                    for (final TagVFilter filter : filters) {
                        deferreds.add(filter.resolveTagkName(tsdb));
                    }
                    return Deferred.group(deferreds).addCallback(new FilterCB());
                } else {
                    return Deferred.fromResult(null);
                }
            }
        }
        // fire off the callback chain by resolving the metric first
        return tsdb.metrics.getIdAsync(sub_query.getMetric()).addCallbackDeferring(new MetricCB());
    }
}
Also used : Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) TagVFilter(net.opentsdb.query.filter.TagVFilter) Callback(com.stumbleupon.async.Callback)

Example 4 with Deferred

use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.

the class AddDataExample method main.

public static void main(final String[] args) throws Exception {
    processArgs(args);
    // Create a config object with a path to the file for parsing. Or manually
    // override settings.
    // e.g. config.overrideConfig("tsd.storage.hbase.zk_quorum", "localhost");
    final Config config;
    if (pathToConfigFile != null && !pathToConfigFile.isEmpty()) {
        config = new Config(pathToConfigFile);
    } else {
        // Search for a default config from /etc/opentsdb/opentsdb.conf, etc.
        config = new Config(true);
    }
    final TSDB tsdb = new TSDB(config);
    // Declare new metric
    String metricName = "my.tsdb.test.metric";
    // First check to see it doesn't already exist
    // we don't actually need this for the first
    byte[] byteMetricUID;
    // addPoint().
    try {
        byteMetricUID = tsdb.getUID(UniqueIdType.METRIC, metricName);
    } catch (IllegalArgumentException iae) {
        System.out.println("Metric name not valid.");
        iae.printStackTrace();
        System.exit(1);
    } catch (NoSuchUniqueName nsune) {
        // If not, great. Create it.
        byteMetricUID = tsdb.assignUid("metric", metricName);
    }
    // Make a single datum
    long timestamp = System.currentTimeMillis() / 1000;
    long value = 314159;
    // Make key-val
    Map<String, String> tags = new HashMap<String, String>(1);
    tags.put("script", "example1");
    // Start timer
    long startTime1 = System.currentTimeMillis();
    // Write a number of data points at 30 second intervals. Each write will 
    // return a deferred (similar to a Java Future or JS Promise) that will 
    // be called on completion with either a "null" value on success or an
    // exception.
    int n = 100;
    ArrayList<Deferred<Object>> deferreds = new ArrayList<Deferred<Object>>(n);
    for (int i = 0; i < n; i++) {
        Deferred<Object> deferred = tsdb.addPoint(metricName, timestamp, value + i, tags);
        deferreds.add(deferred);
        timestamp += 30;
    }
    // Add the callbacks to the deferred object. (They might have already
    // returned, btw)
    // This will cause the calling thread to wait until the add has completed.
    System.out.println("Waiting for deferred result to return...");
    Deferred.groupInOrder(deferreds).addErrback(new AddDataExample().new errBack()).addCallback(new AddDataExample().new succBack()).join();
    // Alternatively you can add another callback here or use a join with a 
    // timeout argument.
    // End timer.
    long elapsedTime1 = System.currentTimeMillis() - startTime1;
    System.out.println("\nAdding " + n + " points took: " + elapsedTime1 + " milliseconds.\n");
    // Gracefully shutdown connection to TSDB. This is CRITICAL as it will 
    // flush any pending operations to HBase.
    tsdb.shutdown().join();
}
Also used : HashMap(java.util.HashMap) Config(net.opentsdb.utils.Config) Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) TSDB(net.opentsdb.core.TSDB) NoSuchUniqueName(net.opentsdb.uid.NoSuchUniqueName)

Example 5 with Deferred

use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.

the class Annotation method deleteRange.

/**
   * Deletes global or TSUID associated annotiations for the given time range.
   * @param tsdb The TSDB object to use for storage access
   * @param tsuid An optional TSUID. If set to null, then global annotations for
   * the given range will be deleted
   * @param start_time A start timestamp in milliseconds
   * @param end_time An end timestamp in millseconds
   * @return The number of annotations deleted
   * @throws IllegalArgumentException if the timestamps are invalid
   * @since 2.1
   */
public static Deferred<Integer> deleteRange(final TSDB tsdb, final byte[] tsuid, final long start_time, final long end_time) {
    if (end_time < 1) {
        throw new IllegalArgumentException("The end timestamp has not been set");
    }
    if (end_time < start_time) {
        throw new IllegalArgumentException("The end timestamp cannot be less than the start timestamp");
    }
    final List<Deferred<Object>> delete_requests = new ArrayList<Deferred<Object>>();
    int width = tsuid != null ? Const.SALT_WIDTH() + tsuid.length + Const.TIMESTAMP_BYTES : Const.SALT_WIDTH() + TSDB.metrics_width() + Const.TIMESTAMP_BYTES;
    final byte[] start_row = new byte[width];
    final byte[] end_row = new byte[width];
    // downsample to seconds for the row keys
    final long start = start_time / 1000;
    final long end = end_time / 1000;
    final long normalized_start = (start - (start % Const.MAX_TIMESPAN));
    final long normalized_end = (end - (end % Const.MAX_TIMESPAN) + Const.MAX_TIMESPAN);
    Bytes.setInt(start_row, (int) normalized_start, Const.SALT_WIDTH() + TSDB.metrics_width());
    Bytes.setInt(end_row, (int) normalized_end, Const.SALT_WIDTH() + TSDB.metrics_width());
    if (tsuid != null) {
        // first copy the metric UID then the tags
        System.arraycopy(tsuid, 0, start_row, Const.SALT_WIDTH(), TSDB.metrics_width());
        System.arraycopy(tsuid, 0, end_row, Const.SALT_WIDTH(), TSDB.metrics_width());
        width = Const.SALT_WIDTH() + TSDB.metrics_width() + Const.TIMESTAMP_BYTES;
        final int remainder = tsuid.length - TSDB.metrics_width();
        System.arraycopy(tsuid, TSDB.metrics_width(), start_row, width, remainder);
        System.arraycopy(tsuid, TSDB.metrics_width(), end_row, width, remainder);
    }
    /**
     * Iterates through the scanner results in an asynchronous manner, returning
     * once the scanner returns a null result set.
     */
    final class ScannerCB implements Callback<Deferred<List<Deferred<Object>>>, ArrayList<ArrayList<KeyValue>>> {

        final Scanner scanner;

        public ScannerCB() {
            scanner = tsdb.getClient().newScanner(tsdb.dataTable());
            scanner.setStartKey(start_row);
            scanner.setStopKey(end_row);
            scanner.setFamily(FAMILY);
            if (tsuid != null) {
                final List<String> tsuids = new ArrayList<String>(1);
                tsuids.add(UniqueId.uidToString(tsuid));
                Internal.createAndSetTSUIDFilter(scanner, tsuids);
            }
        }

        public Deferred<List<Deferred<Object>>> scan() {
            return scanner.nextRows().addCallbackDeferring(this);
        }

        @Override
        public Deferred<List<Deferred<Object>>> call(final ArrayList<ArrayList<KeyValue>> rows) throws Exception {
            if (rows == null || rows.isEmpty()) {
                return Deferred.fromResult(delete_requests);
            }
            for (final ArrayList<KeyValue> row : rows) {
                final long base_time = Internal.baseTime(tsdb, row.get(0).key());
                for (KeyValue column : row) {
                    if ((column.qualifier().length == 3 || column.qualifier().length == 5) && column.qualifier()[0] == PREFIX()) {
                        final long timestamp = timeFromQualifier(column.qualifier(), base_time);
                        if (timestamp < start_time || timestamp > end_time) {
                            continue;
                        }
                        final DeleteRequest delete = new DeleteRequest(tsdb.dataTable(), column.key(), FAMILY, column.qualifier());
                        delete_requests.add(tsdb.getClient().delete(delete));
                    }
                }
            }
            return scan();
        }
    }
    /** Called when the scanner is done. Delete requests may still be pending */
    final class ScannerDoneCB implements Callback<Deferred<ArrayList<Object>>, List<Deferred<Object>>> {

        @Override
        public Deferred<ArrayList<Object>> call(final List<Deferred<Object>> deletes) throws Exception {
            return Deferred.group(delete_requests);
        }
    }
    /** Waits on the group of deferreds to complete before returning the count */
    final class GroupCB implements Callback<Deferred<Integer>, ArrayList<Object>> {

        @Override
        public Deferred<Integer> call(final ArrayList<Object> deletes) throws Exception {
            return Deferred.fromResult(deletes.size());
        }
    }
    Deferred<ArrayList<Object>> scanner_done = new ScannerCB().scan().addCallbackDeferring(new ScannerDoneCB());
    return scanner_done.addCallbackDeferring(new GroupCB());
}
Also used : Scanner(org.hbase.async.Scanner) KeyValue(org.hbase.async.KeyValue) Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) Callback(com.stumbleupon.async.Callback) ArrayList(java.util.ArrayList) List(java.util.List) DeleteRequest(org.hbase.async.DeleteRequest)

Aggregations

Deferred (com.stumbleupon.async.Deferred)40 ArrayList (java.util.ArrayList)33 Callback (com.stumbleupon.async.Callback)29 IOException (java.io.IOException)14 KeyValue (org.hbase.async.KeyValue)14 HashMap (java.util.HashMap)12 Map (java.util.Map)11 Scanner (org.hbase.async.Scanner)11 HBaseException (org.hbase.async.HBaseException)9 DeferredGroupException (com.stumbleupon.async.DeferredGroupException)8 List (java.util.List)8 NoSuchUniqueName (net.opentsdb.uid.NoSuchUniqueName)8 DeleteRequest (org.hbase.async.DeleteRequest)6 TSSubQuery (net.opentsdb.core.TSSubQuery)5 Annotation (net.opentsdb.meta.Annotation)5 NoSuchUniqueId (net.opentsdb.uid.NoSuchUniqueId)5 JSONException (net.opentsdb.utils.JSONException)5 InvocationOnMock (org.mockito.invocation.InvocationOnMock)5 DataPoints (net.opentsdb.core.DataPoints)4 IncomingDataPoint (net.opentsdb.core.IncomingDataPoint)4