use of com.stumbleupon.async.Callback in project opentsdb by OpenTSDB.
the class Annotation method getGlobalAnnotations.
/**
* Scans through the global annotation storage rows and returns a list of
* parsed annotation objects. If no annotations were found for the given
* timespan, the resulting list will be empty.
* @param tsdb The TSDB to use for storage access
* @param start_time Start time to scan from. May be 0
* @param end_time End time to scan to. Must be greater than 0
* @return A list with detected annotations. May be empty.
* @throws IllegalArgumentException if the end timestamp has not been set or
* the end time is less than the start time
*/
public static Deferred<List<Annotation>> getGlobalAnnotations(final TSDB tsdb, 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");
}
/**
* Scanner that loops through the [0, 0, 0, timestamp] rows looking for
* global annotations. Returns a list of parsed annotation objects.
* The list may be empty.
*/
final class ScannerCB implements Callback<Deferred<List<Annotation>>, ArrayList<ArrayList<KeyValue>>> {
final Scanner scanner;
final ArrayList<Annotation> annotations = new ArrayList<Annotation>();
/**
* Initializes the scanner
*/
public ScannerCB() {
final byte[] start = new byte[Const.SALT_WIDTH() + TSDB.metrics_width() + Const.TIMESTAMP_BYTES];
final byte[] end = new byte[Const.SALT_WIDTH() + TSDB.metrics_width() + Const.TIMESTAMP_BYTES];
final long normalized_start = (start_time - (start_time % Const.MAX_TIMESPAN));
final long normalized_end = (end_time - (end_time % Const.MAX_TIMESPAN) + Const.MAX_TIMESPAN);
Bytes.setInt(start, (int) normalized_start, Const.SALT_WIDTH() + TSDB.metrics_width());
Bytes.setInt(end, (int) normalized_end, Const.SALT_WIDTH() + TSDB.metrics_width());
scanner = tsdb.getClient().newScanner(tsdb.dataTable());
scanner.setStartKey(start);
scanner.setStopKey(end);
scanner.setFamily(FAMILY);
}
public Deferred<List<Annotation>> scan() {
return scanner.nextRows().addCallbackDeferring(this);
}
@Override
public Deferred<List<Annotation>> call(final ArrayList<ArrayList<KeyValue>> rows) throws Exception {
if (rows == null || rows.isEmpty()) {
return Deferred.fromResult((List<Annotation>) annotations);
}
for (final ArrayList<KeyValue> row : rows) {
for (KeyValue column : row) {
if ((column.qualifier().length == 3 || column.qualifier().length == 5) && column.qualifier()[0] == PREFIX()) {
Annotation note = JSON.parseToObject(column.value(), Annotation.class);
if (note.start_time < start_time || note.end_time > end_time) {
continue;
}
annotations.add(note);
}
}
}
return scan();
}
}
return new ScannerCB().scan();
}
use of com.stumbleupon.async.Callback in project opentsdb by OpenTSDB.
the class EDPtoDPS method getAggregatedTagsAsync.
@Override
public Deferred<List<String>> getAggregatedTagsAsync() {
final ByteSet tagks = edps[index].aggregatedTags();
final List<String> aggregated_tags = new ArrayList<String>(tagks.size());
final List<Deferred<String>> names = new ArrayList<Deferred<String>>(tagks.size());
for (final byte[] tagk : tagks) {
names.add(tsdb.getUidName(UniqueIdType.TAGK, tagk));
}
/** Adds the names to the aggregated_tags list */
final class ResolveCB implements Callback<List<String>, ArrayList<String>> {
@Override
public List<String> call(final ArrayList<String> names) throws Exception {
for (final String name : names) {
aggregated_tags.add(name);
}
return aggregated_tags;
}
}
return Deferred.group(names).addCallback(new ResolveCB());
}
use of com.stumbleupon.async.Callback in project opentsdb by OpenTSDB.
the class TSMeta method incrementAndGetCounter.
/**
* Increments the tsuid datapoint counter or creates a new counter. Also
* creates a new meta data entry if the counter did not exist.
* <b>Note:</b> This method also:
* <ul><li>Passes the new TSMeta object to the Search plugin after loading
* UIDMeta objects</li>
* <li>Passes the new TSMeta through all configured trees if enabled</li></ul>
* @param tsdb The TSDB to use for storage access
* @param tsuid The TSUID to increment or create
* @return 0 if the put failed, a positive LONG if the put was successful
* @throws HBaseException if there was a storage issue
* @throws JSONException if the data was corrupted
* @throws NoSuchUniqueName if one of the UIDMeta objects does not exist
*/
public static Deferred<Long> incrementAndGetCounter(final TSDB tsdb, final byte[] tsuid) {
/**
* Callback that will create a new TSMeta if the increment result is 1 or
* will simply return the new value.
*/
final class TSMetaCB implements Callback<Deferred<Long>, Long> {
/**
* Called after incrementing the counter and will create a new TSMeta if
* the returned value was 1 as well as pass the new meta through trees
* and the search indexer if configured.
* @return 0 if the put failed, a positive LONG if the put was successful
*/
@Override
public Deferred<Long> call(final Long incremented_value) throws Exception {
LOG.debug("Value: " + incremented_value);
if (incremented_value > 1) {
// whenever the user runs the full sync CLI
return Deferred.fromResult(incremented_value);
}
// create a new meta object with the current system timestamp. Ideally
// we would want the data point's timestamp, but that's much more data
// to keep track of and may not be accurate.
final TSMeta meta = new TSMeta(tsuid, System.currentTimeMillis() / 1000);
/**
* Called after the meta has been passed through tree processing. The
* result of the processing doesn't matter and the user may not even
* have it enabled, so we'll just return the counter.
*/
final class TreeCB implements Callback<Deferred<Long>, Boolean> {
@Override
public Deferred<Long> call(Boolean success) throws Exception {
return Deferred.fromResult(incremented_value);
}
}
/**
* Called after retrieving the newly stored TSMeta and loading
* associated UIDMeta objects. This class will also pass the meta to the
* search plugin and run it through any configured trees
*/
final class FetchNewCB implements Callback<Deferred<Long>, TSMeta> {
@Override
public Deferred<Long> call(TSMeta stored_meta) throws Exception {
// pass to the search plugin
tsdb.indexTSMeta(stored_meta);
// pass through the trees
return tsdb.processTSMetaThroughTrees(stored_meta).addCallbackDeferring(new TreeCB());
}
}
/**
* Called after the CAS to store the new TSMeta object. If the CAS
* failed then we return immediately with a 0 for the counter value.
* Otherwise we keep processing to load the meta and pass it on.
*/
final class StoreNewCB implements Callback<Deferred<Long>, Boolean> {
@Override
public Deferred<Long> call(Boolean success) throws Exception {
if (!success) {
LOG.warn("Unable to save metadata: " + meta);
return Deferred.fromResult(0L);
}
LOG.info("Successfullly created new TSUID entry for: " + meta);
return new LoadUIDs(tsdb, UniqueId.uidToString(tsuid)).call(meta).addCallbackDeferring(new FetchNewCB());
}
}
// store the new TSMeta object and setup the callback chain
return meta.storeNew(tsdb).addCallbackDeferring(new StoreNewCB());
}
}
// setup the increment request and execute
final AtomicIncrementRequest inc = new AtomicIncrementRequest(tsdb.metaTable(), tsuid, FAMILY, COUNTER_QUALIFIER);
// then we only want to increment the data point count.
if (!tsdb.getConfig().enable_realtime_ts()) {
return tsdb.getClient().atomicIncrement(inc);
}
return tsdb.getClient().atomicIncrement(inc).addCallbackDeferring(new TSMetaCB());
}
use of com.stumbleupon.async.Callback in project opentsdb by OpenTSDB.
the class TSMeta method storeIfNecessary.
/**
* Attempts to fetch the meta column and if null, attempts to write a new
* column using {@link #storeNew}.
* @param tsdb The TSDB instance to use for access.
* @param tsuid The TSUID of the time series.
* @return A deferred with a true if the meta exists or was created, false
* if the meta did not exist and writing failed.
*/
public static Deferred<Boolean> storeIfNecessary(final TSDB tsdb, final byte[] tsuid) {
final GetRequest get = new GetRequest(tsdb.metaTable(), tsuid);
get.family(FAMILY);
get.qualifier(META_QUALIFIER);
final class CreateNewCB implements Callback<Deferred<Boolean>, Object> {
@Override
public Deferred<Boolean> call(Object arg0) throws Exception {
final TSMeta meta = new TSMeta(tsuid, System.currentTimeMillis() / 1000);
final class FetchNewCB implements Callback<Deferred<Boolean>, TSMeta> {
@Override
public Deferred<Boolean> call(TSMeta stored_meta) throws Exception {
// pass to the search plugin
tsdb.indexTSMeta(stored_meta);
// pass through the trees
tsdb.processTSMetaThroughTrees(stored_meta);
return Deferred.fromResult(true);
}
}
final class StoreNewCB implements Callback<Deferred<Boolean>, Boolean> {
@Override
public Deferred<Boolean> call(Boolean success) throws Exception {
if (!success) {
LOG.warn("Unable to save metadata: " + meta);
return Deferred.fromResult(false);
}
LOG.info("Successfullly created new TSUID entry for: " + meta);
return new LoadUIDs(tsdb, UniqueId.uidToString(tsuid)).call(meta).addCallbackDeferring(new FetchNewCB());
}
}
return meta.storeNew(tsdb).addCallbackDeferring(new StoreNewCB());
}
}
final class ExistsCB implements Callback<Deferred<Boolean>, ArrayList<KeyValue>> {
@Override
public Deferred<Boolean> call(ArrayList<KeyValue> row) throws Exception {
if (row == null || row.isEmpty() || row.get(0).value() == null) {
return new CreateNewCB().call(null);
}
return Deferred.fromResult(true);
}
}
return tsdb.getClient().get(get).addCallbackDeferring(new ExistsCB());
}
use of com.stumbleupon.async.Callback in project opentsdb by OpenTSDB.
the class TSMeta method syncToStorage.
/**
* Attempts a CompareAndSet storage call, loading the object from storage,
* synchronizing changes, and attempting a put. Also verifies that associated
* UID name mappings exist before merging.
* <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> We do not store the UIDMeta information with TSMeta's since
* users may change a single UIDMeta object and we don't want to update every
* TSUID that includes that object with the new data. Instead, UIDMetas are
* merged into the TSMeta on retrieval so we always have canonical data. This
* also saves space in 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 storage call was successful, false if the object was
* modified in storage during the CAS call. If false, retry the call. Other
* failures will result in an exception being thrown.
* @throws HBaseException if there was an issue
* @throws IllegalArgumentException if parsing failed
* @throws NoSuchUniqueId If any of the UID name mappings do not exist
* @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 (tsuid == null || tsuid.isEmpty()) {
throw new IllegalArgumentException("Missing TSUID");
}
boolean has_changes = false;
for (Map.Entry<String, Boolean> entry : changed.entrySet()) {
if (entry.getValue()) {
has_changes = true;
break;
}
}
if (!has_changes) {
LOG.debug(this + " does not have changes, skipping sync to storage");
throw new IllegalStateException("No changes detected in TSUID meta data");
}
/**
* Callback used to verify that the UID name mappings exist. We don't need
* to process the actual name, we just want it to throw an error if any
* of the UIDs don't exist.
*/
class UidCB implements Callback<Object, String> {
@Override
public Object call(String name) throws Exception {
// nothing to do as missing mappings will throw a NoSuchUniqueId
return null;
}
}
// parse out the tags from the tsuid
final List<byte[]> parsed_tags = UniqueId.getTagsFromTSUID(tsuid);
// Deferred group used to accumulate UidCB callbacks so the next call
// can wait until all of the UIDs have been verified
ArrayList<Deferred<Object>> uid_group = new ArrayList<Deferred<Object>>(parsed_tags.size() + 1);
// calculate the metric UID and fetch it's name mapping
final byte[] metric_uid = UniqueId.stringToUid(tsuid.substring(0, TSDB.metrics_width() * 2));
uid_group.add(tsdb.getUidName(UniqueIdType.METRIC, metric_uid).addCallback(new UidCB()));
int idx = 0;
for (byte[] tag : parsed_tags) {
if (idx % 2 == 0) {
uid_group.add(tsdb.getUidName(UniqueIdType.TAGK, tag).addCallback(new UidCB()));
} else {
uid_group.add(tsdb.getUidName(UniqueIdType.TAGV, tag).addCallback(new UidCB()));
}
idx++;
}
/**
* Callback executed after all of the UID mappings have been verified. This
* will then proceed with the CAS call.
*/
final class ValidateCB implements Callback<Deferred<Boolean>, ArrayList<Object>> {
private final TSMeta local_meta;
public ValidateCB(final TSMeta local_meta) {
this.local_meta = local_meta;
}
/**
* Nested class that executes the CAS after retrieving existing TSMeta
* from storage.
*/
final class StoreCB implements Callback<Deferred<Boolean>, TSMeta> {
/**
* Executes the CAS if the TSMeta was successfully retrieved
* @return True if the CAS was successful, false if the stored data
* was modified in flight
* @throws IllegalArgumentException if the TSMeta did not exist in
* storage. Only the TSD should be able to create TSMeta objects.
*/
@Override
public Deferred<Boolean> call(TSMeta stored_meta) throws Exception {
if (stored_meta == null) {
throw new IllegalArgumentException("Requested TSMeta did not exist");
}
final byte[] original_meta = stored_meta.getStorageJSON();
local_meta.syncMeta(stored_meta, overwrite);
final PutRequest put = new PutRequest(tsdb.metaTable(), UniqueId.stringToUid(local_meta.tsuid), FAMILY, META_QUALIFIER, local_meta.getStorageJSON());
return tsdb.getClient().compareAndSet(put, original_meta);
}
}
/**
* Called on UID mapping verification and continues executing the CAS
* procedure.
* @return Results from the {@link #StoreCB} callback
*/
@Override
public Deferred<Boolean> call(ArrayList<Object> validated) throws Exception {
return getFromStorage(tsdb, UniqueId.stringToUid(tsuid)).addCallbackDeferring(new StoreCB());
}
}
// Begins the callback chain by validating that the UID mappings exist
return Deferred.group(uid_group).addCallbackDeferring(new ValidateCB(this));
}
Aggregations