blob: 540d0adf88bc281d18153f7f8a576f33deb9107b [file] [log] [blame]
Madan Jampani10073672016-01-21 19:13:59 -08001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.store.primitives.impl;
18
19import java.util.Collection;
20import java.util.Map;
21import java.util.Map.Entry;
22import java.util.Set;
23import java.util.concurrent.CompletableFuture;
24import java.util.function.BiFunction;
25import java.util.function.Function;
26import java.util.function.Predicate;
27
28import org.onosproject.store.service.AsyncConsistentMap;
29import org.onosproject.store.service.MapEvent;
30import org.onosproject.store.service.MapEventListener;
31import org.onosproject.store.service.Versioned;
32
33import com.google.common.base.Throwables;
34import com.google.common.collect.Maps;
35
36/**
37 * {@link AsyncConsistentMap} that meters all its operations.
38 *
39 * @param <K> key type
40 * @param <V> value type
41 */
42public class MeteredAsyncConsistentMap<K, V> extends DelegatingAsyncConsistentMap<K, V> {
43
44 private static final String PRIMITIVE_NAME = "consistentMap";
45 private static final String SIZE = "size";
46 private static final String IS_EMPTY = "isEmpty";
47 private static final String CONTAINS_KEY = "containsKey";
48 private static final String CONTAINS_VALUE = "containsValue";
49 private static final String GET = "get";
50 private static final String COMPUTE_IF = "computeIf";
51 private static final String PUT = "put";
52 private static final String PUT_AND_GET = "putAndGet";
53 private static final String PUT_IF_ABSENT = "putIfAbsent";
54 private static final String REMOVE = "remove";
55 private static final String CLEAR = "clear";
56 private static final String KEY_SET = "keySet";
57 private static final String VALUES = "values";
58 private static final String ENTRY_SET = "entrySet";
59 private static final String REPLACE = "replace";
60 private static final String COMPUTE_IF_ABSENT = "computeIfAbsent";
61 private static final String ADD_LISTENER = "addListener";
62 private static final String REMOVE_LISTENER = "removeListener";
63 private static final String NOTIFY_LISTENER = "notifyListener";
64
65 private final Map<MapEventListener<K, V>, InternalMeteredMapEventListener> listeners =
66 Maps.newIdentityHashMap();
67 private final MeteringAgent monitor;
68
69 public MeteredAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap) {
70 super(backingMap);
71 this.monitor = new MeteringAgent(PRIMITIVE_NAME, backingMap.name(), true);
72 }
73
74 @Override
75 public CompletableFuture<Integer> size() {
76 final MeteringAgent.Context timer = monitor.startTimer(SIZE);
77 return super.size()
78 .whenComplete((r, e) -> timer.stop(e));
79 }
80
81 @Override
82 public CompletableFuture<Boolean> isEmpty() {
83 final MeteringAgent.Context timer = monitor.startTimer(IS_EMPTY);
84 return super.isEmpty()
85 .whenComplete((r, e) -> timer.stop(e));
86 }
87
88 @Override
89 public CompletableFuture<Boolean> containsKey(K key) {
90 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_KEY);
91 return super.containsKey(key)
92 .whenComplete((r, e) -> timer.stop(e));
93 }
94
95 @Override
96 public CompletableFuture<Boolean> containsValue(V value) {
97 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_VALUE);
98 return super.containsValue(value)
99 .whenComplete((r, e) -> timer.stop(e));
100 }
101
102 @Override
103 public CompletableFuture<Versioned<V>> get(K key) {
104 final MeteringAgent.Context timer = monitor.startTimer(GET);
105 return super.get(key)
106 .whenComplete((r, e) -> timer.stop(e));
107 }
108
109 @Override
110 public CompletableFuture<Versioned<V>> computeIfAbsent(K key,
111 Function<? super K, ? extends V> mappingFunction) {
112 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF_ABSENT);
113 return super.computeIfAbsent(key, mappingFunction)
114 .whenComplete((r, e) -> timer.stop(e));
115 }
116
117 @Override
118 public CompletableFuture<Versioned<V>> computeIf(K key,
119 Predicate<? super V> condition,
120 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
121 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF);
122 return super.computeIf(key, condition, remappingFunction)
123 .whenComplete((r, e) -> timer.stop(e));
124 }
125
126 @Override
127 public CompletableFuture<Versioned<V>> put(K key, V value) {
128 final MeteringAgent.Context timer = monitor.startTimer(PUT);
129 return super.put(key, value)
130 .whenComplete((r, e) -> timer.stop(e));
131 }
132
133 @Override
134 public CompletableFuture<Versioned<V>> putAndGet(K key, V value) {
135 final MeteringAgent.Context timer = monitor.startTimer(PUT_AND_GET);
136 return super.putAndGet(key, value)
137 .whenComplete((r, e) -> timer.stop(e));
138 }
139
140 @Override
141 public CompletableFuture<Versioned<V>> remove(K key) {
142 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
143 return super.remove(key)
144 .whenComplete((r, e) -> timer.stop(e));
145 }
146
147 @Override
148 public CompletableFuture<Void> clear() {
149 final MeteringAgent.Context timer = monitor.startTimer(CLEAR);
150 return super.clear()
151 .whenComplete((r, e) -> timer.stop(e));
152 }
153
154 @Override
155 public CompletableFuture<Set<K>> keySet() {
156 final MeteringAgent.Context timer = monitor.startTimer(KEY_SET);
157 return super.keySet()
158 .whenComplete((r, e) -> timer.stop(e));
159 }
160
161 @Override
162 public CompletableFuture<Collection<Versioned<V>>> values() {
163 final MeteringAgent.Context timer = monitor.startTimer(VALUES);
164 return super.values()
165 .whenComplete((r, e) -> timer.stop(e));
166 }
167
168 @Override
169 public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() {
170 final MeteringAgent.Context timer = monitor.startTimer(ENTRY_SET);
171 return super.entrySet()
172 .whenComplete((r, e) -> timer.stop(e));
173 }
174
175 @Override
176 public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) {
177 final MeteringAgent.Context timer = monitor.startTimer(PUT_IF_ABSENT);
178 return super.putIfAbsent(key, value)
179 .whenComplete((r, e) -> timer.stop(e));
180 }
181
182 @Override
183 public CompletableFuture<Boolean> remove(K key, V value) {
184 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
185 return super.remove(key, value)
186 .whenComplete((r, e) -> timer.stop(e));
187
188 }
189
190 @Override
191 public CompletableFuture<Boolean> remove(K key, long version) {
192 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
193 return super.remove(key, version)
194 .whenComplete((r, e) -> timer.stop(e));
195 }
196
197 @Override
198 public CompletableFuture<Versioned<V>> replace(K key, V value) {
199 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
200 return super.replace(key, value)
201 .whenComplete((r, e) -> timer.stop(e));
202 }
203
204 @Override
205 public CompletableFuture<Boolean> replace(K key, V oldValue, V newValue) {
206 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
207 return super.replace(key, oldValue, newValue)
208 .whenComplete((r, e) -> timer.stop(e));
209 }
210
211 @Override
212 public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) {
213 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
214 return super.replace(key, oldVersion, newValue)
215 .whenComplete((r, e) -> timer.stop(e));
216 }
217
218 @Override
219 public CompletableFuture<Void> addListener(MapEventListener<K, V> listener) {
220 final MeteringAgent.Context timer = monitor.startTimer(ADD_LISTENER);
221 synchronized (listeners) {
222 InternalMeteredMapEventListener meteredListener =
223 listeners.computeIfAbsent(listener, k -> new InternalMeteredMapEventListener(listener));
224 return super.addListener(meteredListener)
225 .whenComplete((r, e) -> timer.stop(e));
226 }
227 }
228
229 @Override
230 public CompletableFuture<Void> removeListener(MapEventListener<K, V> listener) {
231 final MeteringAgent.Context timer = monitor.startTimer(REMOVE_LISTENER);
232 InternalMeteredMapEventListener meteredListener = listeners.remove(listener);
233 if (meteredListener != null) {
234 return super.removeListener(listener)
235 .whenComplete((r, e) -> timer.stop(e));
236 } else {
237 timer.stop(null);
238 return CompletableFuture.completedFuture(null);
239 }
240 }
241
242 private class InternalMeteredMapEventListener implements MapEventListener<K, V> {
243
244 private final MapEventListener<K, V> listener;
245
246 InternalMeteredMapEventListener(MapEventListener<K, V> listener) {
247 this.listener = listener;
248 }
249
250 @Override
251 public void event(MapEvent<K, V> event) {
252 final MeteringAgent.Context timer = monitor.startTimer(NOTIFY_LISTENER);
253 try {
254 listener.event(event);
255 timer.stop(null);
256 } catch (Exception e) {
257 timer.stop(e);
258 Throwables.propagate(e);
259 }
260 }
261 }
262}