/** * Used with verb overrides to parse out values from a query string * * @param query The query to parse * @return An TSMeta object with configured values * @throws BadRequestException if a required value was missing or could not be parsed */ private TSMeta parseTSMetaQS(final HttpQuery query) { final String tsuid = query.getRequiredQueryStringParam("tsuid"); final TSMeta meta = new TSMeta(tsuid); final String display_name = query.getQueryStringParam("display_name"); if (display_name != null) { meta.setDisplayName(display_name); } final String description = query.getQueryStringParam("description"); if (description != null) { meta.setDescription(description); } final String notes = query.getQueryStringParam("notes"); if (notes != null) { meta.setNotes(notes); } final String units = query.getQueryStringParam("units"); if (units != null) { meta.setUnits(units); } final String data_type = query.getQueryStringParam("data_type"); if (data_type != null) { meta.setDataType(data_type); } final String retention = query.getQueryStringParam("retention"); if (retention != null && !retention.isEmpty()) { try { meta.setRetention(Integer.parseInt(retention)); } catch (NumberFormatException nfe) { throw new BadRequestException("Unable to parse 'retention' value"); } } final String max = query.getQueryStringParam("max"); if (max != null && !max.isEmpty()) { try { meta.setMax(Float.parseFloat(max)); } catch (NumberFormatException nfe) { throw new BadRequestException("Unable to parse 'max' value"); } } final String min = query.getQueryStringParam("min"); if (min != null && !min.isEmpty()) { try { meta.setMin(Float.parseFloat(min)); } catch (NumberFormatException nfe) { throw new BadRequestException("Unable to parse 'min' value"); } } return meta; }
@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; }
@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()); }
/** * 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) { // this would only happen if someone deleted a UID but left the // 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) { // this would only happen if someone deleted a UID but left the // 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) { // this would only happen if someone deleted a UID but left the // 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"); } }