Search in sources :

Example 16 with Callback

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

the class TreeRule method fetchRule.

/**
   * Attempts to retrieve the specified tree rule from storage.
   * @param tsdb The TSDB to use for storage access
   * @param tree_id ID of the tree the rule belongs to
   * @param level Level where the rule resides
   * @param order Order where the rule resides
   * @return A TreeRule object if found, null if it does not exist
   * @throws HBaseException if there was an issue
   * @throws IllegalArgumentException if the one of the required parameters was
   * missing
   * @throws JSONException if the object could not be serialized
   */
public static Deferred<TreeRule> fetchRule(final TSDB tsdb, final int tree_id, final int level, final int order) {
    if (tree_id < 1 || tree_id > 65535) {
        throw new IllegalArgumentException("Invalid Tree ID");
    }
    if (level < 0) {
        throw new IllegalArgumentException("Invalid rule level");
    }
    if (order < 0) {
        throw new IllegalArgumentException("Invalid rule order");
    }
    // fetch the whole row
    final GetRequest get = new GetRequest(tsdb.treeTable(), Tree.idToBytes(tree_id));
    get.family(Tree.TREE_FAMILY());
    get.qualifier(getQualifier(level, order));
    /**
     * Called after fetching to parse the results
     */
    final class FetchCB implements Callback<Deferred<TreeRule>, ArrayList<KeyValue>> {

        @Override
        public Deferred<TreeRule> call(final ArrayList<KeyValue> row) {
            if (row == null || row.isEmpty()) {
                return Deferred.fromResult(null);
            }
            return Deferred.fromResult(parseFromStorage(row.get(0)));
        }
    }
    return tsdb.getClient().get(get).addCallbackDeferring(new FetchCB());
}
Also used : Callback(com.stumbleupon.async.Callback) KeyValue(org.hbase.async.KeyValue) GetRequest(org.hbase.async.GetRequest) ArrayList(java.util.ArrayList)

Example 17 with Callback

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

the class TreeRule method deleteAllRules.

/**
   * Attempts to delete all rules belonging to the given tree.
   * @param tsdb The TSDB to use for storage access
   * @param tree_id ID of the tree the rules belongs to
   * @return A deferred to wait on for completion. The value has no meaning and
   * may be null.
   * @throws HBaseException if there was an issue
   * @throws IllegalArgumentException if the one of the required parameters was
   * missing
   */
public static Deferred<Object> deleteAllRules(final TSDB tsdb, final int tree_id) {
    if (tree_id < 1 || tree_id > 65535) {
        throw new IllegalArgumentException("Invalid Tree ID");
    }
    // fetch the whole row
    final GetRequest get = new GetRequest(tsdb.treeTable(), Tree.idToBytes(tree_id));
    get.family(Tree.TREE_FAMILY());
    /**
     * Called after fetching the requested row. If the row is empty, we just
     * return, otherwise we compile a list of qualifiers to delete and submit
     * a single delete request to storage.
     */
    final class GetCB implements Callback<Deferred<Object>, ArrayList<KeyValue>> {

        @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);
        }
    }
    return tsdb.getClient().get(get).addCallbackDeferring(new GetCB());
}
Also used : KeyValue(org.hbase.async.KeyValue) Callback(com.stumbleupon.async.Callback) GetRequest(org.hbase.async.GetRequest) ArrayList(java.util.ArrayList) DeleteRequest(org.hbase.async.DeleteRequest)

Example 18 with Callback

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

the class TreeRule method syncToStorage.

/**
   * Attempts to write the rule to storage via CompareAndSet, merging changes
   * with an existing rule.
   * <b>Note:</b> If the local object didn't have any fields set by the caller
   * or there weren't any changes, then the data will not be written and an 
   * exception will be thrown.
   * <b>Note:</b> This method also validates the rule, making sure that proper
   * combinations of data exist before writing to storage.
   * @param tsdb The TSDB to use for storage access
   * @param overwrite When the RPC method is PUT, will overwrite all user
   * accessible fields
   * @return True if the CAS call succeeded, false if the stored data was
   * modified in flight. This should be retried if that happens.
   * @throws HBaseException if there was an issue
   * @throws IllegalArgumentException if parsing failed or the tree ID was 
   * invalid or validation failed
   * @throws IllegalStateException if the data hasn't changed. This is OK!
   * @throws JSONException if the object could not be serialized
   */
