blob: b692bf307fac406e36ef2de0ec165290adb16e5d [file] [log] [blame]
Madan Jampani7c521002015-03-23 12:23:01 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Madan Jampani7c521002015-03-23 12:23:01 -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 */
Brian O'Connor7cbbbb72016-04-09 02:13:23 -070016package org.onosproject.store.primitives;
17
Madan Jampani7c521002015-03-23 12:23:01 -070018import java.util.Collection;
Jordan Halterman8c473582018-07-03 00:00:47 -070019import java.util.Iterator;
Madan Jampanie1065222015-08-17 16:21:51 -070020import java.util.Map;
Madan Jampani7c521002015-03-23 12:23:01 -070021import java.util.Map.Entry;
Madan Jampanif6c973a2016-01-30 22:20:48 -080022import java.util.Objects;
Madan Jampanifa242182016-01-22 13:42:54 -080023import java.util.Set;
Madan Jampani7c521002015-03-23 12:23:01 -070024import java.util.concurrent.CompletableFuture;
25import java.util.concurrent.ExecutionException;
Madan Jampani0463cf92016-05-04 14:46:08 -070026import java.util.concurrent.Executor;
Madan Jampani7c521002015-03-23 12:23:01 -070027import java.util.concurrent.TimeUnit;
28import java.util.concurrent.TimeoutException;
Madan Jampani346d4f52015-05-04 11:09:39 -070029import java.util.function.BiFunction;
Madan Jampani1d3b6172016-04-28 13:22:57 -070030import java.util.function.Consumer;
Madan Jampani346d4f52015-05-04 11:09:39 -070031import java.util.function.Function;
32import java.util.function.Predicate;
Madan Jampani7c521002015-03-23 12:23:01 -070033
Madan Jampanif6c973a2016-01-30 22:20:48 -080034import org.onlab.util.Tools;
Madan Jampania090a112016-01-18 16:38:17 -080035import org.onosproject.store.service.AsyncConsistentMap;
Jordan Halterman8c473582018-07-03 00:00:47 -070036import org.onosproject.store.service.AsyncIterator;
Madan Jampani7c521002015-03-23 12:23:01 -070037import org.onosproject.store.service.ConsistentMap;
38import org.onosproject.store.service.ConsistentMapException;
Madan Jampanif6c973a2016-01-30 22:20:48 -080039import org.onosproject.store.service.ConsistentMapException.ConcurrentModification;
Madan Jampani50589ac2015-06-08 11:38:46 -070040import org.onosproject.store.service.MapEventListener;
Madan Jampania090a112016-01-18 16:38:17 -080041import org.onosproject.store.service.Synchronous;
Madan Jampani7c521002015-03-23 12:23:01 -070042import org.onosproject.store.service.Versioned;
43
Madan Jampanif6c973a2016-01-30 22:20:48 -080044import com.google.common.base.Throwables;
45
Madan Jampani7c521002015-03-23 12:23:01 -070046/**
Madan Jampanifa242182016-01-22 13:42:54 -080047 * Default implementation of {@code ConsistentMap}.
Madan Jampani7c521002015-03-23 12:23:01 -070048 *
49 * @param <K> type of key.
50 * @param <V> type of value.
51 */
Madan Jampania090a112016-01-18 16:38:17 -080052public class DefaultConsistentMap<K, V> extends Synchronous<AsyncConsistentMap<K, V>> implements ConsistentMap<K, V> {
Madan Jampani7c521002015-03-23 12:23:01 -070053
Aaron Kruglikov2f2e81e2016-12-01 15:39:06 -080054 private static final int MAX_DELAY_BETWEEN_RETRY_MILLS = 50;
Madan Jampanifa242182016-01-22 13:42:54 -080055 private final AsyncConsistentMap<K, V> asyncMap;
Madan Jampani28b2cd62016-02-02 10:49:52 -080056 private final long operationTimeoutMillis;
Madan Jampanie1065222015-08-17 16:21:51 -070057 private Map<K, V> javaMap;
Madan Jampani7c521002015-03-23 12:23:01 -070058
Madan Jampani28b2cd62016-02-02 10:49:52 -080059 public DefaultConsistentMap(AsyncConsistentMap<K, V> asyncMap, long operationTimeoutMillis) {
Madan Jampania090a112016-01-18 16:38:17 -080060 super(asyncMap);
Madan Jampani50589ac2015-06-08 11:38:46 -070061 this.asyncMap = asyncMap;
Madan Jampani28b2cd62016-02-02 10:49:52 -080062 this.operationTimeoutMillis = operationTimeoutMillis;
Madan Jampani7c521002015-03-23 12:23:01 -070063 }
64
65 @Override
66 public int size() {
67 return complete(asyncMap.size());
68 }
69
70 @Override
71 public boolean isEmpty() {
72 return complete(asyncMap.isEmpty());
73 }
74
75 @Override
76 public boolean containsKey(K key) {
77 return complete(asyncMap.containsKey(key));
78 }
79
80 @Override
81 public boolean containsValue(V value) {
82 return complete(asyncMap.containsValue(value));
83 }
84
85 @Override
86 public Versioned<V> get(K key) {
87 return complete(asyncMap.get(key));
88 }
89
90 @Override
Jordan Haltermanf6272442017-04-20 02:18:08 -070091 public Versioned<V> getOrDefault(K key, V defaultValue) {
92 return complete(asyncMap.getOrDefault(key, defaultValue));
93 }
94
95 @Override
Madan Jampani346d4f52015-05-04 11:09:39 -070096 public Versioned<V> computeIfAbsent(K key,
97 Function<? super K, ? extends V> mappingFunction) {
Madan Jampanif6c973a2016-01-30 22:20:48 -080098 return computeIf(key, Objects::isNull, (k, v) -> mappingFunction.apply(k));
Madan Jampani346d4f52015-05-04 11:09:39 -070099 }
100
101 @Override
102 public Versioned<V> computeIfPresent(K key,
103 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif6c973a2016-01-30 22:20:48 -0800104 return computeIf(key, Objects::nonNull, remappingFunction);
Madan Jampani346d4f52015-05-04 11:09:39 -0700105 }
106
107 @Override
108 public Versioned<V> compute(K key,
109 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif6c973a2016-01-30 22:20:48 -0800110 return computeIf(key, v -> true, remappingFunction);
Madan Jampani346d4f52015-05-04 11:09:39 -0700111 }
112
113 @Override
114 public Versioned<V> computeIf(K key,
115 Predicate<? super V> condition,
116 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Madan Jampanif6c973a2016-01-30 22:20:48 -0800117 return Tools.retryable(() -> complete(asyncMap.computeIf(key, condition, remappingFunction)),
118 ConcurrentModification.class,
119 Integer.MAX_VALUE,
Aaron Kruglikov2f2e81e2016-12-01 15:39:06 -0800120 MAX_DELAY_BETWEEN_RETRY_MILLS).get();
Madan Jampani346d4f52015-05-04 11:09:39 -0700121 }
122
123 @Override
Madan Jampani7c521002015-03-23 12:23:01 -0700124 public Versioned<V> put(K key, V value) {
125 return complete(asyncMap.put(key, value));
126 }
127
128 @Override
Madan Jampani346d4f52015-05-04 11:09:39 -0700129 public Versioned<V> putAndGet(K key, V value) {
130 return complete(asyncMap.putAndGet(key, value));
131 }
132
133 @Override
Madan Jampani7c521002015-03-23 12:23:01 -0700134 public Versioned<V> remove(K key) {
135 return complete(asyncMap.remove(key));
136 }
137
138 @Override
139 public void clear() {
140 complete(asyncMap.clear());
141 }
142
143 @Override
144 public Set<K> keySet() {
145 return complete(asyncMap.keySet());
146 }
147
148 @Override
149 public Collection<Versioned<V>> values() {
150 return complete(asyncMap.values());
151 }
152
153 @Override
154 public Set<Entry<K, Versioned<V>>> entrySet() {
155 return complete(asyncMap.entrySet());
156 }
157
158 @Override
159 public Versioned<V> putIfAbsent(K key, V value) {
160 return complete(asyncMap.putIfAbsent(key, value));
161 }
162
163 @Override
164 public boolean remove(K key, V value) {
165 return complete(asyncMap.remove(key, value));
166 }
167
168 @Override
169 public boolean remove(K key, long version) {
170 return complete(asyncMap.remove(key, version));
171 }
172
173 @Override
Jihwan Kim9887ad92015-12-12 00:23:57 +0900174 public Versioned<V> replace(K key, V value) {
175 return complete(asyncMap.replace(key, value));
176 }
177
178 @Override
Madan Jampani7c521002015-03-23 12:23:01 -0700179 public boolean replace(K key, V oldValue, V newValue) {
180 return complete(asyncMap.replace(key, oldValue, newValue));
181 }
182
183 @Override
184 public boolean replace(K key, long oldVersion, V newValue) {
185 return complete(asyncMap.replace(key, oldVersion, newValue));
186 }
187
Madan Jampanifa242182016-01-22 13:42:54 -0800188 @Override
Jordan Halterman8c473582018-07-03 00:00:47 -0700189 public Iterator<Entry<K, Versioned<V>>> iterator() {
190 return new DefaultIterator<>(complete(asyncMap.iterator()));
191 }
192
193 @Override
Madan Jampani0463cf92016-05-04 14:46:08 -0700194 public void addListener(MapEventListener<K, V> listener, Executor executor) {
195 complete(asyncMap.addListener(listener, executor));
Madan Jampanifa242182016-01-22 13:42:54 -0800196 }
197
198 @Override
199 public void removeListener(MapEventListener<K, V> listener) {
Hyunsun Moon65b38cb2016-05-06 18:27:37 -0700200 complete(asyncMap.removeListener(listener));
Madan Jampanifa242182016-01-22 13:42:54 -0800201 }
202
203 @Override
Madan Jampani1d3b6172016-04-28 13:22:57 -0700204 public void addStatusChangeListener(Consumer<Status> listener) {
205 asyncMap.addStatusChangeListener(listener);
206 }
207
208 @Override
209 public void removeStatusChangeListener(Consumer<Status> listener) {
210 asyncMap.removeStatusChangeListener(listener);
211 }
212
213 @Override
214 public Collection<Consumer<Status>> statusChangeListeners() {
215 return asyncMap.statusChangeListeners();
216 }
217
Jordan Halterman8c473582018-07-03 00:00:47 -0700218 private class DefaultIterator<K, V> implements Iterator<Entry<K, Versioned<V>>> {
219 private final AsyncIterator<Entry<K, Versioned<V>>> iterator;
220
221 public DefaultIterator(AsyncIterator<Map.Entry<K, Versioned<V>>> iterator) {
222 this.iterator = iterator;
223 }
224
225 @Override
226 public boolean hasNext() {
227 return complete(iterator.hasNext());
228 }
229
230 @Override
231 public Map.Entry<K, Versioned<V>> next() {
232 return complete(iterator.next());
233 }
234 }
235
Madan Jampani1d3b6172016-04-28 13:22:57 -0700236 @Override
Madan Jampanifa242182016-01-22 13:42:54 -0800237 public Map<K, V> asJavaMap() {
238 synchronized (this) {
239 if (javaMap == null) {
240 javaMap = new ConsistentMapBackedJavaMap<>(this);
241 }
242 }
243 return javaMap;
244 }
245
HIGUCHI Yutadc4394c2016-01-29 15:35:10 -0800246 @Override
247 public String toString() {
248 return asJavaMap().toString();
249 }
250
Madan Jampani28b2cd62016-02-02 10:49:52 -0800251 private <T> T complete(CompletableFuture<T> future) {
Madan Jampani7c521002015-03-23 12:23:01 -0700252 try {
Madan Jampani28b2cd62016-02-02 10:49:52 -0800253 return future.get(operationTimeoutMillis, TimeUnit.MILLISECONDS);
Madan Jampani7c521002015-03-23 12:23:01 -0700254 } catch (InterruptedException e) {
255 Thread.currentThread().interrupt();
256 throw new ConsistentMapException.Interrupted();
257 } catch (TimeoutException e) {
Madan Jampani42755872016-09-06 19:31:06 -0700258 throw new ConsistentMapException.Timeout(name());
Madan Jampani7c521002015-03-23 12:23:01 -0700259 } catch (ExecutionException e) {
Ray Milkey6a51cb92018-03-06 09:03:03 -0800260 Throwables.throwIfUnchecked(e.getCause());
Madan Jampanif6c973a2016-01-30 22:20:48 -0800261 throw new ConsistentMapException(e.getCause());
Madan Jampani7c521002015-03-23 12:23:01 -0700262 }
263 }
Madan Jampani7c521002015-03-23 12:23:01 -0700264}