Flavio Castro
Committed by Gerrit Code Review

ONOS-2315 Adding new metrics to ConsistentMaps

Change-Id: Iba9a70f5eb268834564be26e42776b9caa4ea547
...@@ -25,6 +25,7 @@ import java.util.Map.Entry; ...@@ -25,6 +25,7 @@ import java.util.Map.Entry;
25 import java.util.Objects; 25 import java.util.Objects;
26 import java.util.concurrent.CompletableFuture; 26 import java.util.concurrent.CompletableFuture;
27 import java.util.concurrent.CopyOnWriteArraySet; 27 import java.util.concurrent.CopyOnWriteArraySet;
28 +import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.atomic.AtomicReference; 29 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.function.BiFunction; 30 import java.util.function.BiFunction;
30 import java.util.function.Consumer; 31 import java.util.function.Consumer;
...@@ -33,6 +34,11 @@ import java.util.function.Predicate; ...@@ -33,6 +34,11 @@ import java.util.function.Predicate;
33 import java.util.stream.Collectors; 34 import java.util.stream.Collectors;
34 import java.util.Set; 35 import java.util.Set;
35 36
37 +import com.codahale.metrics.Timer;
38 +import org.onlab.metrics.MetricsComponent;
39 +import org.onlab.metrics.MetricsFeature;
40 +import org.onlab.metrics.MetricsService;
41 +import org.onlab.osgi.DefaultServiceDirectory;
36 import org.onlab.util.HexString; 42 import org.onlab.util.HexString;
37 import org.onlab.util.SharedExecutors; 43 import org.onlab.util.SharedExecutors;
38 import org.onlab.util.Tools; 44 import org.onlab.util.Tools;
...@@ -70,6 +76,34 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -70,6 +76,34 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
70 private final boolean purgeOnUninstall; 76 private final boolean purgeOnUninstall;
71 private final Consumer<MapEvent<K, V>> eventPublisher; 77 private final Consumer<MapEvent<K, V>> eventPublisher;
72 78
79 + private final MetricsService metricsService;
80 + private final MetricsComponent metricsComponent;
81 + private final MetricsFeature metricsFeature;
82 + private final Map<String, Timer> perMapOpTimers = Maps.newConcurrentMap();
83 + private final Map<String, Timer> perOpTimers = Maps.newConcurrentMap();
84 + private final Timer cMapTimer;
85 + private final Timer perMapTimer;
86 + private final MetricsFeature wildcard;
87 +
88 + private static final String COMPONENT_NAME = "consistentMap";
89 + private static final String SIZE = "size";
90 + private static final String IS_EMPTY = "isEmpty";
91 + private static final String CONTAINS_KEY = "containsKey";
92 + private static final String CONTAINS_VALUE = "containsValue";
93 + private static final String GET = "get";
94 + private static final String COMPUTE_IF = "computeIf";
95 + private static final String PUT = "put";
96 + private static final String PUT_AND_GET = "putAndGet";
97 + private static final String PUT_IF_ABSENT = "putIfAbsent";
98 + private static final String REMOVE = "remove";
99 + private static final String CLEAR = "clear";
100 + private static final String KEY_SET = "keySet";
101 + private static final String VALUES = "values";
102 + private static final String ENTRY_SET = "entrySet";
103 + private static final String REPLACE = "replace";
104 + private static final String COMPUTE_IF_ABSENT = "computeIfAbsent";
105 +
106 +
73 private final Set<MapEventListener<K, V>> listeners = new CopyOnWriteArraySet<>(); 107 private final Set<MapEventListener<K, V>> listeners = new CopyOnWriteArraySet<>();
74 108
75 private final Logger log = getLogger(getClass()); 109 private final Logger log = getLogger(getClass());
...@@ -116,6 +150,13 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -116,6 +150,13 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
116 } 150 }
117 }); 151 });
118 }); 152 });
153 + this.metricsService = DefaultServiceDirectory.getService(MetricsService.class);
154 + this.metricsComponent = metricsService.registerComponent(COMPONENT_NAME);
155 + this.metricsFeature = metricsComponent.registerFeature(name);
156 + this.wildcard = metricsComponent.registerFeature("*");
157 + this.perMapTimer = metricsService.createTimer(metricsComponent, metricsFeature, "*");
158 + this.cMapTimer = metricsService.createTimer(metricsComponent, wildcard, "*");
159 +
119 } 160 }
120 161
121 /** 162 /**
...@@ -153,31 +194,41 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -153,31 +194,41 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
153 194
154 @Override 195 @Override
155 public CompletableFuture<Integer> size() { 196 public CompletableFuture<Integer> size() {
156 - return database.mapSize(name); 197 + final OperationTimer timer = startTimer(SIZE);
198 + return database.mapSize(name)
199 + .whenComplete((r, e) -> timer.stop());
157 } 200 }
158 201
159 @Override 202 @Override
160 public CompletableFuture<Boolean> isEmpty() { 203 public CompletableFuture<Boolean> isEmpty() {
161 - return database.mapIsEmpty(name); 204 + final OperationTimer timer = startTimer(IS_EMPTY);
205 + return database.mapIsEmpty(name)
206 + .whenComplete((r, e) -> timer.stop());
162 } 207 }
163 208
164 @Override 209 @Override
165 public CompletableFuture<Boolean> containsKey(K key) { 210 public CompletableFuture<Boolean> containsKey(K key) {
166 checkNotNull(key, ERROR_NULL_KEY); 211 checkNotNull(key, ERROR_NULL_KEY);
167 - return database.mapContainsKey(name, keyCache.getUnchecked(key)); 212 + final OperationTimer timer = startTimer(CONTAINS_KEY);
213 + return database.mapContainsKey(name, keyCache.getUnchecked(key))
214 + .whenComplete((r, e) -> timer.stop());
168 } 215 }
169 216
170 @Override 217 @Override
171 public CompletableFuture<Boolean> containsValue(V value) { 218 public CompletableFuture<Boolean> containsValue(V value) {
172 checkNotNull(value, ERROR_NULL_VALUE); 219 checkNotNull(value, ERROR_NULL_VALUE);
173 - return database.mapContainsValue(name, serializer.encode(value)); 220 + final OperationTimer timer = startTimer(CONTAINS_VALUE);
221 + return database.mapContainsValue(name, serializer.encode(value))
222 + .whenComplete((r, e) -> timer.stop());
174 } 223 }
175 224
176 @Override 225 @Override
177 public CompletableFuture<Versioned<V>> get(K key) { 226 public CompletableFuture<Versioned<V>> get(K key) {
178 checkNotNull(key, ERROR_NULL_KEY); 227 checkNotNull(key, ERROR_NULL_KEY);
228 + final OperationTimer timer = startTimer(GET);
179 return database.mapGet(name, keyCache.getUnchecked(key)) 229 return database.mapGet(name, keyCache.getUnchecked(key))
180 - .thenApply(v -> v != null ? v.map(serializer::decode) : null); 230 + .whenComplete((r, e) -> timer.stop())
231 + .thenApply(v -> v != null ? v.map(serializer::decode) : null);
181 } 232 }
182 233
183 @Override 234 @Override
...@@ -185,7 +236,10 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -185,7 +236,10 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
185 Function<? super K, ? extends V> mappingFunction) { 236 Function<? super K, ? extends V> mappingFunction) {
186 checkNotNull(key, ERROR_NULL_KEY); 237 checkNotNull(key, ERROR_NULL_KEY);
187 checkNotNull(mappingFunction, "Mapping function cannot be null"); 238 checkNotNull(mappingFunction, "Mapping function cannot be null");
188 - return updateAndGet(key, Match.ifNull(), Match.any(), mappingFunction.apply(key)).thenApply(v -> v.newValue()); 239 + final OperationTimer timer = startTimer(COMPUTE_IF_ABSENT);
240 + return updateAndGet(key, Match.ifNull(), Match.any(), mappingFunction.apply(key))
241 + .whenComplete((r, e) -> timer.stop())
242 + .thenApply(v -> v.newValue());
189 } 243 }
190 244
191 @Override 245 @Override
...@@ -207,6 +261,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -207,6 +261,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
207 checkNotNull(key, ERROR_NULL_KEY); 261 checkNotNull(key, ERROR_NULL_KEY);
208 checkNotNull(condition, "predicate function cannot be null"); 262 checkNotNull(condition, "predicate function cannot be null");
209 checkNotNull(remappingFunction, "Remapping function cannot be null"); 263 checkNotNull(remappingFunction, "Remapping function cannot be null");
264 + final OperationTimer timer = startTimer(COMPUTE_IF);
210 return get(key).thenCompose(r1 -> { 265 return get(key).thenCompose(r1 -> {
211 V existingValue = r1 == null ? null : r1.value(); 266 V existingValue = r1 == null ? null : r1.value();
212 // if the condition evaluates to false, return existing value. 267 // if the condition evaluates to false, return existing value.
...@@ -227,6 +282,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -227,6 +282,7 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
227 Match<V> valueMatcher = r1 == null ? Match.ifNull() : Match.any(); 282 Match<V> valueMatcher = r1 == null ? Match.ifNull() : Match.any();
228 Match<Long> versionMatcher = r1 == null ? Match.any() : Match.ifValue(r1.version()); 283 Match<Long> versionMatcher = r1 == null ? Match.any() : Match.ifValue(r1.version());
229 return updateAndGet(key, valueMatcher, versionMatcher, computedValue.get()) 284 return updateAndGet(key, valueMatcher, versionMatcher, computedValue.get())
285 + .whenComplete((r, e) -> timer.stop())
230 .thenApply(v -> { 286 .thenApply(v -> {
231 if (v.updated()) { 287 if (v.updated()) {
232 return v.newValue(); 288 return v.newValue();
...@@ -241,71 +297,96 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -241,71 +297,96 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
241 public CompletableFuture<Versioned<V>> put(K key, V value) { 297 public CompletableFuture<Versioned<V>> put(K key, V value) {
242 checkNotNull(key, ERROR_NULL_KEY); 298 checkNotNull(key, ERROR_NULL_KEY);
243 checkNotNull(value, ERROR_NULL_VALUE); 299 checkNotNull(value, ERROR_NULL_VALUE);
244 - return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.oldValue()); 300 + final OperationTimer timer = startTimer(PUT);
301 + return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.oldValue())
302 + .whenComplete((r, e) -> timer.stop());
245 } 303 }
246 304
247 @Override 305 @Override
248 public CompletableFuture<Versioned<V>> putAndGet(K key, V value) { 306 public CompletableFuture<Versioned<V>> putAndGet(K key, V value) {
249 checkNotNull(key, ERROR_NULL_KEY); 307 checkNotNull(key, ERROR_NULL_KEY);
250 checkNotNull(value, ERROR_NULL_VALUE); 308 checkNotNull(value, ERROR_NULL_VALUE);
251 - return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.newValue()); 309 + final OperationTimer timer = startTimer(PUT_AND_GET);
310 + return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.newValue())
311 + .whenComplete((r, e) -> timer.stop());
252 } 312 }
253 313
254 @Override 314 @Override
255 public CompletableFuture<Versioned<V>> remove(K key) { 315 public CompletableFuture<Versioned<V>> remove(K key) {
256 checkNotNull(key, ERROR_NULL_KEY); 316 checkNotNull(key, ERROR_NULL_KEY);
257 - return updateAndGet(key, Match.any(), Match.any(), null).thenApply(v -> v.oldValue()); 317 + final OperationTimer timer = startTimer(REMOVE);
318 + return updateAndGet(key, Match.any(), Match.any(), null).thenApply(v -> v.oldValue())
319 + .whenComplete((r, e) -> timer.stop());
258 } 320 }
259 321
260 @Override 322 @Override
261 public CompletableFuture<Void> clear() { 323 public CompletableFuture<Void> clear() {
262 checkIfUnmodifiable(); 324 checkIfUnmodifiable();
263 - return database.mapClear(name).thenApply(this::unwrapResult); 325 + final OperationTimer timer = startTimer(CLEAR);
326 + return database.mapClear(name).thenApply(this::unwrapResult)
327 + .whenComplete((r, e) -> timer.stop());
264 } 328 }
265 329
266 @Override 330 @Override
267 public CompletableFuture<Set<K>> keySet() { 331 public CompletableFuture<Set<K>> keySet() {
332 + final OperationTimer timer = startTimer(KEY_SET);
268 return database.mapKeySet(name) 333 return database.mapKeySet(name)
269 .thenApply(s -> s 334 .thenApply(s -> s
270 - .stream() 335 + .stream()
271 - .map(this::dK) 336 + .map(this::dK)
272 - .collect(Collectors.toSet())); 337 + .collect(Collectors.toSet()))
338 + .whenComplete((r, e) -> timer.stop());
273 } 339 }
274 340
275 @Override 341 @Override
276 public CompletableFuture<Collection<Versioned<V>>> values() { 342 public CompletableFuture<Collection<Versioned<V>>> values() {
277 - return database.mapValues(name).thenApply(c -> c 343 + final OperationTimer timer = startTimer(VALUES);
278 - .stream() 344 + return database.mapValues(name)
279 - .map(v -> v.<V>map(serializer::decode)) 345 + .whenComplete((r, e) -> timer.stop())
280 - .collect(Collectors.toList())); 346 + .thenApply(c -> c
347 + .stream()
348 + .map(v -> v.<V>map(serializer::decode))
349 + .collect(Collectors.toList()));
281 } 350 }
282 351
283 @Override 352 @Override
284 public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() { 353 public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() {
285 - return database.mapEntrySet(name).thenApply(s -> s 354 + final OperationTimer timer = startTimer(ENTRY_SET);
286 - .stream() 355 + return database.mapEntrySet(name)
287 - .map(this::mapRawEntry) 356 + .whenComplete((r, e) -> timer.stop())
288 - .collect(Collectors.toSet())); 357 + .thenApply(s -> s
358 + .stream()
359 + .map(this::mapRawEntry)
360 + .collect(Collectors.toSet()));
289 } 361 }
290 362
291 @Override 363 @Override
292 public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) { 364 public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) {
293 checkNotNull(key, ERROR_NULL_KEY); 365 checkNotNull(key, ERROR_NULL_KEY);
294 checkNotNull(value, ERROR_NULL_VALUE); 366 checkNotNull(value, ERROR_NULL_VALUE);
295 - return updateAndGet(key, Match.ifNull(), Match.any(), value).thenApply(v -> v.oldValue()); 367 + final OperationTimer timer = startTimer(PUT_IF_ABSENT);
368 + return updateAndGet(key, Match.ifNull(), Match.any(), value)
369 + .whenComplete((r, e) -> timer.stop())
370 + .thenApply(v -> v.oldValue());
296 } 371 }
297 372
298 @Override 373 @Override
299 public CompletableFuture<Boolean> remove(K key, V value) { 374 public CompletableFuture<Boolean> remove(K key, V value) {
300 checkNotNull(key, ERROR_NULL_KEY); 375 checkNotNull(key, ERROR_NULL_KEY);
301 checkNotNull(value, ERROR_NULL_VALUE); 376 checkNotNull(value, ERROR_NULL_VALUE);
302 - return updateAndGet(key, Match.ifValue(value), Match.any(), null).thenApply(v -> v.updated()); 377 + final OperationTimer timer = startTimer(REMOVE);
378 + return updateAndGet(key, Match.ifValue(value), Match.any(), null)
379 + .whenComplete((r, e) -> timer.stop())
380 + .thenApply(v -> v.updated());
303 } 381 }
304 382
305 @Override 383 @Override
306 public CompletableFuture<Boolean> remove(K key, long version) { 384 public CompletableFuture<Boolean> remove(K key, long version) {
307 checkNotNull(key, ERROR_NULL_KEY); 385 checkNotNull(key, ERROR_NULL_KEY);
308 - return updateAndGet(key, Match.any(), Match.ifValue(version), null).thenApply(v -> v.updated()); 386 + final OperationTimer timer = startTimer(REMOVE);
387 + return updateAndGet(key, Match.any(), Match.ifValue(version), null)
388 + .whenComplete((r, e) -> timer.stop())
389 + .thenApply(v -> v.updated());
309 } 390 }
310 391
311 @Override 392 @Override
...@@ -313,12 +394,18 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -313,12 +394,18 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
313 checkNotNull(key, ERROR_NULL_KEY); 394 checkNotNull(key, ERROR_NULL_KEY);
314 checkNotNull(oldValue, ERROR_NULL_VALUE); 395 checkNotNull(oldValue, ERROR_NULL_VALUE);
315 checkNotNull(newValue, ERROR_NULL_VALUE); 396 checkNotNull(newValue, ERROR_NULL_VALUE);
316 - return updateAndGet(key, Match.ifValue(oldValue), Match.any(), newValue).thenApply(v -> v.updated()); 397 + final OperationTimer timer = startTimer(REPLACE);
398 + return updateAndGet(key, Match.ifValue(oldValue), Match.any(), newValue)
399 + .whenComplete((r, e) -> timer.stop())
400 + .thenApply(v -> v.updated());
317 } 401 }
318 402
319 @Override 403 @Override
320 public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) { 404 public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) {
321 - return updateAndGet(key, Match.any(), Match.ifValue(oldVersion), newValue).thenApply(v -> v.updated()); 405 + final OperationTimer timer = startTimer(REPLACE);
406 + return updateAndGet(key, Match.any(), Match.ifValue(oldVersion), newValue)
407 + .whenComplete((r, e) -> timer.stop())
408 + .thenApply(v -> v.updated());
322 } 409 }
323 410
324 private Map.Entry<K, Versioned<V>> mapRawEntry(Map.Entry<String, Versioned<byte[]>> e) { 411 private Map.Entry<K, Versioned<V>> mapRawEntry(Map.Entry<String, Versioned<byte[]>> e) {
...@@ -331,10 +418,10 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -331,10 +418,10 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
331 V value) { 418 V value) {
332 checkIfUnmodifiable(); 419 checkIfUnmodifiable();
333 return database.mapUpdate(name, 420 return database.mapUpdate(name,
334 - keyCache.getUnchecked(key), 421 + keyCache.getUnchecked(key),
335 - oldValueMatch.map(serializer::encode), 422 + oldValueMatch.map(serializer::encode),
336 - oldVersionMatch, 423 + oldVersionMatch,
337 - value == null ? null : serializer.encode(value)) 424 + value == null ? null : serializer.encode(value))
338 .thenApply(this::unwrapResult) 425 .thenApply(this::unwrapResult)
339 .thenApply(r -> r.<K, V>map(this::dK, serializer::decode)) 426 .thenApply(r -> r.<K, V>map(this::dK, serializer::decode))
340 .whenComplete((r, e) -> { 427 .whenComplete((r, e) -> {
...@@ -392,4 +479,34 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V> ...@@ -392,4 +479,34 @@ public class DefaultAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, V>
392 eventPublisher.accept(event); 479 eventPublisher.accept(event);
393 } 480 }
394 } 481 }
482 +
483 + private OperationTimer startTimer(String op) {
484 + //check if timer exist, if it doesn't creates it
485 + final Timer currTimer = perMapOpTimers.computeIfAbsent(op, timer ->
486 + metricsService.createTimer(metricsComponent, metricsFeature, op));
487 + perOpTimers.computeIfAbsent(op, timer -> metricsService.createTimer(metricsComponent, wildcard, op));
488 + //starts timer
489 + return new OperationTimer(currTimer.time(), op);
490 + }
491 +
492 + private class OperationTimer {
493 + private final Timer.Context context;
494 + private final String operation;
495 +
496 + public OperationTimer(Timer.Context context, String operation) {
497 + this.context = context;
498 + this.operation = operation;
499 + }
500 +
501 + public void stop() {
502 + //Stop and updates timer with specific measurements per map, per operation
503 + final long time = context.stop();
504 + //updates timer with aggregated measurements per map
505 + perOpTimers.get(operation).update(time, TimeUnit.NANOSECONDS);
506 + //updates timer with aggregated measurements per map
507 + perMapTimer.update(time, TimeUnit.NANOSECONDS);
508 + //updates timer with aggregated measurements per all Consistent Maps
509 + cMapTimer.update(time, TimeUnit.NANOSECONDS);
510 + }
511 + }
395 } 512 }
...\ No newline at end of file ...\ No newline at end of file
......