blob: 84d173497fa93c080ed91a8e58b09f5e229545e4 [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;
Ray Milkey6f440332015-07-31 10:40:53 -070019import java.util.LinkedList;
20import java.util.List;
21import java.util.Map;
22import java.util.Set;
Jordan Halterman00e92da2018-05-22 23:05:52 -070023import java.util.concurrent.ConcurrentHashMap;
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;
pierventree97f4832020-07-13 14:07:05 +020031import java.util.stream.Stream;
Ray Milkey6f440332015-07-31 10:40:53 -070032
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);
Charles Chan593acf92017-11-22 13:55:41 -080046 private final Serializer serializer;
Ray Milkey6f440332015-07-31 10:40:53 -070047
Charles Chan593acf92017-11-22 13:55:41 -080048 private TestConsistentMap(String mapName, Serializer serializer) {
Jordan Halterman00e92da2018-05-22 23:05:52 -070049 map = new ConcurrentHashMap<>();
Ray Milkey6f440332015-07-31 10:40:53 -070050 listeners = new LinkedList<>();
51 this.mapName = mapName;
Charles Chan593acf92017-11-22 13:55:41 -080052 this.serializer = serializer;
Ray Milkey6f440332015-07-31 10:40:53 -070053 }
54
55 private Versioned<V> version(V v) {
alshabibe1248b62015-08-20 17:21:55 -070056 return new Versioned<>(v, counter.incrementAndGet(), System.currentTimeMillis());
Ray Milkey6f440332015-07-31 10:40:53 -070057 }
58
59 /**
60 * Notify all listeners of an event.
61 */
Madan Jampanif95290a2016-01-27 21:06:11 -080062 private void notifyListeners(String mapName,
63 K key, Versioned<V> newvalue, Versioned<V> oldValue) {
64 MapEvent<K, V> event = new MapEvent<>(mapName, key, newvalue, oldValue);
Ray Milkey6f440332015-07-31 10:40:53 -070065 listeners.forEach(
66 listener -> listener.event(event)
67 );
68 }
69
70 @Override
71 public int size() {
72 return map.size();
73 }
74
75 @Override
76 public boolean isEmpty() {
77 return map.isEmpty();
78 }
79
80 @Override
81 public boolean containsKey(K key) {
82 return map.containsKey(key);
83 }
84
85 @Override
86 public boolean containsValue(V value) {
87 return map.containsValue(value);
88 }
89
90 @Override
91 public Versioned<V> get(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -080092 return map.get(key);
Ray Milkey6f440332015-07-31 10:40:53 -070093 }
94
95 @Override
96 public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -080097 AtomicBoolean updated = new AtomicBoolean(false);
98 Versioned<V> result = map.compute(key, (k, v) -> {
99 if (v == null) {
100 updated.set(true);
101 return version(mappingFunction.apply(key));
102 }
103 return v;
104 });
105 if (updated.get()) {
106 notifyListeners(mapName, key, result, null);
107 }
Ray Milkey6f440332015-07-31 10:40:53 -0700108 return result;
109 }
110
111 @Override
112 public Versioned<V> compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800113 AtomicBoolean updated = new AtomicBoolean(false);
114 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
115 Versioned<V> result = map.compute(key, (k, v) -> {
116 updated.set(true);
Charles Chan593acf92017-11-22 13:55:41 -0800117 previousValue.set(serializer.decode(serializer.encode(v)));
Madan Jampanif95290a2016-01-27 21:06:11 -0800118 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
119 });
120 if (updated.get()) {
121 notifyListeners(mapName, key, result, previousValue.get());
122 }
123 return result;
Ray Milkey6f440332015-07-31 10:40:53 -0700124 }
125
126 @Override
127 public Versioned<V> computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800128 AtomicBoolean updated = new AtomicBoolean(false);
129 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
130 Versioned<V> result = map.compute(key, (k, v) -> {
131 if (v != null) {
132 updated.set(true);
Charles Chan593acf92017-11-22 13:55:41 -0800133 previousValue.set(serializer.decode(serializer.encode(v)));
Madan Jampanif95290a2016-01-27 21:06:11 -0800134 return version(remappingFunction.apply(k, v.value()));
Brian O'Connorb2a383f2015-12-07 20:05:14 -0800135 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800136 return v;
137 });
138 if (updated.get()) {
139 notifyListeners(mapName, key, result, previousValue.get());
alshabibe1248b62015-08-20 17:21:55 -0700140 }
Ray Milkey6f440332015-07-31 10:40:53 -0700141 return result;
142 }
143
144 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800145 public Versioned<V> computeIf(K key, Predicate<? super V> condition,
146 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
147 AtomicBoolean updated = new AtomicBoolean(false);
148 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
149 Versioned<V> result = map.compute(key, (k, v) -> {
150 if (condition.test(Versioned.valueOrNull(v))) {
Charles Chan593acf92017-11-22 13:55:41 -0800151 previousValue.set(serializer.decode(serializer.encode(v)));
Madan Jampanif95290a2016-01-27 21:06:11 -0800152 updated.set(true);
153 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
154 }
155 return v;
156 });
157 if (updated.get()) {
158 notifyListeners(mapName, key, result, previousValue.get());
159 }
Ray Milkey6f440332015-07-31 10:40:53 -0700160 return result;
161 }
162
163 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800164 public Versioned<V> put(K key, V value) {
165 Versioned<V> newValue = version(value);
166 Versioned<V> previousValue = map.put(key, newValue);
167 notifyListeners(mapName, key, newValue, previousValue);
168 return previousValue;
169 }
170
171 @Override
172 public Versioned<V> putAndGet(K key, V value) {
173 Versioned<V> newValue = version(value);
174 Versioned<V> previousValue = map.put(key, newValue);
175 notifyListeners(mapName, key, newValue, previousValue);
176 return newValue;
177 }
178
179 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700180 public Versioned<V> remove(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800181 Versioned<V> result = map.remove(key);
182 notifyListeners(mapName, key, null, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700183 return result;
184 }
185
186 @Override
187 public void clear() {
Thiago Santos01c93382017-10-20 14:22:57 -0700188 for (K key : map.keySet().stream().collect(Collectors.toList())) {
189 remove(key);
190 }
Ray Milkey6f440332015-07-31 10:40:53 -0700191 }
192
193 @Override
194 public Set<K> keySet() {
195 return map.keySet();
196 }
197
198 @Override
199 public Collection<Versioned<V>> values() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800200 return map.values()
Ray Milkey6f440332015-07-31 10:40:53 -0700201 .stream()
Ray Milkey6f440332015-07-31 10:40:53 -0700202 .collect(Collectors.toList());
203 }
204
205 @Override
206 public Set<Map.Entry<K, Versioned<V>>> entrySet() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800207 return map.entrySet();
Ray Milkey6f440332015-07-31 10:40:53 -0700208 }
209
210 @Override
211 public Versioned<V> putIfAbsent(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800212 Versioned<V> newValue = version(value);
213 Versioned<V> result = map.putIfAbsent(key, newValue);
214 if (result == null) {
215 notifyListeners(mapName, key, newValue, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700216 }
217 return result;
218 }
219
220 @Override
221 public boolean remove(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800222 Versioned<V> existingValue = map.get(key);
223 if (Objects.equal(Versioned.valueOrNull(existingValue), value)) {
224 map.remove(key);
225 notifyListeners(mapName, key, null, existingValue);
226 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700227 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800228 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700229 }
230
231 @Override
232 public boolean remove(K key, long version) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800233 Versioned<V> existingValue = map.get(key);
234 if (existingValue == null) {
235 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700236 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800237 if (existingValue.version() == version) {
238 map.remove(key);
239 notifyListeners(mapName, key, null, existingValue);
240 return true;
241 }
242 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700243 }
244
245 @Override
Jihwan Kim9887ad92015-12-12 00:23:57 +0900246 public Versioned<V> replace(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800247 Versioned<V> existingValue = map.get(key);
248 if (existingValue == null) {
249 return null;
Jihwan Kim9887ad92015-12-12 00:23:57 +0900250 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800251 Versioned<V> newValue = version(value);
252 Versioned<V> result = map.put(key, newValue);
253 notifyListeners(mapName, key, newValue, result);
Jihwan Kim9887ad92015-12-12 00:23:57 +0900254 return result;
255 }
256
257 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700258 public boolean replace(K key, V oldValue, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800259 Versioned<V> existingValue = map.get(key);
260 if (existingValue == null || !existingValue.value().equals(oldValue)) {
261 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700262 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800263 Versioned<V> value = version(newValue);
264 Versioned<V> result = map.put(key, value);
265 notifyListeners(mapName, key, value, result);
266 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700267 }
268
269 @Override
270 public boolean replace(K key, long oldVersion, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800271 Versioned<V> existingValue = map.get(key);
272 if (existingValue == null || existingValue.version() != oldVersion) {
273 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700274 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800275 Versioned<V> value = version(newValue);
276 Versioned<V> result = map.put(key, value);
277 notifyListeners(mapName, key, value, result);
278 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700279 }
280
281 @Override
pierventree97f4832020-07-13 14:07:05 +0200282 public Stream<Map.Entry<K, Versioned<V>>> stream() {
283 return map.entrySet().stream();
284 }
285
286 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700287 public void addListener(MapEventListener<K, V> listener) {
288 listeners.add(listener);
289 }
290
291 @Override
292 public void removeListener(MapEventListener<K, V> listener) {
293 listeners.remove(listener);
294 }
295
alshabibe1248b62015-08-20 17:21:55 -0700296 @Override
297 public Map<K, V> asJavaMap() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800298 return new ConsistentMapBackedJavaMap<>(this);
alshabibe1248b62015-08-20 17:21:55 -0700299 }
300
Ray Milkey6f440332015-07-31 10:40:53 -0700301 public static Builder builder() {
302 return new Builder();
303 }
304
Madan Jampani538be742016-02-10 14:55:38 -0800305 public static class Builder<K, V> extends ConsistentMapBuilder<K, V> {
Flavio Castro41b1f3a2015-07-31 13:51:32 -0700306
307 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700308 public ConsistentMap<K, V> build() {
Charles Chan593acf92017-11-22 13:55:41 -0800309 return new TestConsistentMap<>(name(), serializer());
Ray Milkey6f440332015-07-31 10:40:53 -0700310 }
311
312 @Override
313 public AsyncConsistentMap<K, V> buildAsyncMap() {
314 return null;
315 }
316
317 }
318
319}