blob: 673a5317e2fc06797e58cbe565f468268e6bf122 [file] [log] [blame]
Ray Milkey6f440332015-07-31 10:40:53 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Ray Milkey6f440332015-07-31 10:40:53 -07003 *
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
Madan Jampanif95290a2016-01-27 21:06:11 -080032import org.onosproject.store.primitives.ConsistentMapBackedJavaMap;
Madan Jampania090a112016-01-18 16:38:17 -080033
Madan Jampanif95290a2016-01-27 21:06:11 -080034import com.google.common.base.Objects;
Ray Milkey6f440332015-07-31 10:40:53 -070035
36/**
37 * Test implementation of the consistent map.
38 */
39public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
40
41 private final List<MapEventListener<K, V>> listeners;
Madan Jampanif95290a2016-01-27 21:06:11 -080042 private final Map<K, Versioned<V>> map;
Ray Milkey6f440332015-07-31 10:40:53 -070043 private final String mapName;
alshabibe1248b62015-08-20 17:21:55 -070044 private final AtomicLong counter = new AtomicLong(0);
Charles Chan593acf92017-11-22 13:55:41 -080045 private final Serializer serializer;
Ray Milkey6f440332015-07-31 10:40:53 -070046
Charles Chan593acf92017-11-22 13:55:41 -080047 private TestConsistentMap(String mapName, Serializer serializer) {
Ray Milkey6f440332015-07-31 10:40:53 -070048 map = new HashMap<>();
49 listeners = new LinkedList<>();
50 this.mapName = mapName;
Charles Chan593acf92017-11-22 13:55:41 -080051 this.serializer = serializer;
Ray Milkey6f440332015-07-31 10:40:53 -070052 }
53
54 private Versioned<V> version(V v) {
alshabibe1248b62015-08-20 17:21:55 -070055 return new Versioned<>(v, counter.incrementAndGet(), System.currentTimeMillis());
Ray Milkey6f440332015-07-31 10:40:53 -070056 }
57
58 /**
59 * Notify all listeners of an event.
60 */
Madan Jampanif95290a2016-01-27 21:06:11 -080061 private void notifyListeners(String mapName,
62 K key, Versioned<V> newvalue, Versioned<V> oldValue) {
63 MapEvent<K, V> event = new MapEvent<>(mapName, key, newvalue, oldValue);
Ray Milkey6f440332015-07-31 10:40:53 -070064 listeners.forEach(
65 listener -> listener.event(event)
66 );
67 }
68
69 @Override
70 public int size() {
71 return map.size();
72 }
73
74 @Override
75 public boolean isEmpty() {
76 return map.isEmpty();
77 }
78
79 @Override
80 public boolean containsKey(K key) {
81 return map.containsKey(key);
82 }
83
84 @Override
85 public boolean containsValue(V value) {
86 return map.containsValue(value);
87 }
88
89 @Override
90 public Versioned<V> get(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -080091 return map.get(key);
Ray Milkey6f440332015-07-31 10:40:53 -070092 }
93
94 @Override
95 public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -080096 AtomicBoolean updated = new AtomicBoolean(false);
97 Versioned<V> result = map.compute(key, (k, v) -> {
98 if (v == null) {
99 updated.set(true);
100 return version(mappingFunction.apply(key));
101 }
102 return v;
103 });
104 if (updated.get()) {
105 notifyListeners(mapName, key, result, null);
106 }
Ray Milkey6f440332015-07-31 10:40:53 -0700107 return result;
108 }
109
110 @Override
111 public Versioned<V> compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800112 AtomicBoolean updated = new AtomicBoolean(false);
113 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
114 Versioned<V> result = map.compute(key, (k, v) -> {
115 updated.set(true);
Charles Chan593acf92017-11-22 13:55:41 -0800116 previousValue.set(serializer.decode(serializer.encode(v)));
Madan Jampanif95290a2016-01-27 21:06:11 -0800117 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
118 });
119 if (updated.get()) {
120 notifyListeners(mapName, key, result, previousValue.get());
121 }
122 return result;
Ray Milkey6f440332015-07-31 10:40:53 -0700123 }
124
125 @Override
126 public Versioned<V> computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800127 AtomicBoolean updated = new AtomicBoolean(false);
128 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
129 Versioned<V> result = map.compute(key, (k, v) -> {
130 if (v != null) {
131 updated.set(true);
Charles Chan593acf92017-11-22 13:55:41 -0800132 previousValue.set(serializer.decode(serializer.encode(v)));
Madan Jampanif95290a2016-01-27 21:06:11 -0800133 return version(remappingFunction.apply(k, v.value()));
Brian O'Connorb2a383f2015-12-07 20:05:14 -0800134 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800135 return v;
136 });
137 if (updated.get()) {
138 notifyListeners(mapName, key, result, previousValue.get());
alshabibe1248b62015-08-20 17:21:55 -0700139 }
Ray Milkey6f440332015-07-31 10:40:53 -0700140 return result;
141 }
142
143 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800144 public Versioned<V> computeIf(K key, Predicate<? super V> condition,
145 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
146 AtomicBoolean updated = new AtomicBoolean(false);
147 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
148 Versioned<V> result = map.compute(key, (k, v) -> {
149 if (condition.test(Versioned.valueOrNull(v))) {
Charles Chan593acf92017-11-22 13:55:41 -0800150 previousValue.set(serializer.decode(serializer.encode(v)));
Madan Jampanif95290a2016-01-27 21:06:11 -0800151 updated.set(true);
152 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
153 }
154 return v;
155 });
156 if (updated.get()) {
157 notifyListeners(mapName, key, result, previousValue.get());
158 }
Ray Milkey6f440332015-07-31 10:40:53 -0700159 return result;
160 }
161
162 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800163 public Versioned<V> put(K key, V value) {
164 Versioned<V> newValue = version(value);
165 Versioned<V> previousValue = map.put(key, newValue);
166 notifyListeners(mapName, key, newValue, previousValue);
167 return previousValue;
168 }
169
170 @Override
171 public Versioned<V> putAndGet(K key, V value) {
172 Versioned<V> newValue = version(value);
173 Versioned<V> previousValue = map.put(key, newValue);
174 notifyListeners(mapName, key, newValue, previousValue);
175 return newValue;
176 }
177
178 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700179 public Versioned<V> remove(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800180 Versioned<V> result = map.remove(key);
181 notifyListeners(mapName, key, null, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700182 return result;
183 }
184
185 @Override
186 public void clear() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800187 map.keySet().forEach(this::remove);
Ray Milkey6f440332015-07-31 10:40:53 -0700188 }
189
190 @Override
191 public Set<K> keySet() {
192 return map.keySet();
193 }
194
195 @Override
196 public Collection<Versioned<V>> values() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800197 return map.values()
Ray Milkey6f440332015-07-31 10:40:53 -0700198 .stream()
Ray Milkey6f440332015-07-31 10:40:53 -0700199 .collect(Collectors.toList());
200 }
201
202 @Override
203 public Set<Map.Entry<K, Versioned<V>>> entrySet() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800204 return map.entrySet();
Ray Milkey6f440332015-07-31 10:40:53 -0700205 }
206
207 @Override
208 public Versioned<V> putIfAbsent(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800209 Versioned<V> newValue = version(value);
210 Versioned<V> result = map.putIfAbsent(key, newValue);
211 if (result == null) {
212 notifyListeners(mapName, key, newValue, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700213 }
214 return result;
215 }
216
217 @Override
218 public boolean remove(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800219 Versioned<V> existingValue = map.get(key);
220 if (Objects.equal(Versioned.valueOrNull(existingValue), value)) {
221 map.remove(key);
222 notifyListeners(mapName, key, null, existingValue);
223 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700224 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800225 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700226 }
227
228 @Override
229 public boolean remove(K key, long version) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800230 Versioned<V> existingValue = map.get(key);
231 if (existingValue == null) {
232 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700233 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800234 if (existingValue.version() == version) {
235 map.remove(key);
236 notifyListeners(mapName, key, null, existingValue);
237 return true;
238 }
239 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700240 }
241
242 @Override
Jihwan Kim9887ad92015-12-12 00:23:57 +0900243 public Versioned<V> replace(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800244 Versioned<V> existingValue = map.get(key);
245 if (existingValue == null) {
246 return null;
Jihwan Kim9887ad92015-12-12 00:23:57 +0900247 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800248 Versioned<V> newValue = version(value);
249 Versioned<V> result = map.put(key, newValue);
250 notifyListeners(mapName, key, newValue, result);
Jihwan Kim9887ad92015-12-12 00:23:57 +0900251 return result;
252 }
253
254 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700255 public boolean replace(K key, V oldValue, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800256 Versioned<V> existingValue = map.get(key);
257 if (existingValue == null || !existingValue.value().equals(oldValue)) {
258 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700259 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800260 Versioned<V> value = version(newValue);
261 Versioned<V> result = map.put(key, value);
262 notifyListeners(mapName, key, value, result);
263 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700264 }
265
266 @Override
267 public boolean replace(K key, long oldVersion, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800268 Versioned<V> existingValue = map.get(key);
269 if (existingValue == null || existingValue.version() != oldVersion) {
270 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700271 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800272 Versioned<V> value = version(newValue);
273 Versioned<V> result = map.put(key, value);
274 notifyListeners(mapName, key, value, result);
275 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700276 }
277
278 @Override
279 public void addListener(MapEventListener<K, V> listener) {
280 listeners.add(listener);
281 }
282
283 @Override
284 public void removeListener(MapEventListener<K, V> listener) {
285 listeners.remove(listener);
286 }
287
alshabibe1248b62015-08-20 17:21:55 -0700288 @Override
289 public Map<K, V> asJavaMap() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800290 return new ConsistentMapBackedJavaMap<>(this);
alshabibe1248b62015-08-20 17:21:55 -0700291 }
292
Ray Milkey6f440332015-07-31 10:40:53 -0700293 public static Builder builder() {
294 return new Builder();
295 }
296
Madan Jampani538be742016-02-10 14:55:38 -0800297 public static class Builder<K, V> extends ConsistentMapBuilder<K, V> {
Flavio Castro41b1f3a2015-07-31 13:51:32 -0700298
299 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700300 public ConsistentMap<K, V> build() {
Charles Chan593acf92017-11-22 13:55:41 -0800301 return new TestConsistentMap<>(name(), serializer());
Ray Milkey6f440332015-07-31 10:40:53 -0700302 }
303
304 @Override
305 public AsyncConsistentMap<K, V> buildAsyncMap() {
306 return null;
307 }
308
309 }
310
311}