blob: aa08c8d17cc5ac1442ed7042c62e0a1d3e636fd2 [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;
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) {
Jordan Halterman00e92da2018-05-22 23:05:52 -070048 map = new ConcurrentHashMap<>();
Ray Milkey6f440332015-07-31 10:40:53 -070049 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() {
Thiago Santos01c93382017-10-20 14:22:57 -0700187 for (K key : map.keySet().stream().collect(Collectors.toList())) {
188 remove(key);
189 }
Ray Milkey6f440332015-07-31 10:40:53 -0700190 }
191
192 @Override
193 public Set<K> keySet() {
194 return map.keySet();
195 }
196
197 @Override
198 public Collection<Versioned<V>> values() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800199 return map.values()
Ray Milkey6f440332015-07-31 10:40:53 -0700200 .stream()
Ray Milkey6f440332015-07-31 10:40:53 -0700201 .collect(Collectors.toList());
202 }
203
204 @Override
205 public Set<Map.Entry<K, Versioned<V>>> entrySet() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800206 return map.entrySet();
Ray Milkey6f440332015-07-31 10:40:53 -0700207 }
208
209 @Override
210 public Versioned<V> putIfAbsent(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800211 Versioned<V> newValue = version(value);
212 Versioned<V> result = map.putIfAbsent(key, newValue);
213 if (result == null) {
214 notifyListeners(mapName, key, newValue, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700215 }
216 return result;
217 }
218
219 @Override
220 public boolean remove(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800221 Versioned<V> existingValue = map.get(key);
222 if (Objects.equal(Versioned.valueOrNull(existingValue), value)) {
223 map.remove(key);
224 notifyListeners(mapName, key, null, existingValue);
225 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700226 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800227 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700228 }
229
230 @Override
231 public boolean remove(K key, long version) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800232 Versioned<V> existingValue = map.get(key);
233 if (existingValue == null) {
234 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700235 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800236 if (existingValue.version() == version) {
237 map.remove(key);
238 notifyListeners(mapName, key, null, existingValue);
239 return true;
240 }
241 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700242 }
243
244 @Override
Jihwan Kim9887ad92015-12-12 00:23:57 +0900245 public Versioned<V> replace(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800246 Versioned<V> existingValue = map.get(key);
247 if (existingValue == null) {
248 return null;
Jihwan Kim9887ad92015-12-12 00:23:57 +0900249 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800250 Versioned<V> newValue = version(value);
251 Versioned<V> result = map.put(key, newValue);
252 notifyListeners(mapName, key, newValue, result);
Jihwan Kim9887ad92015-12-12 00:23:57 +0900253 return result;
254 }
255
256 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700257 public boolean replace(K key, V oldValue, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800258 Versioned<V> existingValue = map.get(key);
259 if (existingValue == null || !existingValue.value().equals(oldValue)) {
260 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700261 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800262 Versioned<V> value = version(newValue);
263 Versioned<V> result = map.put(key, value);
264 notifyListeners(mapName, key, value, result);
265 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700266 }
267
268 @Override
269 public boolean replace(K key, long oldVersion, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800270 Versioned<V> existingValue = map.get(key);
271 if (existingValue == null || existingValue.version() != oldVersion) {
272 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700273 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800274 Versioned<V> value = version(newValue);
275 Versioned<V> result = map.put(key, value);
276 notifyListeners(mapName, key, value, result);
277 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700278 }
279
280 @Override
281 public void addListener(MapEventListener<K, V> listener) {
282 listeners.add(listener);
283 }
284
285 @Override
286 public void removeListener(MapEventListener<K, V> listener) {
287 listeners.remove(listener);
288 }
289
alshabibe1248b62015-08-20 17:21:55 -0700290 @Override
291 public Map<K, V> asJavaMap() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800292 return new ConsistentMapBackedJavaMap<>(this);
alshabibe1248b62015-08-20 17:21:55 -0700293 }
294
Ray Milkey6f440332015-07-31 10:40:53 -0700295 public static Builder builder() {
296 return new Builder();
297 }
298
Madan Jampani538be742016-02-10 14:55:38 -0800299 public static class Builder<K, V> extends ConsistentMapBuilder<K, V> {
Flavio Castro41b1f3a2015-07-31 13:51:32 -0700300
301 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700302 public ConsistentMap<K, V> build() {
Charles Chan593acf92017-11-22 13:55:41 -0800303 return new TestConsistentMap<>(name(), serializer());
Ray Milkey6f440332015-07-31 10:40:53 -0700304 }
305
306 @Override
307 public AsyncConsistentMap<K, V> buildAsyncMap() {
308 return null;
309 }
310
311 }
312
313}