public Deferred<Boolean> syncToStorage(final TSDB tsdb, final boolean overwrite) {
    if (tree_id < 1 || tree_id > 65535) {
        throw new IllegalArgumentException("Invalid Tree ID");
    }
    // if there aren't any changes, save time and bandwidth by not writing to
    // storage
    boolean has_changes = false;
    for (Map.Entry<String, Boolean> entry : changed.entrySet()) {
        if (entry.getValue()) {
            has_changes = true;
            break;
        }
    }
    if (!has_changes) {
        LOG.trace(this + " does not have changes, skipping sync to storage");
        throw new IllegalStateException("No changes detected in the rule");
    }
    /**
     * Executes the CAS after retrieving existing rule from storage, if it
     * exists.
     */
    final class StoreCB implements Callback<Deferred<Boolean>, TreeRule> {

        final TreeRule local_rule;

        public StoreCB(final TreeRule local_rule) {
            this.local_rule = local_rule;
        }

        /**
       * @return True if the CAS was successful, false if not
       */
        @Override
        public Deferred<Boolean> call(final TreeRule fetched_rule) {
            TreeRule stored_rule = fetched_rule;
            final byte[] original_rule = stored_rule == null ? new byte[0] : JSON.serializeToBytes(stored_rule);
            if (stored_rule == null) {
                stored_rule = local_rule;
            } else {
                if (!stored_rule.copyChanges(local_rule, overwrite)) {
                    LOG.debug(this + " does not have changes, skipping sync to storage");
                    throw new IllegalStateException("No changes detected in the rule");
                }
            }
            // reset the local change map so we don't keep writing on subsequent
            // requests
            initializeChangedMap();
            // validate before storing
            stored_rule.validateRule();
            final PutRequest put = new PutRequest(tsdb.treeTable(), Tree.idToBytes(tree_id), Tree.TREE_FAMILY(), getQualifier(level, order), JSON.serializeToBytes(stored_rule));
            return tsdb.getClient().compareAndSet(put, original_rule);
        }
    }
    // start the callback chain by fetching from storage
    return fetchRule(tsdb, tree_id, level, order).addCallbackDeferring(new StoreCB(this));
}
Also used : Callback(com.stumbleupon.async.Callback) PutRequest(org.hbase.async.PutRequest) HashMap(java.util.HashMap) Map(java.util.Map)

Example 19 with Callback

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

the class AnnotationRpc method executeBulkUpdate.

/**
   * Performs CRU methods on a list of annotation objects to reduce calls to
   * the API. Only supports body content and adding or updating annotation
   * objects. Deletions are separate.
   * @param tsdb The TSD to which we belong
   * @param method The request method
   * @param query The query to parse and respond to
   */
