use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.
the class Tree method deleteTree.
/**
* Attempts to delete all branches, leaves, collisions and not-matched entries
* for the given tree. Optionally can delete the tree definition and rules as
* well.
* <b>Warning:</b> This call can take a long time to complete so it should
* only be done from a command line or issues once via RPC and allowed to
* process. Multiple deletes running at the same time on the same tree
* shouldn't be an issue but it's a waste of resources.
* @param tsdb The TSDB to use for storage access
* @param tree_id ID of the tree to delete
* @param delete_definition Whether or not the tree definition and rule set
* should be deleted as well
* @return True if the deletion completed successfully, false if there was an
* issue.
* @throws HBaseException if there was an issue
* @throws IllegalArgumentException if the tree ID was invalid
*/
public static Deferred<Boolean> deleteTree(final TSDB tsdb, final int tree_id, final boolean delete_definition) {
if (tree_id < 1 || tree_id > 65535) {
throw new IllegalArgumentException("Invalid Tree ID");
}
// scan all of the rows starting with the tree ID. We can't just delete the
// rows as there may be other types of data. Thus we have to check the
// qualifiers of every column to see if it's safe to delete
final byte[] start = idToBytes(tree_id);
final byte[] end = idToBytes(tree_id + 1);
final Scanner scanner = tsdb.getClient().newScanner(tsdb.treeTable());
scanner.setStartKey(start);
scanner.setStopKey(end);
scanner.setFamily(TREE_FAMILY);
final Deferred<Boolean> completed = new Deferred<Boolean>();
/**
* Scanner callback that loops through all rows between tree id and
* tree id++ searching for tree related columns to delete.
*/
final class DeleteTreeScanner implements Callback<Deferred<Boolean>, ArrayList<ArrayList<KeyValue>>> {
// list where we'll store delete requests for waiting on
private final ArrayList<Deferred<Object>> delete_deferreds = new ArrayList<Deferred<Object>>();
/**
* Fetches the next set of rows from the scanner and adds this class as
* a callback
* @return The list of delete requests when the scanner returns a null set
*/
public Deferred<Boolean> deleteTree() {
return scanner.nextRows().addCallbackDeferring(this);
}
@Override
public Deferred<Boolean> call(ArrayList<ArrayList<KeyValue>> rows) throws Exception {
if (rows == null) {
completed.callback(true);
return null;
}
for (final ArrayList<KeyValue> row : rows) {
// one delete request per row. We'll almost always delete the whole
// row, so just preallocate the entire row.
ArrayList<byte[]> qualifiers = new ArrayList<byte[]>(row.size());
for (KeyValue column : row) {
// tree
if (delete_definition && Bytes.equals(TREE_QUALIFIER, column.qualifier())) {
LOG.trace("Deleting tree defnition in row: " + Branch.idToString(column.key()));
qualifiers.add(column.qualifier());
// branches
} else if (Bytes.equals(Branch.BRANCH_QUALIFIER(), column.qualifier())) {
LOG.trace("Deleting branch in row: " + Branch.idToString(column.key()));
qualifiers.add(column.qualifier());
// leaves
} else if (column.qualifier().length > Leaf.LEAF_PREFIX().length && Bytes.memcmp(Leaf.LEAF_PREFIX(), column.qualifier(), 0, Leaf.LEAF_PREFIX().length) == 0) {
LOG.trace("Deleting leaf in row: " + Branch.idToString(column.key()));
qualifiers.add(column.qualifier());
// collisions
} else if (column.qualifier().length > COLLISION_PREFIX.length && Bytes.memcmp(COLLISION_PREFIX, column.qualifier(), 0, COLLISION_PREFIX.length) == 0) {
LOG.trace("Deleting collision in row: " + Branch.idToString(column.key()));
qualifiers.add(column.qualifier());
// not matched
} else if (column.qualifier().length > NOT_MATCHED_PREFIX.length && Bytes.memcmp(NOT_MATCHED_PREFIX, column.qualifier(), 0, NOT_MATCHED_PREFIX.length) == 0) {
LOG.trace("Deleting not matched in row: " + Branch.idToString(column.key()));
qualifiers.add(column.qualifier());
// tree rule
} else if (delete_definition && column.qualifier().length > TreeRule.RULE_PREFIX().length && Bytes.memcmp(TreeRule.RULE_PREFIX(), column.qualifier(), 0, TreeRule.RULE_PREFIX().length) == 0) {
LOG.trace("Deleting tree rule in row: " + Branch.idToString(column.key()));
qualifiers.add(column.qualifier());
}
}
if (qualifiers.size() > 0) {
final DeleteRequest delete = new DeleteRequest(tsdb.treeTable(), row.get(0).key(), TREE_FAMILY, qualifiers.toArray(new byte[qualifiers.size()][]));
delete_deferreds.add(tsdb.getClient().delete(delete));
}
}
/**
* Callback used as a kind of buffer so that we don't wind up loading
* thousands or millions of delete requests into memory and possibly run
* into a StackOverflowError or general OOM. The scanner defaults are
* our limit so each pass of the scanner will wait for the previous set
* of deferreds to complete before continuing
*/
final class ContinueCB implements Callback<Deferred<Boolean>, ArrayList<Object>> {
public Deferred<Boolean> call(ArrayList<Object> objects) {
LOG.debug("Purged [" + objects.size() + "] columns, continuing");
delete_deferreds.clear();
// call ourself again to get the next set of rows from the scanner
return deleteTree();
}
}
// call ourself again after waiting for the existing delete requests
// to complete
Deferred.group(delete_deferreds).addCallbackDeferring(new ContinueCB());
return null;
}
}
// start the scanner
new DeleteTreeScanner().deleteTree();
return completed;
}
use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.
the class UniqueIdRpc method handleUIDMeta.
/**
* Handles CRUD calls to individual UIDMeta data entries
* @param tsdb The TSDB from the RPC router
* @param query The query for this request
*/
private void handleUIDMeta(final TSDB tsdb, final HttpQuery query) {
final HttpMethod method = query.getAPIMethod();
// GET
if (method == HttpMethod.GET) {
final String uid = query.getRequiredQueryStringParam("uid");
final UniqueIdType type = UniqueId.stringToUniqueIdType(query.getRequiredQueryStringParam("type"));
try {
final UIDMeta meta = UIDMeta.getUIDMeta(tsdb, type, uid).joinUninterruptibly();
query.sendReply(query.serializer().formatUidMetaV1(meta));
} catch (NoSuchUniqueId e) {
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Could not find the requested UID", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
// POST
} else if (method == HttpMethod.POST || method == HttpMethod.PUT) {
final UIDMeta meta;
if (query.hasContent()) {
meta = query.serializer().parseUidMetaV1();
} else {
meta = this.parseUIDMetaQS(query);
}
/**
* 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<UIDMeta>, Boolean> {
@Override
public Deferred<UIDMeta> call(Boolean success) throws Exception {
if (!success) {
throw new BadRequestException(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Failed to save the UIDMeta to storage", "This may be caused by another process modifying storage data");
}
return UIDMeta.getUIDMeta(tsdb, meta.getType(), meta.getUID());
}
}
try {
final Deferred<UIDMeta> process_meta = meta.syncToStorage(tsdb, method == HttpMethod.PUT).addCallbackDeferring(new SyncCB());
final UIDMeta updated_meta = process_meta.joinUninterruptibly();
tsdb.indexUIDMeta(updated_meta);
query.sendReply(query.serializer().formatUidMetaV1(updated_meta));
} catch (IllegalStateException e) {
query.sendStatusOnly(HttpResponseStatus.NOT_MODIFIED);
} catch (IllegalArgumentException e) {
throw new BadRequestException(e);
} catch (NoSuchUniqueId e) {
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Could not find the requested UID", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
// DELETE
} else if (method == HttpMethod.DELETE) {
final UIDMeta meta;
if (query.hasContent()) {
meta = query.serializer().parseUidMetaV1();
} else {
meta = this.parseUIDMetaQS(query);
}
try {
meta.delete(tsdb).joinUninterruptibly();
tsdb.deleteUIDMeta(meta);
} catch (IllegalArgumentException e) {
throw new BadRequestException("Unable to delete UIDMeta information", e);
} catch (NoSuchUniqueId e) {
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Could not find the requested UID", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
query.sendStatusOnly(HttpResponseStatus.NO_CONTENT);
} else {
throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED, "Method not allowed", "The HTTP method [" + method.getName() + "] is not permitted for this endpoint");
}
}
use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.
the class UniqueIdRpc method handleTSMeta.
/**
* Handles CRUD calls to individual TSMeta data entries
* @param tsdb The TSDB from the RPC router
* @param query The query for this request
*/
private void handleTSMeta(final TSDB tsdb, final HttpQuery query) {
final HttpMethod method = query.getAPIMethod();
// GET
if (method == HttpMethod.GET) {
String tsuid = null;
if (query.hasQueryStringParam("tsuid")) {
tsuid = query.getQueryStringParam("tsuid");
try {
final TSMeta meta = TSMeta.getTSMeta(tsdb, tsuid).joinUninterruptibly();
if (meta != null) {
query.sendReply(query.serializer().formatTSMetaV1(meta));
} else {
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Could not find Timeseries meta data");
}
} catch (NoSuchUniqueName e) {
// the timeseries meta data
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Unable to find one of the UIDs", e);
} catch (BadRequestException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
String mquery = query.getRequiredQueryStringParam("m");
// m is of the following forms:
// metric[{tag=value,...}]
// where the parts in square brackets `[' .. `]' are optional.
final HashMap<String, String> tags = new HashMap<String, String>();
String metric = null;
try {
metric = Tags.parseWithMetric(mquery, tags);
} catch (IllegalArgumentException e) {
throw new BadRequestException(e);
}
final TSUIDQuery tsuid_query = new TSUIDQuery(tsdb, metric, tags);
try {
final List<TSMeta> tsmetas = tsuid_query.getTSMetas().joinUninterruptibly();
query.sendReply(query.serializer().formatTSMetaListV1(tsmetas));
} catch (NoSuchUniqueName e) {
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Unable to find one of the UIDs", e);
} catch (BadRequestException e) {
throw e;
} catch (RuntimeException e) {
throw new BadRequestException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// POST / PUT
} else if (method == HttpMethod.POST || method == HttpMethod.PUT) {
final TSMeta meta;
if (query.hasContent()) {
meta = query.serializer().parseTSMetaV1();
} else {
meta = this.parseTSMetaQS(query);
}
/**
* 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<TSMeta>, Boolean> {
@Override
public Deferred<TSMeta> call(Boolean success) throws Exception {
if (!success) {
throw new BadRequestException(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Failed to save the TSMeta to storage", "This may be caused by another process modifying storage data");
}
return TSMeta.getTSMeta(tsdb, meta.getTSUID());
}
}
if (meta.getTSUID() == null || meta.getTSUID().isEmpty()) {
// we got a JSON object without TSUID. Try to find a timeseries spec of
// the form "m": "metric{tagk=tagv,...}"
final String metric = query.getRequiredQueryStringParam("m");
final boolean create = query.getQueryStringParam("create") != null && query.getQueryStringParam("create").equals("true");
final String tsuid = getTSUIDForMetric(metric, tsdb);
class WriteCounterIfNotPresentCB implements Callback<Boolean, Boolean> {
@Override
public Boolean call(Boolean exists) throws Exception {
if (!exists && create) {
final PutRequest put = new PutRequest(tsdb.metaTable(), UniqueId.stringToUid(tsuid), TSMeta.FAMILY(), TSMeta.COUNTER_QUALIFIER(), Bytes.fromLong(0));
tsdb.getClient().put(put);
}
return exists;
}
}
try {
// Check whether we have a TSMeta stored already
final boolean exists = TSMeta.metaExistsInStorage(tsdb, tsuid).joinUninterruptibly();
// set TSUID
meta.setTSUID(tsuid);
if (!exists && create) {
// Write 0 to counter column if not present
TSMeta.counterExistsInStorage(tsdb, UniqueId.stringToUid(tsuid)).addCallback(new WriteCounterIfNotPresentCB()).joinUninterruptibly();
// set TSUID
final Deferred<TSMeta> process_meta = meta.storeNew(tsdb).addCallbackDeferring(new SyncCB());
final TSMeta updated_meta = process_meta.joinUninterruptibly();
tsdb.indexTSMeta(updated_meta);
tsdb.processTSMetaThroughTrees(updated_meta);
query.sendReply(query.serializer().formatTSMetaV1(updated_meta));
} else if (exists) {
final Deferred<TSMeta> process_meta = meta.syncToStorage(tsdb, method == HttpMethod.PUT).addCallbackDeferring(new SyncCB());
final TSMeta updated_meta = process_meta.joinUninterruptibly();
tsdb.indexTSMeta(updated_meta);
query.sendReply(query.serializer().formatTSMetaV1(updated_meta));
} else {
throw new BadRequestException("Could not find TSMeta, specify \"create=true\" to create a new one.");
}
} catch (IllegalStateException e) {
query.sendStatusOnly(HttpResponseStatus.NOT_MODIFIED);
} catch (IllegalArgumentException e) {
throw new BadRequestException(e);
} catch (BadRequestException e) {
throw e;
} catch (NoSuchUniqueName e) {
// the timeseries meta data
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Unable to find one or more UIDs", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
try {
final Deferred<TSMeta> process_meta = meta.syncToStorage(tsdb, method == HttpMethod.PUT).addCallbackDeferring(new SyncCB());
final TSMeta updated_meta = process_meta.joinUninterruptibly();
tsdb.indexTSMeta(updated_meta);
query.sendReply(query.serializer().formatTSMetaV1(updated_meta));
} catch (IllegalStateException e) {
query.sendStatusOnly(HttpResponseStatus.NOT_MODIFIED);
} catch (IllegalArgumentException e) {
throw new BadRequestException(e);
} catch (NoSuchUniqueName e) {
// the timeseries meta data
throw new BadRequestException(HttpResponseStatus.NOT_FOUND, "Unable to find one or more UIDs", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// DELETE
} else if (method == HttpMethod.DELETE) {
final TSMeta meta;
if (query.hasContent()) {
meta = query.serializer().parseTSMetaV1();
} else {
meta = this.parseTSMetaQS(query);
}
try {
meta.delete(tsdb);
tsdb.deleteTSMeta(meta.getTSUID());
} catch (IllegalArgumentException e) {
throw new BadRequestException("Unable to delete TSMeta information", e);
}
query.sendStatusOnly(HttpResponseStatus.NO_CONTENT);
} else {
throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED, "Method not allowed", "The HTTP method [" + method.getName() + "] is not permitted for this endpoint");
}
}
use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.
the class UniqueId method deleteAsync.
/**
* Attempts to remove the mappings for the given string from the UID table
* as well as the cache. If used, the caller should remove the entry from all
* TSD caches as well.
* <p>
* WARNING: This is a best attempt only method in that we'll lookup the UID
* for the given string, then issue two delete requests, one for each mapping.
* If either mapping fails then the cache can be re-populated later on with
* stale data. In that case, please run the FSCK utility.
* <p>
* WARNING 2: This method will NOT delete time series data or TSMeta data
* associated with the UIDs. It only removes them from the UID table. Deleting
* a metric is generally safe as you won't query over it in the future. But
* deleting tag keys or values can cause queries to fail if they find data
* without a corresponding name.
*
* @param name The name of the UID to delete
* @return A deferred to wait on for completion. The result will be null if
* successful, an exception otherwise.
* @throws NoSuchUniqueName if the UID string did not exist in storage
* @throws IllegalStateException if the TSDB wasn't set for this UID object
* @since 2.2
*/
public Deferred<Object> deleteAsync(final String name) {
if (tsdb == null) {
throw new IllegalStateException("The TSDB is null for this UID object.");
}
final byte[] uid = new byte[id_width];
final ArrayList<Deferred<Object>> deferreds = new ArrayList<Deferred<Object>>(2);
/** Catches errors and still cleans out the cache */
class ErrCB implements Callback<Object, Exception> {
@Override
public Object call(final Exception ex) throws Exception {
name_cache.remove(name);
id_cache.remove(fromBytes(uid));
LOG.error("Failed to delete " + fromBytes(kind) + " UID " + name + " but still cleared the cache", ex);
return ex;
}
}
/** Used to wait on the group of delete requests */
class GroupCB implements Callback<Deferred<Object>, ArrayList<Object>> {
@Override
public Deferred<Object> call(final ArrayList<Object> response) throws Exception {
name_cache.remove(name);
id_cache.remove(fromBytes(uid));
LOG.info("Successfully deleted " + fromBytes(kind) + " UID " + name);
return Deferred.fromResult(null);
}
}
/** Called after fetching the UID from storage */
class LookupCB implements Callback<Deferred<Object>, byte[]> {
@Override
public Deferred<Object> call(final byte[] stored_uid) throws Exception {
if (stored_uid == null) {
return Deferred.fromError(new NoSuchUniqueName(kind(), name));
}
System.arraycopy(stored_uid, 0, uid, 0, id_width);
final DeleteRequest forward = new DeleteRequest(table, toBytes(name), ID_FAMILY, kind);
deferreds.add(tsdb.getClient().delete(forward));
final DeleteRequest reverse = new DeleteRequest(table, uid, NAME_FAMILY, kind);
deferreds.add(tsdb.getClient().delete(reverse));
final DeleteRequest meta = new DeleteRequest(table, uid, NAME_FAMILY, toBytes((type.toString().toLowerCase() + "_meta")));
deferreds.add(tsdb.getClient().delete(meta));
return Deferred.group(deferreds).addCallbackDeferring(new GroupCB());
}
}
final byte[] cached_uid = name_cache.get(name);
if (cached_uid == null) {
return getIdFromHBase(name).addCallbackDeferring(new LookupCB()).addErrback(new ErrCB());
}
System.arraycopy(cached_uid, 0, uid, 0, id_width);
final DeleteRequest forward = new DeleteRequest(table, toBytes(name), ID_FAMILY, kind);
deferreds.add(tsdb.getClient().delete(forward));
final DeleteRequest reverse = new DeleteRequest(table, uid, NAME_FAMILY, kind);
deferreds.add(tsdb.getClient().delete(reverse));
final DeleteRequest meta = new DeleteRequest(table, uid, NAME_FAMILY, toBytes((type.toString().toLowerCase() + "_meta")));
deferreds.add(tsdb.getClient().delete(meta));
return Deferred.group(deferreds).addCallbackDeferring(new GroupCB()).addErrback(new ErrCB());
}
use of com.stumbleupon.async.Deferred in project opentsdb by OpenTSDB.
the class TestSearchRpc method setupAnswerSearchQuery.
/**
* Configures an Answer to respond with when the tests call
* tsdb.executeSearch(), responding to the type of query requested with valid
* responses for parsing tests.
*/
private void setupAnswerSearchQuery() {
mock_plugin = mock(SearchPlugin.class);
Whitebox.setInternalState(tsdb, "search", mock_plugin);
when(mock_plugin.executeQuery((SearchQuery) any())).thenAnswer(new Answer<Deferred<SearchQuery>>() {
@Override
public Deferred<SearchQuery> answer(InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
search_query = (SearchQuery) args[0];
List<Object> results = new ArrayList<Object>(1);
// if we want an empty response, return an empty response
if (search_query.getQuery().toUpperCase().equals("EMTPY")) {
search_query.setResults(results);
search_query.setTotalResults(0);
return Deferred.fromResult(search_query);
}
switch(search_query.getType()) {
case TSMETA:
final TSMeta meta = new TSMeta("000001000001000001");
meta.setCreated(1356998400);
meta.setDescription("System CPU metric");
UIDMeta uid = new UIDMeta(UniqueIdType.METRIC, "000001");
final Field uid_name = UIDMeta.class.getDeclaredField("name");
uid_name.setAccessible(true);
uid_name.set(uid, "sys.cpu.0");
final Field metric = TSMeta.class.getDeclaredField("metric");
metric.setAccessible(true);
metric.set(meta, uid);
final ArrayList<UIDMeta> tags = new ArrayList<UIDMeta>(2);
uid = new UIDMeta(UniqueIdType.TAGK, "000001");
uid_name.set(uid, "host");
tags.add(uid);
uid = new UIDMeta(UniqueIdType.TAGV, "000001");
uid_name.set(uid, "web01");
tags.add(uid);
final Field tags_field = TSMeta.class.getDeclaredField("tags");
tags_field.setAccessible(true);
tags_field.set(meta, tags);
results.add(meta);
break;
case LOOKUP:
case TSMETA_SUMMARY:
final HashMap<String, Object> ts = new HashMap<String, Object>(1);
ts.put("metric", "sys.cpu.0");
final HashMap<String, String> tag_map = new HashMap<String, String>(2);
tag_map.put("host", "web01");
tag_map.put("owner", "ops");
ts.put("tags", tag_map);
ts.put("tsuid", "000001000001000001");
results.add(ts);
break;
case TSUIDS:
results.add("000001000001000001");
results.add("000002000002000002");
break;
case UIDMETA:
UIDMeta uid2 = new UIDMeta(UniqueIdType.METRIC, "000001");
final Field name_field = UIDMeta.class.getDeclaredField("name");
name_field.setAccessible(true);
name_field.set(uid2, "sys.cpu.0");
results.add(uid2);
uid2 = new UIDMeta(UniqueIdType.TAGK, "000001");
name_field.set(uid2, "host");
results.add(uid2);
break;
case ANNOTATION:
final Annotation note = new Annotation();
note.setStartTime(1356998400);
note.setEndTime(1356998460);
note.setDescription("Something went pear shaped");
note.setTSUID("000001000001000001");
results.add(note);
break;
}
search_query.setResults(results);
search_query.setTotalResults(results.size());
search_query.setTime(0.42F);
return Deferred.fromResult(search_query);
}
});
}
Aggregations