protected <T> Future<List<FDBMetric.Value<T>>> readAllValues( Transaction tr, final BaseMetricImpl<T> metric) { tr.options().setAccessSystemKeys(); return tr.getRange( dataSubspace.pack( tupleFrom(metric.getType(), metric.getName(), address, DEFAULT_ID, 0)), dataSubspace.pack( tupleFrom(metric.getType(), metric.getName(), address, DEFAULT_ID, NLEVELS))) .asList() .map( new Function<List<KeyValue>, List<FDBMetric.Value<T>>>() { @Override public List<FDBMetric.Value<T>> apply(List<KeyValue> kvs) { List<FDBMetric.Value<T>> result = new ArrayList<>(); for (KeyValue kv : kvs) { result.addAll(metric.decodeValues(kv.getValue())); } // Merge all levels. Collections.sort( result, new Comparator<FDBMetric.Value<T>>() { @Override public int compare(FDBMetric.Value<T> v1, FDBMetric.Value<T> v2) { if (v1.time < v2.time) return -1; else if (v1.time > v2.time) return +1; else return 0; } }); return result; } }); }
protected Map<List<String>, byte[]> readConf(Transaction tr) { tr.options().setAccessSystemKeys(); byte[] confKey = confSubspace.getKey(); List<KeyValue> kvs = tr.getRange(Range.startsWith(confKey)).asList().get(); Map<List<String>, byte[]> result = new HashMap<>(); for (KeyValue kv : kvs) { byte[] tupleBytes = new byte[kv.getKey().length - confKey.length]; System.arraycopy(kv.getKey(), confKey.length, tupleBytes, 0, tupleBytes.length); // TODO: It's a shame that there isn't a fromBytes with index offets. Tuple2 tuple = Tuple2.fromBytes(tupleBytes); List<String> list = new ArrayList<>(tuple.size()); for (int i = 0; i < tuple.size(); i++) { if (BINARY_STRINGS) { try { list.add(new String(tuple.getBytes(i), "UTF-8")); } catch (UnsupportedEncodingException ex) { throw new AkibanInternalException("Error decoding binary string", ex); } } else { list.add(tuple.getString(i)); } } result.put(list, kv.getValue()); } // Initiate a watch (from this same transaction) for changes to the key // used to signal configuration changes. tr.watch(confChangesSubspace.getKey()) .onReady( new Runnable() { @Override public void run() { confChanged = true; notifyBackground(); } }); return result; }
protected void writeMetrics() { boolean anyConfChanges = false; for (BaseMetricImpl<?> metric : metrics.values()) { if (!metric.confChanged && !metric.valueChanged) continue; synchronized (metric) { if (metric.confChanged) { anyConfChanges = true; pendingWrites.add( new KeyValue( confSubspace.pack( tupleFrom( metric.getType(), metric.getName(), address, DEFAULT_ID, ENABLED_OPTION)), metric.enabled ? ENABLED_TRUE : ENABLED_FALSE)); metric.confChanged = false; } if (metric.valueChanged) { pendingWrites.add( new KeyValue( dataSubspace.pack( tupleFrom(metric.getType(), metric.getName(), address, DEFAULT_ID)), metric.encodeValue())); metric.valueChanged = false; } for (int level = 0; level < NLEVELS; level++) { MetricLevel<?> metricLevel = metric.levels.get(level); while (true) { MetricLevelValues values = metricLevel.values.pollFirst(); if (values == null) break; pendingWrites.add( new KeyValue( dataSubspace.pack( tupleFrom( metric.getType(), metric.getName(), address, DEFAULT_ID, level, values.start)), values.bytes)); // Continue to fill (will overwrite key with longer value). if (metricLevel.values.isEmpty() && !values.isFull()) { metricLevel.values.addLast(values); break; } } } } } if (anyConfChanges) { // Signal a change in configuration. We will respond to this change, // too, but that seemd harmless and difficult to avoid in a general // way. byte[] bytes = new byte[16]; random.nextBytes(bytes); if (logger.isDebugEnabled()) { logger.debug("Writing {}: {}", METRIC_CONF_CHANGES_KEY, ByteArrayUtil.printable(bytes)); } pendingWrites.add(new KeyValue(confChangesSubspace.getKey(), bytes)); } if (!pendingWrites.isEmpty()) { getDatabase() .run( new Function<Transaction, Void>() { @Override public Void apply(Transaction tr) { tr.options().setAccessSystemKeys(); for (KeyValue kv : pendingWrites) { tr.set(kv.getKey(), kv.getValue()); } return null; } }); pendingWrites.clear(); } }
public void deleteLongMetric(Transaction tr, String name) { tr.clear(Range.startsWith(dataSubspace.pack(tupleFrom(LONG_TYPE, name)))); tr.clear(Range.startsWith(confSubspace.pack(tupleFrom(LONG_TYPE, name)))); }
public void deleteBooleanMetric(Transaction tr, String name) { tr.clear(Range.startsWith(dataSubspace.pack(tupleFrom(BOOLEAN_TYPE, name)))); tr.clear(Range.startsWith(confSubspace.pack(tupleFrom(BOOLEAN_TYPE, name)))); }