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;
             }
           });
 }
 // Change a metric's enabled flag, either from configuration storage of at
 // user's request.
 protected void setEnabled(BaseMetricImpl<?> metric, boolean enabled, boolean explicit) {
   if (metric.enabled == enabled) return;
   boolean notifyBackground = false;
   synchronized (metric) {
     metric.enabled = enabled;
     if (enabled) {
       // As though just changed to current value.
       metricChanged(metric);
     }
     if (explicit) {
       metric.confChanged = true;
     }
   }
   if (enabled && !anyEnabled) {
     anyEnabled = true;
     notifyBackground = true; // So goes to sleep instead of indefinite wait.
   }
   if (explicit) {
     metricsConfChanged = true;
     notifyBackground = true;
   }
   if (notifyBackground) {
     notifyBackground();
   }
 }
  protected <T> void metricChanged(BaseMetricImpl<T> metric) {
    long lastTime = metric.changeTime;

    // NOTE: changeTime is only accurate for metrics that are enabled, and
    // to guarantee that it always corresponds to the value, updates to
    // enabled metrics are synchronized.
    metric.changeTime = timebase + System.nanoTime();
    metric.valueChanged = true;
    metricsDataChanged = true;

    int level;
    if ((lastTime == 0) || (metric.changeTime <= lastTime)) {
      level = 0;
    } else {
      // Longer duration -> higher level.
      double r = random.nextDouble();
      if (r == 0) {
        level = NLEVELS - 1;
      } else {
        level =
            Math.min(
                NLEVELS - 1,
                (int) (Math.log((metric.changeTime - lastTime) / r) / METRIC_LEVEL_DIVISOR));
      }
    }
    MetricLevel<T> metricLevel = metric.levels.get(level);
    MetricLevelValues values = metricLevel.values.peekLast();
    if ((values == null) || values.isFull()) {
      if (logger.isTraceEnabled()) {
        logger.trace(
            "New level {} entry at {} for {}", new Object[] {level, metric.changeTime, metric});
      }
      values = new MetricLevelValues(metric.changeTime, metric.encodeValue());
      metricLevel.values.addLast(values);
    } else {
      if (logger.isTraceEnabled()) {
        logger.trace(
            "Adding to level {} entry at {} for {}",
            new Object[] {level, metric.changeTime, metric});
      }
      values.append(metric.encodeValue(metricLevel));
    }
    metricLevel.lastValue = metric.getObject();
    metricLevel.lastTime = metric.changeTime;
  }
 protected void updateEnabled(BaseMetricImpl<?> metric) {
   List<String> keys =
       Arrays.asList(metric.getType(), metric.getName(), address, DEFAULT_ID, ENABLED_OPTION);
   byte[] enabled = conf.get(keys);
   if (enabled == null) {
     metric.confChanged = true; // Write conf key for brand new metric.
     // Check wildcard enabling.
     keys.set(2, "");
     enabled = conf.get(keys);
     if (enabled != null) {
       setEnabled(metric, enabled[0] != 0, false);
     }
     metricsConfChanged = true;
     notifyBackground();
   } else {
     setEnabled(metric, enabled[0] != 0, false);
   }
 }
 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();
   }
 }
 protected void addMetric(BaseMetricImpl<?> metric) {
   if (metrics.putIfAbsent(metric.getName(), metric) != null) {
     throw new IllegalArgumentException("There is already a metric named " + metric.getName());
   }
   updateEnabled(metric); // Get initial enabled state from conf.
 }