void executeBulkUpdate(final TSDB tsdb, final HttpMethod method, HttpQuery query) {
    final List<Annotation> notes;
    try {
        notes = query.serializer().parseAnnotationsV1();
    } catch (IllegalArgumentException e) {
        throw new BadRequestException(e);
    } catch (JSONException e) {
        throw new BadRequestException(e);
    }
    final List<Deferred<Annotation>> callbacks = new ArrayList<Deferred<Annotation>>(notes.size());
    /**
     * Storage callback used to determine if the storage call was successful
     * or not. Also returns the updated object from storage.
     */
    class SyncCB implements Callback<Deferred<Annotation>, Boolean> {

        private final Annotation note;

        public SyncCB(final Annotation note) {
            this.note = note;
        }

        @Override
        public Deferred<Annotation> call(Boolean success) throws Exception {
            if (!success) {
                throw new BadRequestException(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Failed to save an Annotation to storage", "This may be caused by another process modifying storage data: " + note);
            }
            return Annotation.getAnnotation(tsdb, note.getTSUID(), note.getStartTime());
        }
    }
    /**
     * Simple callback that will index the updated annotation
     */
    class IndexCB implements Callback<Deferred<Annotation>, Annotation> {

        @Override
        public Deferred<Annotation> call(final Annotation note) throws Exception {
            tsdb.indexAnnotation(note);
            return Deferred.fromResult(note);
        }
    }
    for (Annotation note : notes) {
        try {
            Deferred<Annotation> deferred = note.syncToStorage(tsdb, method == HttpMethod.PUT).addCallbackDeferring(new SyncCB(note));
            Deferred<Annotation> indexer = deferred.addCallbackDeferring(new IndexCB());
            callbacks.add(indexer);
        } catch (IllegalStateException e) {
            LOG.info("No changes for annotation: " + note);
        } catch (IllegalArgumentException e) {
            throw new BadRequestException(HttpResponseStatus.BAD_REQUEST, e.getMessage(), "Annotation error: " + note, e);
        }
    }
    try {
        // wait untill all of the syncs have completed, then rebuild the list
        // of annotations using the data synced from storage.
        Deferred.group(callbacks).joinUninterruptibly();
        notes.clear();
        for (Deferred<Annotation> note : callbacks) {
            notes.add(note.joinUninterruptibly());
        }
        query.sendReply(query.serializer().formatAnnotationsV1(notes));
    } catch (IllegalArgumentException e) {
        throw new BadRequestException(e);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) JSONException(net.opentsdb.utils.JSONException) Annotation(net.opentsdb.meta.Annotation) IOException(java.io.IOException) JSONException(net.opentsdb.utils.JSONException) Callback(com.stumbleupon.async.Callback)

Example 20 with Callback

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

the class TimeSeriesLookup method lookupAsync.

/**
   * Lookup time series associated with the given metric, tagk, tagv or tag 
   * pairs. Either the meta table or the data table will be scanned. If no
   * metric is given, a full table scan must be performed and this call may take
   * a long time to complete. 
   * When dumping to stdout, if an ID can't be looked up, it will be logged and
   * skipped.
   * @return A list of TSUIDs matching the given lookup query.
   * @throws NoSuchUniqueName if any of the given names fail to resolve to a 
   * UID.
   * @since 2.2
   */
public Deferred<List<byte[]>> lookupAsync() {
    final Pattern tagv_regex = tagv_filter != null ? Pattern.compile(tagv_filter) : null;
    // we don't really know what size the UIDs will resolve to so just grab
    // a decent amount.
    final StringBuffer buf = to_stdout ? new StringBuffer(2048) : null;
    final long start = System.currentTimeMillis();
    final int limit;
    if (query.getLimit() > 0) {
        if (query.useMeta() || Const.SALT_WIDTH() < 1) {
            limit = query.getLimit();
        } else if (query.getLimit() < Const.SALT_BUCKETS()) {
            limit = 1;
        } else {
            limit = query.getLimit() / Const.SALT_BUCKETS();
        }
    } else {
        limit = 0;
    }
    class ScannerCB implements Callback<Deferred<List<byte[]>>, ArrayList<ArrayList<KeyValue>>> {

        private final Scanner scanner;

        // used to avoid dupes when scanning the data table
        private byte[] last_tsuid = null;

        private int rows_read;

        ScannerCB(final Scanner scanner) {
            this.scanner = scanner;
        }

        Deferred<List<byte[]>> scan() {
            return scanner.nextRows().addCallbackDeferring(this);
        }

        @Override
        public Deferred<List<byte[]>> call(final ArrayList<ArrayList<KeyValue>> rows) throws Exception {
            if (rows == null) {
                scanner.close();
                if (query.useMeta() || Const.SALT_WIDTH() < 1) {
                    LOG.debug("Lookup query matched " + tsuids.size() + " time series in " + (System.currentTimeMillis() - start) + " ms");
                }
                return Deferred.fromResult(tsuids);
            }
            for (final ArrayList<KeyValue> row : rows) {
                if (limit > 0 && rows_read >= limit) {
                    // little recursion to close the scanner and log above.
                    return call(null);
                }
                final byte[] tsuid = query.useMeta() ? row.get(0).key() : UniqueId.getTSUIDFromKey(row.get(0).key(), TSDB.metrics_width(), Const.TIMESTAMP_BYTES);
                // string objects.
                if (tagv_regex != null && !tagv_regex.matcher(new String(tsuid, CHARSET)).find()) {
                    continue;
                }
                if (to_stdout) {
                    if (last_tsuid != null && Bytes.memcmp(last_tsuid, tsuid) == 0) {
                        continue;
                    }
                    last_tsuid = tsuid;
                    try {
                        buf.append(UniqueId.uidToString(tsuid)).append(" ");
                        buf.append(RowKey.metricNameAsync(tsdb, tsuid).joinUninterruptibly());
                        buf.append(" ");
                        final List<byte[]> tag_ids = UniqueId.getTagPairsFromTSUID(tsuid);
                        final Map<String, String> resolved_tags = Tags.resolveIdsAsync(tsdb, tag_ids).joinUninterruptibly();
                        for (final Map.Entry<String, String> tag_pair : resolved_tags.entrySet()) {
                            buf.append(tag_pair.getKey()).append("=").append(tag_pair.getValue()).append(" ");
                        }
                    } catch (NoSuchUniqueId nsui) {
                        LOG.error("Unable to resolve UID in TSUID (" + UniqueId.uidToString(tsuid) + ") " + nsui.getMessage());
                    }
                    // reset the buffer so we can re-use it
                    buf.setLength(0);
                } else {
                    tsuids.add(tsuid);
                }
                ++rows_read;
            }
            return scan();
        }

        @Override
        public String toString() {
            return "Scanner callback";
        }
    }
    class CompleteCB implements Callback<List<byte[]>, ArrayList<List<byte[]>>> {

        @Override
        public List<byte[]> call(final ArrayList<List<byte[]>> unused) throws Exception {
            LOG.debug("Lookup query matched " + tsuids.size() + " time series in " + (System.currentTimeMillis() - start) + " ms");
            return tsuids;
        }

        @Override
        public String toString() {
            return "Final async lookup callback";
        }
    }
    class UIDCB implements Callback<Deferred<List<byte[]>>, Object> {

        @Override
        public Deferred<List<byte[]>> call(Object arg0) throws Exception {
            if (!query.useMeta() && Const.SALT_WIDTH() > 0 && metric_uid != null) {
                final ArrayList<Deferred<List<byte[]>>> deferreds = new ArrayList<Deferred<List<byte[]>>>(Const.SALT_BUCKETS());
                for (int i = 0; i < Const.SALT_BUCKETS(); i++) {
                    deferreds.add(new ScannerCB(getScanner(i)).scan());
                }
                return Deferred.group(deferreds).addCallback(new CompleteCB());
            } else {
                return new ScannerCB(getScanner(0)).scan();
            }
        }

        @Override
        public String toString() {
            return "UID resolution callback";
        }
    }
    return resolveUIDs().addCallbackDeferring(new UIDCB());
}
Also used : Pattern(java.util.regex.Pattern) Scanner(org.hbase.async.Scanner) KeyValue(org.hbase.async.KeyValue) Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) Callback(com.stumbleupon.async.Callback) NoSuchUniqueId(net.opentsdb.uid.NoSuchUniqueId) ArrayList(java.util.ArrayList) List(java.util.List) Map(java.util.Map)

Aggregations

Callback (com.stumbleupon.async.Callback)59 ArrayList (java.util.ArrayList)47 KeyValue (org.hbase.async.KeyValue)30 Deferred (com.stumbleupon.async.Deferred)29 GetRequest (org.hbase.async.GetRequest)17 HashMap (java.util.HashMap)15 Map (java.util.Map)15 IOException (java.io.IOException)13 Scanner (org.hbase.async.Scanner)12 PutRequest (org.hbase.async.PutRequest)11 DeferredGroupException (com.stumbleupon.async.DeferredGroupException)9 List (java.util.List)9 HBaseException (org.hbase.async.HBaseException)9 TreeMap (java.util.TreeMap)8 DeleteRequest (org.hbase.async.DeleteRequest)7 IncomingDataPoint (net.opentsdb.core.IncomingDataPoint)6 DataPoints (net.opentsdb.core.DataPoints)5 TSSubQuery (net.opentsdb.core.TSSubQuery)5 TSQuery (net.opentsdb.core.TSQuery)4 Annotation (net.opentsdb.meta.Annotation)4