|
2 | 2 |
|
3 | 3 | import com.codahale.metrics.Histogram; |
4 | 4 | import com.codahale.metrics.Meter; |
| 5 | +import com.codahale.metrics.Snapshot; |
5 | 6 | import java.io.IOException; |
6 | 7 | import java.lang.invoke.MethodHandles; |
7 | 8 | import java.util.concurrent.ScheduledExecutorService; |
8 | 9 | import java.util.concurrent.TimeUnit; |
9 | 10 | import java.util.concurrent.atomic.AtomicBoolean; |
| 11 | +import java.util.function.BiConsumer; |
10 | 12 | import java.util.function.LongSupplier; |
| 13 | +import java.util.function.Predicate; |
11 | 14 | import java.util.function.Supplier; |
12 | 15 | import org.apache.lucene.index.Unloader; |
13 | 16 | import org.apache.lucene.util.InfoStream; |
| 17 | +import org.apache.solr.common.MapWriter; |
14 | 18 | import org.apache.solr.handler.admin.MetricsHandler; |
15 | 19 | import org.apache.solr.metrics.MetricSuppliers; |
16 | 20 | import org.apache.solr.metrics.MetricsMap; |
| 21 | +import org.apache.solr.metrics.SolrMetricManager; |
17 | 22 | import org.apache.solr.metrics.SolrMetricProducer; |
18 | 23 | import org.apache.solr.metrics.SolrMetricsContext; |
| 24 | +import org.apache.solr.util.stats.MetricUtils; |
19 | 25 | import org.slf4j.Logger; |
20 | 26 | import org.slf4j.LoggerFactory; |
21 | 27 |
|
@@ -50,14 +56,108 @@ final class UnloadHelper<T extends Unloader.UnloadHelper> |
50 | 56 | String[] metricPath = new String[] {SolrInfoBean.Category.OTHER.toString(), "unloadable"}; |
51 | 57 | created = solrMetricsContext.meter("created", metricPath); |
52 | 58 | loaded = solrMetricsContext.meter("loaded", metricPath); |
53 | | - loadTimeMillis = solrMetricsContext.histogram("loadTimeMillis", metricPath); |
| 59 | + loadTimeMillis = |
| 60 | + invertedHistogram( |
| 61 | + solrMetricsContext, "loadTimeMillis", metricPath, DEFAULT_WRITE_HISTOGRAM); |
54 | 62 | lastAccessToReloadMillis = |
55 | | - solrMetricsContext.histogram("lastAccessToReloadMillis", metricPath); |
| 63 | + invertedHistogram( |
| 64 | + solrMetricsContext, |
| 65 | + "lastAccessToReloadMillis", |
| 66 | + metricPath, |
| 67 | + (snapshot, filter) -> { |
| 68 | + filter.accept("min_ms", TimeUnit.NANOSECONDS.toMillis(snapshot.getMin())); |
| 69 | + filter.accept("max_ms", TimeUnit.NANOSECONDS.toMillis(snapshot.getMax())); |
| 70 | + filter.accept("mean_ms", nsToMs(snapshot.getMean())); |
| 71 | + filter.accept("median_ms", nsToMs(snapshot.getMedian())); |
| 72 | + filter.accept("stddev_ms", nsToMs(snapshot.getStdDev())); |
| 73 | + filter.accept("p25_ms", nsToMs(snapshot.getValue(0.25))); |
| 74 | + filter.accept("p05_ms", nsToMs(snapshot.getValue(0.05))); |
| 75 | + filter.accept("p01_ms", nsToMs(snapshot.getValue(0.01))); |
| 76 | + filter.accept("p001_ms", nsToMs(snapshot.getValue(0.001))); |
| 77 | + }); |
56 | 78 | unloaded = solrMetricsContext.meter("unloaded", metricPath); |
57 | 79 | closed = solrMetricsContext.meter("closed", metricPath); |
58 | 80 | } |
59 | 81 | } |
60 | 82 |
|
| 83 | + private static final long NANOS_PER_MILLI = TimeUnit.MILLISECONDS.toNanos(1); |
| 84 | + |
| 85 | + private static double nsToMs(double nanos) { |
| 86 | + return nanos / NANOS_PER_MILLI; |
| 87 | + } |
| 88 | + |
| 89 | + private static Histogram invertedHistogram( |
| 90 | + SolrMetricsContext ctx, |
| 91 | + String metricName, |
| 92 | + String[] metricPath, |
| 93 | + BiConsumer<Snapshot, BiConsumer<String, Object>> writeHistogram) { |
| 94 | + SolrMetricManager mgr = ctx.getMetricManager(); |
| 95 | + final String name = SolrMetricManager.mkName(metricName, metricPath); |
| 96 | + ctx.registerMetricName(name); |
| 97 | + return mgr.registry(ctx.getRegistryName()) |
| 98 | + .histogram( |
| 99 | + name, () -> new TimeHistogram(mgr.getHistogramSupplier().newMetric(), writeHistogram)); |
| 100 | + } |
| 101 | + |
| 102 | + @SuppressWarnings("UnnecessaryLambda") |
| 103 | + private static final BiConsumer<Snapshot, BiConsumer<String, Object>> DEFAULT_WRITE_HISTOGRAM = |
| 104 | + (snapshot, filter) -> { |
| 105 | + filter.accept("min_ms", TimeUnit.NANOSECONDS.toMillis(snapshot.getMin())); |
| 106 | + filter.accept("max_ms", TimeUnit.NANOSECONDS.toMillis(snapshot.getMax())); |
| 107 | + filter.accept("mean_ms", nsToMs(snapshot.getMean())); |
| 108 | + filter.accept("median_ms", nsToMs(snapshot.getMedian())); |
| 109 | + filter.accept("stddev_ms", nsToMs(snapshot.getStdDev())); |
| 110 | + filter.accept("p75_ms", nsToMs(snapshot.get75thPercentile())); |
| 111 | + filter.accept("p95_ms", nsToMs(snapshot.get95thPercentile())); |
| 112 | + filter.accept("p99_ms", nsToMs(snapshot.get99thPercentile())); |
| 113 | + filter.accept("p999_ms", nsToMs(snapshot.get999thPercentile())); |
| 114 | + }; |
| 115 | + |
| 116 | + private static final class TimeHistogram extends Histogram implements MetricUtils.SnapshotWriter { |
| 117 | + |
| 118 | + private final Histogram delegate; |
| 119 | + private final BiConsumer<Snapshot, BiConsumer<String, Object>> writeHistogram; |
| 120 | + |
| 121 | + private TimeHistogram( |
| 122 | + Histogram delegate, BiConsumer<Snapshot, BiConsumer<String, Object>> writeHistogram) { |
| 123 | + super(null); |
| 124 | + this.delegate = delegate; |
| 125 | + this.writeHistogram = writeHistogram; |
| 126 | + } |
| 127 | + |
| 128 | + @Override |
| 129 | + public void addSnapshot( |
| 130 | + MapWriter.EntryWriter ew, Snapshot snapshot, Predicate<CharSequence> propertyFilter) { |
| 131 | + BiConsumer<String, Object> filter = |
| 132 | + (k, v) -> { |
| 133 | + if (propertyFilter.test(k)) { |
| 134 | + ew.putNoEx(k, v); |
| 135 | + } |
| 136 | + }; |
| 137 | + writeHistogram.accept(snapshot, filter); |
| 138 | + } |
| 139 | + |
| 140 | + @Override |
| 141 | + public void update(int value) { |
| 142 | + delegate.update(value); |
| 143 | + } |
| 144 | + |
| 145 | + @Override |
| 146 | + public void update(long value) { |
| 147 | + delegate.update(value); |
| 148 | + } |
| 149 | + |
| 150 | + @Override |
| 151 | + public long getCount() { |
| 152 | + return delegate.getCount(); |
| 153 | + } |
| 154 | + |
| 155 | + @Override |
| 156 | + public Snapshot getSnapshot() { |
| 157 | + return delegate.getSnapshot(); |
| 158 | + } |
| 159 | + } |
| 160 | + |
61 | 161 | private volatile boolean closing = false; |
62 | 162 |
|
63 | 163 | private void handleRefQueues(LongSupplier indirectTrackedCount, LongSupplier refsCollected) { |
@@ -106,8 +206,8 @@ public ScheduledExecutorService onCreation(Unloader<?> u) { |
106 | 206 | @Override |
107 | 207 | public void onLoad(long nanosSincePriorAccess, long loadTime) { |
108 | 208 | loaded.mark(); |
109 | | - loadTimeMillis.update(TimeUnit.NANOSECONDS.toMillis(loadTime)); |
110 | | - lastAccessToReloadMillis.update(TimeUnit.NANOSECONDS.toMillis(nanosSincePriorAccess)); |
| 209 | + loadTimeMillis.update(loadTime); |
| 210 | + lastAccessToReloadMillis.update(nanosSincePriorAccess); |
111 | 211 | super.onLoad(nanosSincePriorAccess, loadTime); |
112 | 212 | } |
113 | 213 |
|
|
0 commit comments