blob: 05207956a9422a9d7988f658b541e08a7eabe209 [file] [log] [blame]
Ray Milkey6f440332015-07-31 10:40:53 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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);
Ray Milkey6f440332015-07-31 10:40:53 -070045
46 private TestConsistentMap(String mapName) {
47 map = new HashMap<>();
48 listeners = new LinkedList<>();
49 this.mapName = mapName;
50 }
51
52 private Versioned<V> version(V v) {
alshabibe1248b62015-08-20 17:21:55 -070053 return new Versioned<>(v, counter.incrementAndGet(), System.currentTimeMillis());
Ray Milkey6f440332015-07-31 10:40:53 -070054 }
55
56 /**
57 * Notify all listeners of an event.
58 */
Madan Jampanif95290a2016-01-27 21:06:11 -080059 private void notifyListeners(String mapName,
60 K key, Versioned<V> newvalue, Versioned<V> oldValue) {
61 MapEvent<K, V> event = new MapEvent<>(mapName, key, newvalue, oldValue);
Ray Milkey6f440332015-07-31 10:40:53 -070062 listeners.forEach(
63 listener -> listener.event(event)
64 );
65 }
66
67 @Override
68 public int size() {
69 return map.size();
70 }
71
72 @Override
73 public boolean isEmpty() {
74 return map.isEmpty();
75 }
76
77 @Override
78 public boolean containsKey(K key) {
79 return map.containsKey(key);
80 }
81
82 @Override
83 public boolean containsValue(V value) {
84 return map.containsValue(value);
85 }
86
87 @Override
88 public Versioned<V> get(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -080089 return map.get(key);
Ray Milkey6f440332015-07-31 10:40:53 -070090 }
91
92 @Override
93 public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -080094 AtomicBoolean updated = new AtomicBoolean(false);
95 Versioned<V> result = map.compute(key, (k, v) -> {
96 if (v == null) {
97 updated.set(true);
98 return version(mappingFunction.apply(key));
99 }
100 return v;
101 });
102 if (updated.get()) {
103 notifyListeners(mapName, key, result, null);
104 }
Ray Milkey6f440332015-07-31 10:40:53 -0700105 return result;
106 }
107
108 @Override
109 public Versioned<V> compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800110 AtomicBoolean updated = new AtomicBoolean(false);
111 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
112 Versioned<V> result = map.compute(key, (k, v) -> {
113 updated.set(true);
114 previousValue.set(v);
115 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
116 });
117 if (updated.get()) {
118 notifyListeners(mapName, key, result, previousValue.get());
119 }
120 return result;
Ray Milkey6f440332015-07-31 10:40:53 -0700121 }
122
123 @Override
124 public Versioned<V> computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800125 AtomicBoolean updated = new AtomicBoolean(false);
126 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
127 Versioned<V> result = map.compute(key, (k, v) -> {
128 if (v != null) {
129 updated.set(true);
130 previousValue.set(v);
131 return version(remappingFunction.apply(k, v.value()));
Brian O'Connorb2a383f2015-12-07 20:05:14 -0800132 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800133 return v;
134 });
135 if (updated.get()) {
136 notifyListeners(mapName, key, result, previousValue.get());
alshabibe1248b62015-08-20 17:21:55 -0700137 }
Ray Milkey6f440332015-07-31 10:40:53 -0700138 return result;
139 }
140
141 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800142 public Versioned<V> computeIf(K key, Predicate<? super V> condition,
143 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
144 AtomicBoolean updated = new AtomicBoolean(false);
145 AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
146 Versioned<V> result = map.compute(key, (k, v) -> {
147 if (condition.test(Versioned.valueOrNull(v))) {
148 previousValue.set(v);
149 updated.set(true);
150 return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
151 }
152 return v;
153 });
154 if (updated.get()) {
155 notifyListeners(mapName, key, result, previousValue.get());
156 }
Ray Milkey6f440332015-07-31 10:40:53 -0700157 return result;
158 }
159
160 @Override
Madan Jampanif95290a2016-01-27 21:06:11 -0800161 public Versioned<V> put(K key, V value) {
162 Versioned<V> newValue = version(value);
163 Versioned<V> previousValue = map.put(key, newValue);
164 notifyListeners(mapName, key, newValue, previousValue);
165 return previousValue;
166 }
167
168 @Override
169 public Versioned<V> putAndGet(K key, V value) {
170 Versioned<V> newValue = version(value);
171 Versioned<V> previousValue = map.put(key, newValue);
172 notifyListeners(mapName, key, newValue, previousValue);
173 return newValue;
174 }
175
176 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700177 public Versioned<V> remove(K key) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800178 Versioned<V> result = map.remove(key);
179 notifyListeners(mapName, key, null, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700180 return result;
181 }
182
183 @Override
184 public void clear() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800185 map.keySet().forEach(this::remove);
Ray Milkey6f440332015-07-31 10:40:53 -0700186 }
187
188 @Override
189 public Set<K> keySet() {
190 return map.keySet();
191 }
192
193 @Override
194 public Collection<Versioned<V>> values() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800195 return map.values()
Ray Milkey6f440332015-07-31 10:40:53 -0700196 .stream()
Ray Milkey6f440332015-07-31 10:40:53 -0700197 .collect(Collectors.toList());
198 }
199
200 @Override
201 public Set<Map.Entry<K, Versioned<V>>> entrySet() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800202 return map.entrySet();
Ray Milkey6f440332015-07-31 10:40:53 -0700203 }
204
205 @Override
206 public Versioned<V> putIfAbsent(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800207 Versioned<V> newValue = version(value);
208 Versioned<V> result = map.putIfAbsent(key, newValue);
209 if (result == null) {
210 notifyListeners(mapName, key, newValue, result);
Ray Milkey6f440332015-07-31 10:40:53 -0700211 }
212 return result;
213 }
214
215 @Override
216 public boolean remove(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800217 Versioned<V> existingValue = map.get(key);
218 if (Objects.equal(Versioned.valueOrNull(existingValue), value)) {
219 map.remove(key);
220 notifyListeners(mapName, key, null, existingValue);
221 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700222 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800223 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700224 }
225
226 @Override
227 public boolean remove(K key, long version) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800228 Versioned<V> existingValue = map.get(key);
229 if (existingValue == null) {
230 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700231 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800232 if (existingValue.version() == version) {
233 map.remove(key);
234 notifyListeners(mapName, key, null, existingValue);
235 return true;
236 }
237 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700238 }
239
240 @Override
Jihwan Kim9887ad92015-12-12 00:23:57 +0900241 public Versioned<V> replace(K key, V value) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800242 Versioned<V> existingValue = map.get(key);
243 if (existingValue == null) {
244 return null;
Jihwan Kim9887ad92015-12-12 00:23:57 +0900245 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800246 Versioned<V> newValue = version(value);
247 Versioned<V> result = map.put(key, newValue);
248 notifyListeners(mapName, key, newValue, result);
Jihwan Kim9887ad92015-12-12 00:23:57 +0900249 return result;
250 }
251
252 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700253 public boolean replace(K key, V oldValue, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800254 Versioned<V> existingValue = map.get(key);
255 if (existingValue == null || !existingValue.value().equals(oldValue)) {
256 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700257 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800258 Versioned<V> value = version(newValue);
259 Versioned<V> result = map.put(key, value);
260 notifyListeners(mapName, key, value, result);
261 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700262 }
263
264 @Override
265 public boolean replace(K key, long oldVersion, V newValue) {
Madan Jampanif95290a2016-01-27 21:06:11 -0800266 Versioned<V> existingValue = map.get(key);
267 if (existingValue == null || existingValue.version() != oldVersion) {
268 return false;
Ray Milkey6f440332015-07-31 10:40:53 -0700269 }
Madan Jampanif95290a2016-01-27 21:06:11 -0800270 Versioned<V> value = version(newValue);
271 Versioned<V> result = map.put(key, value);
272 notifyListeners(mapName, key, value, result);
273 return true;
Ray Milkey6f440332015-07-31 10:40:53 -0700274 }
275
276 @Override
277 public void addListener(MapEventListener<K, V> listener) {
278 listeners.add(listener);
279 }
280
281 @Override
282 public void removeListener(MapEventListener<K, V> listener) {
283 listeners.remove(listener);
284 }
285
alshabibe1248b62015-08-20 17:21:55 -0700286 @Override
287 public Map<K, V> asJavaMap() {
Madan Jampanif95290a2016-01-27 21:06:11 -0800288 return new ConsistentMapBackedJavaMap<>(this);
alshabibe1248b62015-08-20 17:21:55 -0700289 }
290
Ray Milkey6f440332015-07-31 10:40:53 -0700291 public static Builder builder() {
292 return new Builder();
293 }
294
Madan Jampani538be742016-02-10 14:55:38 -0800295 public static class Builder<K, V> extends ConsistentMapBuilder<K, V> {
Flavio Castro41b1f3a2015-07-31 13:51:32 -0700296
297 @Override
Ray Milkey6f440332015-07-31 10:40:53 -0700298 public ConsistentMap<K, V> build() {
Madan Jampani538be742016-02-10 14:55:38 -0800299 return new TestConsistentMap<>(name());
Ray Milkey6f440332015-07-31 10:40:53 -0700300 }
301
302 @Override
303 public AsyncConsistentMap<K, V> buildAsyncMap() {
304 return null;
305 }
306
307 }
308
309}