blob: 4b9ff9848dc3004a261c0bdb80176ccfdfa9a32d [file] [log] [blame]
Madan Jampani10073672016-01-21 19:13:59 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Madan Jampani10073672016-01-21 19:13:59 -08003 *
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;
Hyunsun Moon65b38cb2016-05-06 18:27:37 -070024import java.util.concurrent.Executor;
Madan Jampani10073672016-01-21 19:13:59 -080025import java.util.function.BiFunction;
26import java.util.function.Function;
27import java.util.function.Predicate;
28
Jordan Halterman948d6592017-04-20 17:18:24 -070029import org.onosproject.store.primitives.MapUpdate;
Madan Jampani542d9e22016-04-05 15:39:55 -070030import org.onosproject.store.primitives.TransactionId;
Madan Jampani10073672016-01-21 19:13:59 -080031import org.onosproject.store.service.AsyncConsistentMap;
32import org.onosproject.store.service.MapEvent;
33import org.onosproject.store.service.MapEventListener;
Jordan Halterman948d6592017-04-20 17:18:24 -070034import org.onosproject.store.service.TransactionLog;
35import org.onosproject.store.service.Version;
Madan Jampani10073672016-01-21 19:13:59 -080036import org.onosproject.store.service.Versioned;
37
38import com.google.common.base.Throwables;
39import com.google.common.collect.Maps;
Madan Jampani542d9e22016-04-05 15:39:55 -070040
Aaron Kruglikov1110b2c2016-02-02 16:24:37 -080041import org.onosproject.utils.MeteringAgent;
Madan Jampani10073672016-01-21 19:13:59 -080042
43/**
44 * {@link AsyncConsistentMap} that meters all its operations.
45 *
46 * @param <K> key type
47 * @param <V> value type
48 */
49public class MeteredAsyncConsistentMap<K, V> extends DelegatingAsyncConsistentMap<K, V> {
50
51 private static final String PRIMITIVE_NAME = "consistentMap";
52 private static final String SIZE = "size";
53 private static final String IS_EMPTY = "isEmpty";
54 private static final String CONTAINS_KEY = "containsKey";
55 private static final String CONTAINS_VALUE = "containsValue";
56 private static final String GET = "get";
Jordan Haltermanb2243072017-05-09 12:04:04 -070057 private static final String GET_OR_DEFAULT = "getOrDefault";
Madan Jampani10073672016-01-21 19:13:59 -080058 private static final String COMPUTE_IF = "computeIf";
59 private static final String PUT = "put";
60 private static final String PUT_AND_GET = "putAndGet";
61 private static final String PUT_IF_ABSENT = "putIfAbsent";
62 private static final String REMOVE = "remove";
63 private static final String CLEAR = "clear";
64 private static final String KEY_SET = "keySet";
65 private static final String VALUES = "values";
66 private static final String ENTRY_SET = "entrySet";
67 private static final String REPLACE = "replace";
68 private static final String COMPUTE_IF_ABSENT = "computeIfAbsent";
Jordan Halterman948d6592017-04-20 17:18:24 -070069 private static final String BEGIN = "begin";
Madan Jampani542d9e22016-04-05 15:39:55 -070070 private static final String PREPARE = "prepare";
71 private static final String COMMIT = "commit";
72 private static final String ROLLBACK = "rollback";
73 private static final String PREPARE_AND_COMMIT = "prepareAndCommit";
Madan Jampani10073672016-01-21 19:13:59 -080074 private static final String ADD_LISTENER = "addListener";
75 private static final String REMOVE_LISTENER = "removeListener";
76 private static final String NOTIFY_LISTENER = "notifyListener";
77
78 private final Map<MapEventListener<K, V>, InternalMeteredMapEventListener> listeners =
79 Maps.newIdentityHashMap();
80 private final MeteringAgent monitor;
81
82 public MeteredAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap) {
83 super(backingMap);
84 this.monitor = new MeteringAgent(PRIMITIVE_NAME, backingMap.name(), true);
85 }
86
87 @Override
88 public CompletableFuture<Integer> size() {
89 final MeteringAgent.Context timer = monitor.startTimer(SIZE);
90 return super.size()
91 .whenComplete((r, e) -> timer.stop(e));
92 }
93
94 @Override
95 public CompletableFuture<Boolean> isEmpty() {
96 final MeteringAgent.Context timer = monitor.startTimer(IS_EMPTY);
97 return super.isEmpty()
98 .whenComplete((r, e) -> timer.stop(e));
99 }
100
101 @Override
102 public CompletableFuture<Boolean> containsKey(K key) {
103 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_KEY);
104 return super.containsKey(key)
105 .whenComplete((r, e) -> timer.stop(e));
106 }
107
108 @Override
109 public CompletableFuture<Boolean> containsValue(V value) {
110 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_VALUE);
111 return super.containsValue(value)
112 .whenComplete((r, e) -> timer.stop(e));
113 }
114
115 @Override
116 public CompletableFuture<Versioned<V>> get(K key) {
117 final MeteringAgent.Context timer = monitor.startTimer(GET);
118 return super.get(key)
119 .whenComplete((r, e) -> timer.stop(e));
120 }
121
122 @Override
Jordan Haltermanb2243072017-05-09 12:04:04 -0700123 public CompletableFuture<Versioned<V>> getOrDefault(K key, V defaultValue) {
124 final MeteringAgent.Context timer = monitor.startTimer(GET_OR_DEFAULT);
125 return super.getOrDefault(key, defaultValue)
126 .whenComplete((r, e) -> timer.stop(e));
127 }
128
129 @Override
Madan Jampani10073672016-01-21 19:13:59 -0800130 public CompletableFuture<Versioned<V>> computeIfAbsent(K key,
131 Function<? super K, ? extends V> mappingFunction) {
132 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF_ABSENT);
133 return super.computeIfAbsent(key, mappingFunction)
134 .whenComplete((r, e) -> timer.stop(e));
135 }
136
137 @Override
138 public CompletableFuture<Versioned<V>> computeIf(K key,
139 Predicate<? super V> condition,
140 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
141 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF);
142 return super.computeIf(key, condition, remappingFunction)
143 .whenComplete((r, e) -> timer.stop(e));
144 }
145
146 @Override
147 public CompletableFuture<Versioned<V>> put(K key, V value) {
148 final MeteringAgent.Context timer = monitor.startTimer(PUT);
149 return super.put(key, value)
150 .whenComplete((r, e) -> timer.stop(e));
151 }
152
153 @Override
154 public CompletableFuture<Versioned<V>> putAndGet(K key, V value) {
155 final MeteringAgent.Context timer = monitor.startTimer(PUT_AND_GET);
156 return super.putAndGet(key, value)
157 .whenComplete((r, e) -> timer.stop(e));
158 }
159
160 @Override
161 public CompletableFuture<Versioned<V>> remove(K key) {
162 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
163 return super.remove(key)
164 .whenComplete((r, e) -> timer.stop(e));
165 }
166
167 @Override
168 public CompletableFuture<Void> clear() {
169 final MeteringAgent.Context timer = monitor.startTimer(CLEAR);
170 return super.clear()
171 .whenComplete((r, e) -> timer.stop(e));
172 }
173
174 @Override
175 public CompletableFuture<Set<K>> keySet() {
176 final MeteringAgent.Context timer = monitor.startTimer(KEY_SET);
177 return super.keySet()
178 .whenComplete((r, e) -> timer.stop(e));
179 }
180
181 @Override
182 public CompletableFuture<Collection<Versioned<V>>> values() {
183 final MeteringAgent.Context timer = monitor.startTimer(VALUES);
184 return super.values()
185 .whenComplete((r, e) -> timer.stop(e));
186 }
187
188 @Override
189 public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() {
190 final MeteringAgent.Context timer = monitor.startTimer(ENTRY_SET);
191 return super.entrySet()
192 .whenComplete((r, e) -> timer.stop(e));
193 }
194
195 @Override
196 public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) {
197 final MeteringAgent.Context timer = monitor.startTimer(PUT_IF_ABSENT);
198 return super.putIfAbsent(key, value)
199 .whenComplete((r, e) -> timer.stop(e));
200 }
201
202 @Override
203 public CompletableFuture<Boolean> remove(K key, V value) {
204 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
205 return super.remove(key, value)
206 .whenComplete((r, e) -> timer.stop(e));
207
208 }
209
210 @Override
211 public CompletableFuture<Boolean> remove(K key, long version) {
212 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
213 return super.remove(key, version)
214 .whenComplete((r, e) -> timer.stop(e));
215 }
216
217 @Override
218 public CompletableFuture<Versioned<V>> replace(K key, V value) {
219 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
220 return super.replace(key, value)
221 .whenComplete((r, e) -> timer.stop(e));
222 }
223
224 @Override
225 public CompletableFuture<Boolean> replace(K key, V oldValue, V newValue) {
226 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
227 return super.replace(key, oldValue, newValue)
228 .whenComplete((r, e) -> timer.stop(e));
229 }
230
231 @Override
232 public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) {
233 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
234 return super.replace(key, oldVersion, newValue)
235 .whenComplete((r, e) -> timer.stop(e));
236 }
237
238 @Override
Hyunsun Moon65b38cb2016-05-06 18:27:37 -0700239 public CompletableFuture<Void> addListener(MapEventListener<K, V> listener, Executor executor) {
Madan Jampani10073672016-01-21 19:13:59 -0800240 final MeteringAgent.Context timer = monitor.startTimer(ADD_LISTENER);
241 synchronized (listeners) {
242 InternalMeteredMapEventListener meteredListener =
243 listeners.computeIfAbsent(listener, k -> new InternalMeteredMapEventListener(listener));
Hyunsun Moon65b38cb2016-05-06 18:27:37 -0700244 return super.addListener(meteredListener, executor)
Madan Jampani10073672016-01-21 19:13:59 -0800245 .whenComplete((r, e) -> timer.stop(e));
246 }
247 }
248
249 @Override
250 public CompletableFuture<Void> removeListener(MapEventListener<K, V> listener) {
251 final MeteringAgent.Context timer = monitor.startTimer(REMOVE_LISTENER);
252 InternalMeteredMapEventListener meteredListener = listeners.remove(listener);
253 if (meteredListener != null) {
Hyunsun Moon65b38cb2016-05-06 18:27:37 -0700254 return super.removeListener(meteredListener)
Madan Jampani10073672016-01-21 19:13:59 -0800255 .whenComplete((r, e) -> timer.stop(e));
256 } else {
257 timer.stop(null);
258 return CompletableFuture.completedFuture(null);
259 }
260 }
261
Madan Jampani542d9e22016-04-05 15:39:55 -0700262 @Override
Jordan Halterman948d6592017-04-20 17:18:24 -0700263 public CompletableFuture<Version> begin(TransactionId transactionId) {
264 final MeteringAgent.Context timer = monitor.startTimer(BEGIN);
265 return super.begin(transactionId)
266 .whenComplete((r, e) -> timer.stop(e));
267 }
268
269 @Override
270 public CompletableFuture<Boolean> prepare(TransactionLog<MapUpdate<K, V>> transactionLog) {
Madan Jampani542d9e22016-04-05 15:39:55 -0700271 final MeteringAgent.Context timer = monitor.startTimer(PREPARE);
Jordan Halterman948d6592017-04-20 17:18:24 -0700272 return super.prepare(transactionLog)
273 .whenComplete((r, e) -> timer.stop(e));
Madan Jampani542d9e22016-04-05 15:39:55 -0700274 }
275
276 @Override
277 public CompletableFuture<Void> commit(TransactionId transactionId) {
278 final MeteringAgent.Context timer = monitor.startTimer(COMMIT);
279 return super.commit(transactionId)
280 .whenComplete((r, e) -> timer.stop(e));
281 }
282
283 @Override
284 public CompletableFuture<Void> rollback(TransactionId transactionId) {
285 final MeteringAgent.Context timer = monitor.startTimer(ROLLBACK);
286 return super.rollback(transactionId)
287 .whenComplete((r, e) -> timer.stop(e));
288 }
289
290 @Override
Jordan Halterman948d6592017-04-20 17:18:24 -0700291 public CompletableFuture<Boolean> prepareAndCommit(TransactionLog<MapUpdate<K, V>> transactionLog) {
Madan Jampani542d9e22016-04-05 15:39:55 -0700292 final MeteringAgent.Context timer = monitor.startTimer(PREPARE_AND_COMMIT);
Jordan Halterman948d6592017-04-20 17:18:24 -0700293 return super.prepareAndCommit(transactionLog)
294 .whenComplete((r, e) -> timer.stop(e));
Madan Jampani542d9e22016-04-05 15:39:55 -0700295 }
296
Madan Jampani10073672016-01-21 19:13:59 -0800297 private class InternalMeteredMapEventListener implements MapEventListener<K, V> {
298
299 private final MapEventListener<K, V> listener;
300
301 InternalMeteredMapEventListener(MapEventListener<K, V> listener) {
302 this.listener = listener;
303 }
304
305 @Override
306 public void event(MapEvent<K, V> event) {
307 final MeteringAgent.Context timer = monitor.startTimer(NOTIFY_LISTENER);
308 try {
309 listener.event(event);
310 timer.stop(null);
311 } catch (Exception e) {
312 timer.stop(e);
313 Throwables.propagate(e);
314 }
315 }
316 }
317}