use of org.hbase.async.HBaseException 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));
}
use of org.hbase.async.HBaseException in project opentsdb by OpenTSDB.
the class UidManager method assign.
/**
* Implements the {@code assign} subcommand.
* @param tsdb The TSDB to use.
* @param table The name of the HBase table to use.
* @param idwidth Number of bytes on which the UIDs should be.
* @param args Command line arguments ({@code assign name [names]}).
* @return The exit status of the command (0 means success).
*/
private static int assign(final TSDB tsdb, final byte[] table, final short idwidth, final String[] args) {
boolean randomize = false;
if (UniqueId.stringToUniqueIdType(args[1]) == UniqueIdType.METRIC) {
randomize = tsdb.getConfig().getBoolean("tsd.core.uid.random_metrics");
}
final UniqueId uid = new UniqueId(tsdb.getClient(), table, args[1], (int) idwidth, randomize);
for (int i = 2; i < args.length; i++) {
try {
uid.getOrCreateId(args[i]);
// Lookup again the ID we've just created and print it.
extactLookupName(tsdb.getClient(), table, idwidth, args[1], args[i]);
} catch (HBaseException e) {
LOG.error("error while processing " + args[i], e);
return 3;
}
}
return 0;
}
use of org.hbase.async.HBaseException in project opentsdb by OpenTSDB.
the class UidManager method findAndPrintRow.
/**
* Gets a given row in HBase and prints it on standard output.
* @param client The HBase client to use.
* @param table The name of the HBase table to use.
* @param key The row key to attempt to get from HBase.
* @param family The family in which we're interested.
* @return 0 if at least one cell was found and printed, 1 otherwise.
*/
private static int findAndPrintRow(final HBaseClient client, final byte[] table, final byte[] key, final byte[] family, boolean formard) {
final GetRequest get = new GetRequest(table, key);
get.family(family);
ArrayList<KeyValue> row;
try {
row = client.get(get).joinUninterruptibly();
} catch (HBaseException e) {
LOG.error("Get failed: " + get, e);
return 1;
} catch (Exception e) {
LOG.error("WTF? Unexpected exception type, get=" + get, e);
return 42;
}
return printResult(row, family, formard) ? 0 : 1;
}
use of org.hbase.async.HBaseException in project opentsdb by OpenTSDB.
the class UniqueId method rename.
/**
* Reassigns the UID to a different name (non-atomic).
* <p>
* Whatever was the UID of {@code oldname} will be given to {@code newname}.
* {@code oldname} will no longer be assigned a UID.
* <p>
* Beware that the assignment change is <b>not atommic</b>. If two threads
* or processes attempt to rename the same UID differently, the result is
* unspecified and might even be inconsistent. This API is only here for
* administrative purposes, not for normal programmatic interactions.
* @param oldname The old name to rename.
* @param newname The new name.
* @throws NoSuchUniqueName if {@code oldname} wasn't assigned.
* @throws IllegalArgumentException if {@code newname} was already assigned.
* @throws HBaseException if there was a problem with HBase while trying to
* update the mapping.
*/
public void rename(final String oldname, final String newname) {
final byte[] row = getId(oldname);
final String row_string = fromBytes(row);
{
byte[] id = null;
try {
id = getId(newname);
} catch (NoSuchUniqueName e) {
// OK, we don't want the new name to be assigned.
}
if (id != null) {
throw new IllegalArgumentException("When trying rename(\"" + oldname + "\", \"" + newname + "\") on " + this + ": new name already" + " assigned ID=" + Arrays.toString(id));
}
}
if (renaming_id_names.contains(row_string) || renaming_id_names.contains(newname)) {
throw new IllegalArgumentException("Ongoing rename on the same ID(\"" + Arrays.toString(row) + "\") or an identical new name(\"" + newname + "\")");
}
renaming_id_names.add(row_string);
renaming_id_names.add(newname);
final byte[] newnameb = toBytes(newname);
// but the forward mapping without reverse mapping is bad.
try {
final PutRequest reverse_mapping = new PutRequest(table, row, NAME_FAMILY, kind, newnameb);
hbasePutWithRetry(reverse_mapping, MAX_ATTEMPTS_PUT, INITIAL_EXP_BACKOFF_DELAY);
} catch (HBaseException e) {
LOG.error("When trying rename(\"" + oldname + "\", \"" + newname + "\") on " + this + ": Failed to update reverse" + " mapping for ID=" + Arrays.toString(row), e);
renaming_id_names.remove(row_string);
renaming_id_names.remove(newname);
throw e;
}
// Now create the new forward mapping.
try {
final PutRequest forward_mapping = new PutRequest(table, newnameb, ID_FAMILY, kind, row);
hbasePutWithRetry(forward_mapping, MAX_ATTEMPTS_PUT, INITIAL_EXP_BACKOFF_DELAY);
} catch (HBaseException e) {
LOG.error("When trying rename(\"" + oldname + "\", \"" + newname + "\") on " + this + ": Failed to create the" + " new forward mapping with ID=" + Arrays.toString(row), e);
renaming_id_names.remove(row_string);
renaming_id_names.remove(newname);
throw e;
}
// Update cache.
// add new name -> ID
addIdToCache(newname, row);
// update ID -> new name
id_cache.put(fromBytes(row), newname);
// remove old name -> ID
name_cache.remove(oldname);
// Delete the old forward mapping.
try {
final DeleteRequest old_forward_mapping = new DeleteRequest(table, toBytes(oldname), ID_FAMILY, kind);
client.delete(old_forward_mapping).joinUninterruptibly();
} catch (HBaseException e) {
LOG.error("When trying rename(\"" + oldname + "\", \"" + newname + "\") on " + this + ": Failed to remove the" + " old forward mapping for ID=" + Arrays.toString(row), e);
throw e;
} catch (Exception e) {
final String msg = "Unexpected exception when trying rename(\"" + oldname + "\", \"" + newname + "\") on " + this + ": Failed to remove the" + " old forward mapping for ID=" + Arrays.toString(row);
LOG.error("WTF? " + msg, e);
throw new RuntimeException(msg, e);
} finally {
renaming_id_names.remove(row_string);
renaming_id_names.remove(newname);
}
// Success!
}
use of org.hbase.async.HBaseException in project opentsdb by OpenTSDB.
the class UniqueId method preloadUidCache.
/**
* Pre-load UID caches, scanning up to "tsd.core.preload_uid_cache.max_entries"
* rows from the UID table.
* @param tsdb The TSDB to use
* @param uid_cache_map A map of {@link UniqueId} objects keyed on the kind.
* @throws HBaseException Passes any HBaseException from HBase scanner.
* @throws RuntimeException Wraps any non HBaseException from HBase scanner.
* @2.1
*/
public static void preloadUidCache(final TSDB tsdb, final ByteMap<UniqueId> uid_cache_map) throws HBaseException {
int max_results = tsdb.getConfig().getInt("tsd.core.preload_uid_cache.max_entries");
LOG.info("Preloading uid cache with max_results=" + max_results);
if (max_results <= 0) {
return;
}
Scanner scanner = null;
try {
int num_rows = 0;
scanner = getSuggestScanner(tsdb.getClient(), tsdb.uidTable(), "", null, max_results);
for (ArrayList<ArrayList<KeyValue>> rows = scanner.nextRows().join(); rows != null; rows = scanner.nextRows().join()) {
for (final ArrayList<KeyValue> row : rows) {
for (KeyValue kv : row) {
final String name = fromBytes(kv.key());
final byte[] kind = kv.qualifier();
final byte[] id = kv.value();
LOG.debug("id='{}', name='{}', kind='{}'", Arrays.toString(id), name, fromBytes(kind));
UniqueId uid_cache = uid_cache_map.get(kind);
if (uid_cache != null) {
uid_cache.cacheMapping(name, id);
}
}
num_rows += row.size();
// free()
row.clear();
if (num_rows >= max_results) {
break;
}
}
}
for (UniqueId unique_id_table : uid_cache_map.values()) {
LOG.info("After preloading, uid cache '{}' has {} ids and {} names.", unique_id_table.kind(), unique_id_table.id_cache.size(), unique_id_table.name_cache.size());
}
} catch (Exception e) {
if (e instanceof HBaseException) {
throw (HBaseException) e;
} else if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else {
throw new RuntimeException("Error while preloading IDs", e);
}
} finally {
if (scanner != null) {
scanner.close();
}
}
}
Aggregations