blob: ccffeadabe01195c959504b97fbbdfda12199492 [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";
57 private static final String COMPUTE_IF = "computeIf";
58 private static final String PUT = "put";
59 private static final String PUT_AND_GET = "putAndGet";
60 private static final String PUT_IF_ABSENT = "putIfAbsent";
61 private static final String REMOVE = "remove";
62 private static final String CLEAR = "clear";
63 private static final String KEY_SET = "keySet";
64 private static final String VALUES = "values";
65 private static final String ENTRY_SET = "entrySet";
66 private static final String REPLACE = "replace";
67 private static final String COMPUTE_IF_ABSENT = "computeIfAbsent";
Jordan Halterman948d6592017-04-20 17:18:24 -070068 private static final String BEGIN = "begin";
Madan Jampani542d9e22016-04-05 15:39:55 -070069 private static final String PREPARE = "prepare";
70 private static final String COMMIT = "commit";
71 private static final String ROLLBACK = "rollback";
72 private static final String PREPARE_AND_COMMIT = "prepareAndCommit";
Madan Jampani10073672016-01-21 19:13:59 -080073 private static final String ADD_LISTENER = "addListener";
74 private static final String REMOVE_LISTENER = "removeListener";
75 private static final String NOTIFY_LISTENER = "notifyListener";
76
77 private final Map<MapEventListener<K, V>, InternalMeteredMapEventListener> listeners =
78 Maps.newIdentityHashMap();
79 private final MeteringAgent monitor;
80
81 public MeteredAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap) {
82 super(backingMap);
83 this.monitor = new MeteringAgent(PRIMITIVE_NAME, backingMap.name(), true);
84 }
85
86 @Override
87 public CompletableFuture<Integer> size() {
88 final MeteringAgent.Context timer = monitor.startTimer(SIZE);
89 return super.size()
90 .whenComplete((r, e) -> timer.stop(e));
91 }
92
93 @Override
94 public CompletableFuture<Boolean> isEmpty() {
95 final MeteringAgent.Context timer = monitor.startTimer(IS_EMPTY);
96 return super.isEmpty()
97 .whenComplete((r, e) -> timer.stop(e));
98 }
99
100 @Override
101 public CompletableFuture<Boolean> containsKey(K key) {
102 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_KEY);
103 return super.containsKey(key)
104 .whenComplete((r, e) -> timer.stop(e));
105 }
106
107 @Override
108 public CompletableFuture<Boolean> containsValue(V value) {
109 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_VALUE);
110 return super.containsValue(value)
111 .whenComplete((r, e) -> timer.stop(e));
112 }
113
114 @Override
115 public CompletableFuture<Versioned<V>> get(K key) {
116 final MeteringAgent.Context timer = monitor.startTimer(GET);
117 return super.get(key)
118 .whenComplete((r, e) -> timer.stop(e));
119 }
120
121 @Override
122 public CompletableFuture<Versioned<V>> computeIfAbsent(K key,
123 Function<? super K, ? extends V> mappingFunction) {
124 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF_ABSENT);
125 return super.computeIfAbsent(key, mappingFunction)
126 .whenComplete((r, e) -> timer.stop(e));
127 }
128
129 @Override
130 public CompletableFuture<Versioned<V>> computeIf(K key,
131 Predicate<? super V> condition,
132 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
133 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF);
134 return super.computeIf(key, condition, remappingFunction)
135 .whenComplete((r, e) -> timer.stop(e));
136 }
137
138 @Override
139 public CompletableFuture<Versioned<V>> put(K key, V value) {
140 final MeteringAgent.Context timer = monitor.startTimer(PUT);
141 return super.put(key, value)
142 .whenComplete((r, e) -> timer.stop(e));
143 }
144
145 @Override
146 public CompletableFuture<Versioned<V>> putAndGet(K key, V value) {
147 final MeteringAgent.Context timer = monitor.startTimer(PUT_AND_GET);
148 return super.putAndGet(key, value)
149 .whenComplete((r, e) -> timer.stop(e));
150 }
151
152 @Override
153 public CompletableFuture<Versioned<V>> remove(K key) {
154 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
155 return super.remove(key)
156 .whenComplete((r, e) -> timer.stop(e));
157 }
158
159 @Override
160 public CompletableFuture<Void> clear() {
161 final MeteringAgent.Context timer = monitor.startTimer(CLEAR);
162 return super.clear()
163 .whenComplete((r, e) -> timer.stop(e));
164 }
165
166 @Override
167 public CompletableFuture<Set<K>> keySet() {
168 final MeteringAgent.Context timer = monitor.startTimer(KEY_SET);
169 return super.keySet()
170 .whenComplete((r, e) -> timer.stop(e));
171 }
172
173 @Override
174 public CompletableFuture<Collection<Versioned<V>>> values() {
175 final MeteringAgent.Context timer = monitor.startTimer(VALUES);
176 return super.values()
177 .whenComplete((r, e) -> timer.stop(e));
178 }
179
180 @Override
181 public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() {
182 final MeteringAgent.Context timer = monitor.startTimer(ENTRY_SET);
183 return super.entrySet()
184 .whenComplete((r, e) -> timer.stop(e));
185 }
186
187 @Override
188 public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) {
189 final MeteringAgent.Context timer = monitor.startTimer(PUT_IF_ABSENT);
190 return super.putIfAbsent(key, value)
191 .whenComplete((r, e) -> timer.stop(e));
192 }
193
194 @Override
195 public CompletableFuture<Boolean> remove(K key, V value) {
196 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
197 return super.remove(key, value)
198 .whenComplete((r, e) -> timer.stop(e));
199
200 }
201
202 @Override
203 public CompletableFuture<Boolean> remove(K key, long version) {
204 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
205 return super.remove(key, version)
206 .whenComplete((r, e) -> timer.stop(e));
207 }
208
209 @Override
210 public CompletableFuture<Versioned<V>> replace(K key, V value) {
211 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
212 return super.replace(key, value)
213 .whenComplete((r, e) -> timer.stop(e));
214 }
215
216 @Override
217 public CompletableFuture<Boolean> replace(K key, V oldValue, V newValue) {
218 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
219 return super.replace(key, oldValue, newValue)
220 .whenComplete((r, e) -> timer.stop(e));
221 }
222
223 @Override
224 public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) {
225 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
226 return super.replace(key, oldVersion, newValue)
227 .whenComplete((r, e) -> timer.stop(e));
228 }
229
230 @Override
Hyunsun Moon65b38cb2016-05-06 18:27:37 -0700231 public CompletableFuture<Void> addListener(MapEventListener<K, V> listener, Executor executor) {
Madan Jampani10073672016-01-21 19:13:59 -0800232 final MeteringAgent.Context timer = monitor.startTimer(ADD_LISTENER);
233 synchronized (listeners) {
234 InternalMeteredMapEventListener meteredListener =
235 listeners.computeIfAbsent(listener, k -> new InternalMeteredMapEventListener(listener));
Hyunsun Moon65b38cb2016-05-06 18:27:37 -0700236 return super.addListener(meteredListener, executor)
Madan Jampani10073672016-01-21 19:13:59 -0800237 .whenComplete((r, e) -> timer.stop(e));
238 }
239 }
240
241 @Override
242 public CompletableFuture<Void> removeListener(MapEventListener<K, V> listener) {
243 final MeteringAgent.Context timer = monitor.startTimer(REMOVE_LISTENER);
244 InternalMeteredMapEventListener meteredListener = listeners.remove(listener);
245 if (meteredListener != null) {
Hyunsun Moon65b38cb2016-05-06 18:27:37 -0700246 return super.removeListener(meteredListener)
Madan Jampani10073672016-01-21 19:13:59 -0800247 .whenComplete((r, e) -> timer.stop(e));
248 } else {
249 timer.stop(null);
250 return CompletableFuture.completedFuture(null);
251 }
252 }
253
Madan Jampani542d9e22016-04-05 15:39:55 -0700254 @Override
Jordan Halterman948d6592017-04-20 17:18:24 -0700255 public CompletableFuture<Version> begin(TransactionId transactionId) {
256 final MeteringAgent.Context timer = monitor.startTimer(BEGIN);
257 return super.begin(transactionId)
258 .whenComplete((r, e) -> timer.stop(e));
259 }
260
261 @Override
262 public CompletableFuture<Boolean> prepare(TransactionLog<MapUpdate<K, V>> transactionLog) {
Madan Jampani542d9e22016-04-05 15:39:55 -0700263 final MeteringAgent.Context timer = monitor.startTimer(PREPARE);
Jordan Halterman948d6592017-04-20 17:18:24 -0700264 return super.prepare(transactionLog)
265 .whenComplete((r, e) -> timer.stop(e));
Madan Jampani542d9e22016-04-05 15:39:55 -0700266 }
267
268 @Override
269 public CompletableFuture<Void> commit(TransactionId transactionId) {
270 final MeteringAgent.Context timer = monitor.startTimer(COMMIT);
271 return super.commit(transactionId)
272 .whenComplete((r, e) -> timer.stop(e));
273 }
274
275 @Override
276 public CompletableFuture<Void> rollback(TransactionId transactionId) {
277 final MeteringAgent.Context timer = monitor.startTimer(ROLLBACK);
278 return super.rollback(transactionId)
279 .whenComplete((r, e) -> timer.stop(e));
280 }
281
282 @Override
Jordan Halterman948d6592017-04-20 17:18:24 -0700283 public CompletableFuture<Boolean> prepareAndCommit(TransactionLog<MapUpdate<K, V>> transactionLog) {
Madan Jampani542d9e22016-04-05 15:39:55 -0700284 final MeteringAgent.Context timer = monitor.startTimer(PREPARE_AND_COMMIT);
Jordan Halterman948d6592017-04-20 17:18:24 -0700285 return super.prepareAndCommit(transactionLog)
286 .whenComplete((r, e) -> timer.stop(e));
Madan Jampani542d9e22016-04-05 15:39:55 -0700287 }
288
Madan Jampani10073672016-01-21 19:13:59 -0800289 private class InternalMeteredMapEventListener implements MapEventListener<K, V> {
290
291 private final MapEventListener<K, V> listener;
292
293 InternalMeteredMapEventListener(MapEventListener<K, V> listener) {
294 this.listener = listener;
295 }
296
297 @Override
298 public void event(MapEvent<K, V> event) {
299 final MeteringAgent.Context timer = monitor.startTimer(NOTIFY_LISTENER);
300 try {
301 listener.event(event);
302 timer.stop(null);
303 } catch (Exception e) {
304 timer.stop(e);
305 Throwables.propagate(e);
306 }
307 }
308 }
309}