blob: c397f30feed7aa85001893d74b125f8786eb4a73 [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;
Aaron Kruglikov1110b2c2016-02-02 16:24:37 -080035import org.onosproject.utils.MeteringAgent;
Madan Jampani10073672016-01-21 19:13:59 -080036
37/**
38 * {@link AsyncConsistentMap} that meters all its operations.
39 *
40 * @param <K> key type
41 * @param <V> value type
42 */
43public class MeteredAsyncConsistentMap<K, V> extends DelegatingAsyncConsistentMap<K, V> {
44
45 private static final String PRIMITIVE_NAME = "consistentMap";
46 private static final String SIZE = "size";
47 private static final String IS_EMPTY = "isEmpty";
48 private static final String CONTAINS_KEY = "containsKey";
49 private static final String CONTAINS_VALUE = "containsValue";
50 private static final String GET = "get";
51 private static final String COMPUTE_IF = "computeIf";
52 private static final String PUT = "put";
53 private static final String PUT_AND_GET = "putAndGet";
54 private static final String PUT_IF_ABSENT = "putIfAbsent";
55 private static final String REMOVE = "remove";
56 private static final String CLEAR = "clear";
57 private static final String KEY_SET = "keySet";
58 private static final String VALUES = "values";
59 private static final String ENTRY_SET = "entrySet";
60 private static final String REPLACE = "replace";
61 private static final String COMPUTE_IF_ABSENT = "computeIfAbsent";
62 private static final String ADD_LISTENER = "addListener";
63 private static final String REMOVE_LISTENER = "removeListener";
64 private static final String NOTIFY_LISTENER = "notifyListener";
65
66 private final Map<MapEventListener<K, V>, InternalMeteredMapEventListener> listeners =
67 Maps.newIdentityHashMap();
68 private final MeteringAgent monitor;
69
70 public MeteredAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap) {
71 super(backingMap);
72 this.monitor = new MeteringAgent(PRIMITIVE_NAME, backingMap.name(), true);
73 }
74
75 @Override
76 public CompletableFuture<Integer> size() {
77 final MeteringAgent.Context timer = monitor.startTimer(SIZE);
78 return super.size()
79 .whenComplete((r, e) -> timer.stop(e));
80 }
81
82 @Override
83 public CompletableFuture<Boolean> isEmpty() {
84 final MeteringAgent.Context timer = monitor.startTimer(IS_EMPTY);
85 return super.isEmpty()
86 .whenComplete((r, e) -> timer.stop(e));
87 }
88
89 @Override
90 public CompletableFuture<Boolean> containsKey(K key) {
91 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_KEY);
92 return super.containsKey(key)
93 .whenComplete((r, e) -> timer.stop(e));
94 }
95
96 @Override
97 public CompletableFuture<Boolean> containsValue(V value) {
98 final MeteringAgent.Context timer = monitor.startTimer(CONTAINS_VALUE);
99 return super.containsValue(value)
100 .whenComplete((r, e) -> timer.stop(e));
101 }
102
103 @Override
104 public CompletableFuture<Versioned<V>> get(K key) {
105 final MeteringAgent.Context timer = monitor.startTimer(GET);
106 return super.get(key)
107 .whenComplete((r, e) -> timer.stop(e));
108 }
109
110 @Override
111 public CompletableFuture<Versioned<V>> computeIfAbsent(K key,
112 Function<? super K, ? extends V> mappingFunction) {
113 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF_ABSENT);
114 return super.computeIfAbsent(key, mappingFunction)
115 .whenComplete((r, e) -> timer.stop(e));
116 }
117
118 @Override
119 public CompletableFuture<Versioned<V>> computeIf(K key,
120 Predicate<? super V> condition,
121 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
122 final MeteringAgent.Context timer = monitor.startTimer(COMPUTE_IF);
123 return super.computeIf(key, condition, remappingFunction)
124 .whenComplete((r, e) -> timer.stop(e));
125 }
126
127 @Override
128 public CompletableFuture<Versioned<V>> put(K key, V value) {
129 final MeteringAgent.Context timer = monitor.startTimer(PUT);
130 return super.put(key, value)
131 .whenComplete((r, e) -> timer.stop(e));
132 }
133
134 @Override
135 public CompletableFuture<Versioned<V>> putAndGet(K key, V value) {
136 final MeteringAgent.Context timer = monitor.startTimer(PUT_AND_GET);
137 return super.putAndGet(key, value)
138 .whenComplete((r, e) -> timer.stop(e));
139 }
140
141 @Override
142 public CompletableFuture<Versioned<V>> remove(K key) {
143 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
144 return super.remove(key)
145 .whenComplete((r, e) -> timer.stop(e));
146 }
147
148 @Override
149 public CompletableFuture<Void> clear() {
150 final MeteringAgent.Context timer = monitor.startTimer(CLEAR);
151 return super.clear()
152 .whenComplete((r, e) -> timer.stop(e));
153 }
154
155 @Override
156 public CompletableFuture<Set<K>> keySet() {
157 final MeteringAgent.Context timer = monitor.startTimer(KEY_SET);
158 return super.keySet()
159 .whenComplete((r, e) -> timer.stop(e));
160 }
161
162 @Override
163 public CompletableFuture<Collection<Versioned<V>>> values() {
164 final MeteringAgent.Context timer = monitor.startTimer(VALUES);
165 return super.values()
166 .whenComplete((r, e) -> timer.stop(e));
167 }
168
169 @Override
170 public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() {
171 final MeteringAgent.Context timer = monitor.startTimer(ENTRY_SET);
172 return super.entrySet()
173 .whenComplete((r, e) -> timer.stop(e));
174 }
175
176 @Override
177 public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) {
178 final MeteringAgent.Context timer = monitor.startTimer(PUT_IF_ABSENT);
179 return super.putIfAbsent(key, value)
180 .whenComplete((r, e) -> timer.stop(e));
181 }
182
183 @Override
184 public CompletableFuture<Boolean> remove(K key, V value) {
185 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
186 return super.remove(key, value)
187 .whenComplete((r, e) -> timer.stop(e));
188
189 }
190
191 @Override
192 public CompletableFuture<Boolean> remove(K key, long version) {
193 final MeteringAgent.Context timer = monitor.startTimer(REMOVE);
194 return super.remove(key, version)
195 .whenComplete((r, e) -> timer.stop(e));
196 }
197
198 @Override
199 public CompletableFuture<Versioned<V>> replace(K key, V value) {
200 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
201 return super.replace(key, value)
202 .whenComplete((r, e) -> timer.stop(e));
203 }
204
205 @Override
206 public CompletableFuture<Boolean> replace(K key, V oldValue, V newValue) {
207 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
208 return super.replace(key, oldValue, newValue)
209 .whenComplete((r, e) -> timer.stop(e));
210 }
211
212 @Override
213 public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) {
214 final MeteringAgent.Context timer = monitor.startTimer(REPLACE);
215 return super.replace(key, oldVersion, newValue)
216 .whenComplete((r, e) -> timer.stop(e));
217 }
218
219 @Override
220 public CompletableFuture<Void> addListener(MapEventListener<K, V> listener) {
221 final MeteringAgent.Context timer = monitor.startTimer(ADD_LISTENER);
222 synchronized (listeners) {
223 InternalMeteredMapEventListener meteredListener =
224 listeners.computeIfAbsent(listener, k -> new InternalMeteredMapEventListener(listener));
225 return super.addListener(meteredListener)
226 .whenComplete((r, e) -> timer.stop(e));
227 }
228 }
229
230 @Override
231 public CompletableFuture<Void> removeListener(MapEventListener<K, V> listener) {
232 final MeteringAgent.Context timer = monitor.startTimer(REMOVE_LISTENER);
233 InternalMeteredMapEventListener meteredListener = listeners.remove(listener);
234 if (meteredListener != null) {
235 return super.removeListener(listener)
236 .whenComplete((r, e) -> timer.stop(e));
237 } else {
238 timer.stop(null);
239 return CompletableFuture.completedFuture(null);
240 }
241 }
242
243 private class InternalMeteredMapEventListener implements MapEventListener<K, V> {
244
245 private final MapEventListener<K, V> listener;
246
247 InternalMeteredMapEventListener(MapEventListener<K, V> listener) {
248 this.listener = listener;
249 }
250
251 @Override
252 public void event(MapEvent<K, V> event) {
253 final MeteringAgent.Context timer = monitor.startTimer(NOTIFY_LISTENER);
254 try {
255 listener.event(event);
256 timer.stop(null);
257 } catch (Exception e) {
258 timer.stop(e);
259 Throwables.propagate(e);
260 }
261 }
262 }
263}