blob: f7857adcef73fb3b582dcf89ab2a618ae2a6205d [file] [log] [blame]
Ray Milkey6f440332015-07-31 10:40:53 -07001/*
2 * Copyright 2015 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 */
16package org.onosproject.store.service;
17
18import java.util.Collection;
19import java.util.HashMap;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23import java.util.Set;
Madan Jampanif95290a2016-01-27 21:06:11 -080024import java.util.concurrent.atomic.AtomicBoolean;
alshabibe1248b62015-08-20 17:21:55 -070025import java.util.concurrent.atomic.AtomicLong;
Madan Jampanif95290a2016-01-27 21:06:11 -080026import java.util.concurrent.atomic.AtomicReference;
Ray Milkey6f440332015-07-31 10:40:53 -070027import java.util.function.BiFunction;
28import java.util.function.Function;
29import java.util.function.Predicate;
30import java.util.stream.Collectors;
31
32import org.onosproject.core.ApplicationId;
Madan Jampanif95290a2016-01-27 21:06:11 -080033import org.onosproject.store.primitives.ConsistentMapBackedJavaMap;
Madan Jampania090a112016-01-18 16:38:17 -080034
Madan Jampanif95290a2016-01-27 21:06:11 -080035import com.google.common.base.Objects;
Ray Milkey6f440332015-07-31 10:40:53 -070036
37/**
38 * Test implementation of the consistent map.
39 */
40public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
41
42 private final List<MapEventListener<K, V>> listeners;
Madan Jampanif95290a2016-01-27 21:06:11 -080043 private final Map<K, Versioned<V>> map;
Ray Milkey6f440332015-07-31 10:40:53 -070044 private final String mapName;
alshabibe1248b62015-08-20 17:21:55 -070045 private final AtomicLong counter = new AtomicLong(0);
Ray Milkey6f440332015-07-31 10:40:53 -070046
47 private TestConsistentMap(String mapName) {
48 map = new HashMap<>();
49 listeners = new LinkedList<>();
50 this.mapName = mapName;
51 }
52
53 private Versioned<V> version(V v) {
alshabibe1248b62015-08-20 17:21:55 -070054 return new Versioned<>(v, counter.incrementAndGet(), System.currentTimeMillis());
Ray Milkey6f440332015-07-31 10:40:53 -070055 }
56
57 /**
58 * Notify all listeners of an event.
59 */
Madan Jampanif95290a2016-01-27 21:06:11 -080060 private void notifyListeners(String mapName,
61 K key, Versioned<V> newvalue, Versioned<V> oldValue) {
62 MapEvent<K, V> event = new MapEvent<>(mapName, key, newvalue, oldValue);
Ray Milkey6f440332015-07-31 10:40:53 -070063 listeners.forEach(
64 listener -> listener.event(event)
65 );
66 }
67
68 @Override
69 public int size() {
70 return map.size();
71 }
72
73 @Override
74 public boolean isEmpty() {
75 return map.isEmpty();
76 }
77
78 @Override
79 public boolean containsKey(K key) {
80 return map.containsKey(key);
81 }
82
83 @Override
84 public boolean containsValue(V value) {
85 return map.containsValue(value);
86 }
87
88 @Override
89 public Versioned<V> get(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -080090 return map.get(key);
Ray Milkey6f440332015-07-31 10:40:53 -070091 }
92
93 @Override
94 public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -080095 AtomicBoolean updated = new AtomicBoolean(false);
96 Versioned<V> result = map.compute(key, (k, v) -> {
97 if (v == null) {
98 updated.set(true);
99 return version(mappingFunction.apply(key));
100 }
101 return v;
102 });
103 if (updated.get()) {
104 notifyListeners(mapName, key, result, null);
105 }
Ray Milkey6f440332015-07-31 10:40:53 -0700106 return result;
107 }
108
109 @Override
110 public Versioned<V> compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800111 AtomicBoolean updated = new AtomicBoolean(false);
112 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
113 Versioned<V> result = map.compute(key, (k, v) -> {
114 updated.set(true);
115 previousValue.set(v);
116 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
117 });
118 if (updated.get()) {
119 notifyListeners(mapName, key, result, previousValue.get());
120 }
121 return result;
Ray Milkey6f440332015-07-31 10:40:53 -0700122 }
123
124 @Override
125 public Versioned<V> computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800126 AtomicBoolean updated = new AtomicBoolean(false);
127 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
128 Versioned<V> result = map.compute(key, (k, v) -> {
129 if (v != null) {
130 updated.set(true);
131 previousValue.set(v);
132 return version(remappingFunction.apply(k, v.value()));
Brian O'Connorb2a383f2015-12-07 20:05:14 -0800133 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800134 return v;
135 });
136 if (updated.get()) {
137 notifyListeners(mapName, key, result, previousValue.get());
alshabibe1248b62015-08-20 17:21:55 -0700138 }
Ray Milkey6f440332015-07-31 10:40:53 -0700139 return result;
140 }
141
142 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800143 public Versioned<V> computeIf(K key, Predicate<? super V> condition,
144 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
145 AtomicBoolean updated = new AtomicBoolean(false);
146 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
147 Versioned<V> result = map.compute(key, (k, v) -> {
148 if (condition.test(Versioned.valueOrNull(v))) {
149 previousValue.set(v);
150 updated.set(true);
151 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
152 }
153 return v;
154 });
155 if (updated.get()) {
156 notifyListeners(mapName, key, result, previousValue.get());
157 }
Ray Milkey6f440332015-07-31 10:40:53 -0700158 return result;
159 }
160
161 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800162 public Versioned<V> put(K key, V value) {
163 Versioned<V> newValue = version(value);
164 Versioned<V> previousValue = map.put(key, newValue);
165 notifyListeners(mapName, key, newValue, previousValue);
166 return previousValue;
167 }
168
169 @Override
170 public Versioned<V> putAndGet(K key, V value) {
171 Versioned<V> newValue = version(value);
172 Versioned<V> previousValue = map.put(key, newValue);
173 notifyListeners(mapName, key, newValue, previousValue);
174 return newValue;
175 }
176
177 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700178 public Versioned<V> remove(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800179 Versioned<V> result = map.remove(key);
180 notifyListeners(mapName, key, null, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700181 return result;
182 }
183
184 @Override
185 public void clear() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800186 map.keySet().forEach(this::remove);
Ray Milkey6f440332015-07-31 10:40:53 -0700187 }
188
189 @Override
190 public Set<K> keySet() {
191 return map.keySet();
192 }
193
194 @Override
195 public Collection<Versioned<V>> values() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800196 return map.values()
Ray Milkey6f440332015-07-31 10:40:53 -0700197 .stream()
Ray Milkey6f440332015-07-31 10:40:53 -0700198 .collect(Collectors.toList());
199 }
200
201 @Override
202 public Set<Map.Entry<K, Versioned<V>>> entrySet() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800203 return map.entrySet();
Ray Milkey6f440332015-07-31 10:40:53 -0700204 }
205
206 @Override
207 public Versioned<V> putIfAbsent(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800208 Versioned<V> newValue = version(value);
209 Versioned<V> result = map.putIfAbsent(key, newValue);
210 if (result == null) {
211 notifyListeners(mapName, key, newValue, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700212 }
213 return result;
214 }
215
216 @Override
217 public boolean remove(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800218 Versioned<V> existingValue = map.get(key);
219 if (Objects.equal(Versioned.valueOrNull(existingValue), value)) {
220 map.remove(key);
221 notifyListeners(mapName, key, null, existingValue);
222 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700223 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800224 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700225 }
226
227 @Override
228 public boolean remove(K key, long version) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800229 Versioned<V> existingValue = map.get(key);
230 if (existingValue == null) {
231 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700232 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800233 if (existingValue.version() == version) {
234 map.remove(key);
235 notifyListeners(mapName, key, null, existingValue);
236 return true;
237 }
238 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700239 }
240
241 @Override
Jihwan Kim9887ad92015-12-12 00:23:57 +0900242 public Versioned<V> replace(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800243 Versioned<V> existingValue = map.get(key);
244 if (existingValue == null) {
245 return null;
Jihwan Kim9887ad92015-12-12 00:23:57 +0900246 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800247 Versioned<V> newValue = version(value);
248 Versioned<V> result = map.put(key, newValue);
249 notifyListeners(mapName, key, newValue, result);
Jihwan Kim9887ad92015-12-12 00:23:57 +0900250 return result;
251 }
252
253 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700254 public boolean replace(K key, V oldValue, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800255 Versioned<V> existingValue = map.get(key);
256 if (existingValue == null || !existingValue.value().equals(oldValue)) {
257 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700258 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800259 Versioned<V> value = version(newValue);
260 Versioned<V> result = map.put(key, value);
261 notifyListeners(mapName, key, value, result);
262 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700263 }
264
265 @Override
266 public boolean replace(K key, long oldVersion, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800267 Versioned<V> existingValue = map.get(key);
268 if (existingValue == null || existingValue.version() != oldVersion) {
269 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700270 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800271 Versioned<V> value = version(newValue);
272 Versioned<V> result = map.put(key, value);
273 notifyListeners(mapName, key, value, result);
274 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700275 }
276
277 @Override
278 public void addListener(MapEventListener<K, V> listener) {
279 listeners.add(listener);
280 }
281
282 @Override
283 public void removeListener(MapEventListener<K, V> listener) {
284 listeners.remove(listener);
285 }
286
alshabibe1248b62015-08-20 17:21:55 -0700287 @Override
288 public Map<K, V> asJavaMap() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800289 return new ConsistentMapBackedJavaMap<>(this);
alshabibe1248b62015-08-20 17:21:55 -0700290 }
291
Ray Milkey6f440332015-07-31 10:40:53 -0700292 public static Builder builder() {
293 return new Builder();
294 }
295
296 public static class Builder<K, V> implements ConsistentMapBuilder<K, V> {
297 String mapName = "map";
298
299 @Override
300 public ConsistentMapBuilder<K, V> withName(String mapName) {
301 this.mapName = mapName;
302 return this;
303 }
304
305 @Override
306 public ConsistentMapBuilder<K, V> withApplicationId(ApplicationId id) {
307 return this;
308 }
309
310 @Override
311 public ConsistentMapBuilder<K, V> withSerializer(Serializer serializer) {
312 return this;
313 }
314
315 @Override
316 public ConsistentMapBuilder<K, V> withPartitionsDisabled() {
317 return this;
318 }
319
320 @Override
321 public ConsistentMapBuilder<K, V> withUpdatesDisabled() {
322 return this;
323 }
324
325 @Override
326 public ConsistentMapBuilder<K, V> withPurgeOnUninstall() {
327 return this;
328 }
329
330 @Override
Madan Jampani3d6a2f62015-08-12 07:19:07 -0700331 public ConsistentMapBuilder<K, V> withRelaxedReadConsistency() {
332 return this;
333 }
334
335 @Override
Flavio Castro41b1f3a2015-07-31 13:51:32 -0700336 public ConsistentMapBuilder<K, V> withMeteringDisabled() {
337 return this;
338 }
339
340 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700341 public ConsistentMap<K, V> build() {
342 return new TestConsistentMap<>(mapName);
343 }
344
345 @Override
346 public AsyncConsistentMap<K, V> buildAsyncMap() {
347 return null;
348 }
349
350 }
351
352}