Madan Jampani

Added newValue and oldValue methods to MapEvent.

Change-Id: Ibaffc8079de03b1f4623044ec53c949831ea8cd1
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.store.primitives.impl; 16 +package org.onosproject.store.primitives;
17 17
18 import java.util.Collection; 18 import java.util.Collection;
19 import java.util.Map; 19 import java.util.Map;
......
...@@ -50,21 +50,24 @@ public class MapEvent<K, V> { ...@@ -50,21 +50,24 @@ public class MapEvent<K, V> {
50 private final String name; 50 private final String name;
51 private final Type type; 51 private final Type type;
52 private final K key; 52 private final K key;
53 - private final Versioned<V> value; 53 + private final Versioned<V> newValue;
54 + private final Versioned<V> oldValue;
54 55
55 /** 56 /**
56 * Creates a new event object. 57 * Creates a new event object.
57 * 58 *
58 * @param name map name 59 * @param name map name
59 - * @param type type of event
60 * @param key key the event concerns 60 * @param key key the event concerns
61 - * @param value value key is mapped to 61 + * @param currentValue new value key is mapped to
62 + * @param previousValue value that was replaced
62 */ 63 */
63 - public MapEvent(String name, Type type, K key, Versioned<V> value) { 64 + public MapEvent(String name, K key, Versioned<V> currentValue, Versioned<V> previousValue) {
64 this.name = name; 65 this.name = name;
65 - this.type = type;
66 this.key = key; 66 this.key = key;
67 - this.value = value; 67 + this.newValue = currentValue;
68 + this.oldValue = previousValue;
69 + this.type = currentValue != null ?
70 + previousValue != null ? Type.UPDATE : Type.INSERT : Type.REMOVE;
68 } 71 }
69 72
70 /** 73 /**
...@@ -100,9 +103,30 @@ public class MapEvent<K, V> { ...@@ -100,9 +103,30 @@ public class MapEvent<K, V> {
100 * the new value. 103 * the new value.
101 * 104 *
102 * @return the value 105 * @return the value
106 + * @deprecated use {@link #newValue()} or {@link #oldValue()} instead.
103 */ 107 */
108 + @Deprecated
104 public Versioned<V> value() { 109 public Versioned<V> value() {
105 - return value; 110 + return type == Type.REMOVE ? oldValue() : newValue();
111 + }
112 +
113 + /**
114 + * Returns the new value in the map associated with the key. If {@link #type()} returns {@code REMOVE},
115 + * this method will return {@code null}.
116 + *
117 + * @return the new value for key
118 + */
119 + public Versioned<V> newValue() {
120 + return newValue;
121 + }
122 +
123 + /**
124 + * Returns the value associated with the key, before it was updated.
125 + *
126 + * @return previous value in map for the key
127 + */
128 + public Versioned<V> oldValue() {
129 + return oldValue;
106 } 130 }
107 131
108 @Override 132 @Override
...@@ -115,12 +139,13 @@ public class MapEvent<K, V> { ...@@ -115,12 +139,13 @@ public class MapEvent<K, V> {
115 return Objects.equals(this.name, that.name) && 139 return Objects.equals(this.name, that.name) &&
116 Objects.equals(this.type, that.type) && 140 Objects.equals(this.type, that.type) &&
117 Objects.equals(this.key, that.key) && 141 Objects.equals(this.key, that.key) &&
118 - Objects.equals(this.value, that.value); 142 + Objects.equals(this.newValue, that.newValue) &&
143 + Objects.equals(this.oldValue, that.oldValue);
119 } 144 }
120 145
121 @Override 146 @Override
122 public int hashCode() { 147 public int hashCode() {
123 - return Objects.hash(name, type, key, value); 148 + return Objects.hash(name, type, key, newValue, oldValue);
124 } 149 }
125 150
126 @Override 151 @Override
...@@ -129,7 +154,8 @@ public class MapEvent<K, V> { ...@@ -129,7 +154,8 @@ public class MapEvent<K, V> {
129 .add("name", name) 154 .add("name", name)
130 .add("type", type) 155 .add("type", type)
131 .add("key", key) 156 .add("key", key)
132 - .add("value", value) 157 + .add("newValue", newValue)
158 + .add("oldValue", oldValue)
133 .toString(); 159 .toString();
134 } 160 }
135 } 161 }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.store.service; 16 package org.onosproject.store.service;
17 17
18 import com.google.common.testing.EqualsTester; 18 import com.google.common.testing.EqualsTester;
19 +
19 import org.junit.Test; 20 import org.junit.Test;
20 21
21 import static org.hamcrest.MatcherAssert.assertThat; 22 import static org.hamcrest.MatcherAssert.assertThat;
...@@ -26,13 +27,14 @@ import static org.hamcrest.Matchers.is; ...@@ -26,13 +27,14 @@ import static org.hamcrest.Matchers.is;
26 */ 27 */
27 public class MapEventTest { 28 public class MapEventTest {
28 29
29 - private final Versioned<Integer> vStats = new Versioned<>(2, 1); 30 + private final Versioned<Integer> vStatsNew = new Versioned<>(2, 2);
31 + private final Versioned<Integer> vStatsOld = new Versioned<>(1, 1);
30 32
31 - private final MapEvent<String, Integer> stats1 = new MapEvent<>("a", MapEvent.Type.INSERT, "1", vStats); 33 + private final MapEvent<String, Integer> stats1 = new MapEvent<>("a", "1", vStatsNew, null);
32 34
33 - private final MapEvent<String, Integer> stats2 = new MapEvent<>("a", MapEvent.Type.REMOVE, "1", vStats); 35 + private final MapEvent<String, Integer> stats2 = new MapEvent<>("a", "1", null, vStatsOld);
34 36
35 - private final MapEvent<String, Integer> stats3 = new MapEvent<>("a", MapEvent.Type.UPDATE, "1", vStats); 37 + private final MapEvent<String, Integer> stats3 = new MapEvent<>("a", "1", vStatsNew, vStatsOld);
36 38
37 /** 39 /**
38 * Tests the creation of the MapEvent object. 40 * Tests the creation of the MapEvent object.
...@@ -42,7 +44,23 @@ public class MapEventTest { ...@@ -42,7 +44,23 @@ public class MapEventTest {
42 assertThat(stats1.name(), is("a")); 44 assertThat(stats1.name(), is("a"));
43 assertThat(stats1.type(), is(MapEvent.Type.INSERT)); 45 assertThat(stats1.type(), is(MapEvent.Type.INSERT));
44 assertThat(stats1.key(), is("1")); 46 assertThat(stats1.key(), is("1"));
45 - assertThat(stats1.value(), is(vStats)); 47 + assertThat(stats1.value(), is(vStatsNew));
48 + assertThat(stats1.newValue(), is(vStatsNew));
49 + assertThat(stats1.oldValue(), is((Versioned<Integer>) null));
50 +
51 + assertThat(stats2.name(), is("a"));
52 + assertThat(stats2.type(), is(MapEvent.Type.REMOVE));
53 + assertThat(stats2.key(), is("1"));
54 + assertThat(stats2.value(), is(vStatsOld));
55 + assertThat(stats2.newValue(), is((Versioned<Integer>) null));
56 + assertThat(stats2.oldValue(), is(vStatsOld));
57 +
58 + assertThat(stats3.name(), is("a"));
59 + assertThat(stats3.type(), is(MapEvent.Type.UPDATE));
60 + assertThat(stats3.key(), is("1"));
61 + assertThat(stats3.value(), is(vStatsNew));
62 + assertThat(stats3.newValue(), is(vStatsNew));
63 + assertThat(stats3.oldValue(), is(vStatsOld));
46 } 64 }
47 65
48 /** 66 /**
......
...@@ -21,15 +21,18 @@ import java.util.LinkedList; ...@@ -21,15 +21,18 @@ import java.util.LinkedList;
21 import java.util.List; 21 import java.util.List;
22 import java.util.Map; 22 import java.util.Map;
23 import java.util.Set; 23 import java.util.Set;
24 +import java.util.concurrent.atomic.AtomicBoolean;
24 import java.util.concurrent.atomic.AtomicLong; 25 import java.util.concurrent.atomic.AtomicLong;
26 +import java.util.concurrent.atomic.AtomicReference;
25 import java.util.function.BiFunction; 27 import java.util.function.BiFunction;
26 import java.util.function.Function; 28 import java.util.function.Function;
27 import java.util.function.Predicate; 29 import java.util.function.Predicate;
28 import java.util.stream.Collectors; 30 import java.util.stream.Collectors;
29 31
30 import org.onosproject.core.ApplicationId; 32 import org.onosproject.core.ApplicationId;
33 +import org.onosproject.store.primitives.ConsistentMapBackedJavaMap;
31 34
32 -import static org.onosproject.store.service.MapEvent.Type.*; 35 +import com.google.common.base.Objects;
33 36
34 /** 37 /**
35 * Test implementation of the consistent map. 38 * Test implementation of the consistent map.
...@@ -37,7 +40,7 @@ import static org.onosproject.store.service.MapEvent.Type.*; ...@@ -37,7 +40,7 @@ import static org.onosproject.store.service.MapEvent.Type.*;
37 public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> { 40 public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
38 41
39 private final List<MapEventListener<K, V>> listeners; 42 private final List<MapEventListener<K, V>> listeners;
40 - private final Map<K, V> map; 43 + private final Map<K, Versioned<V>> map;
41 private final String mapName; 44 private final String mapName;
42 private final AtomicLong counter = new AtomicLong(0); 45 private final AtomicLong counter = new AtomicLong(0);
43 46
...@@ -54,9 +57,9 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> { ...@@ -54,9 +57,9 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
54 /** 57 /**
55 * Notify all listeners of an event. 58 * Notify all listeners of an event.
56 */ 59 */
57 - private void notifyListeners(String mapName, MapEvent.Type type, 60 + private void notifyListeners(String mapName,
58 - K key, Versioned<V> value) { 61 + K key, Versioned<V> newvalue, Versioned<V> oldValue) {
59 - MapEvent<K, V> event = new MapEvent<>(mapName, type, key, value); 62 + MapEvent<K, V> event = new MapEvent<>(mapName, key, newvalue, oldValue);
60 listeners.forEach( 63 listeners.forEach(
61 listener -> listener.event(event) 64 listener -> listener.event(event)
62 ); 65 );
...@@ -84,71 +87,103 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> { ...@@ -84,71 +87,103 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
84 87
85 @Override 88 @Override
86 public Versioned<V> get(K key) { 89 public Versioned<V> get(K key) {
87 - V value = map.get(key); 90 + return map.get(key);
88 - if (value != null) {
89 - return version(value);
90 - } else {
91 - return null;
92 - }
93 } 91 }
94 92
95 @Override 93 @Override
96 public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { 94 public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
97 - Versioned<V> result = version(map.computeIfAbsent(key, mappingFunction)); 95 + AtomicBoolean updated = new AtomicBoolean(false);
98 - notifyListeners(mapName, INSERT, key, result); 96 + Versioned<V> result = map.compute(key, (k, v) -> {
97 + if (v == null) {
98 + updated.set(true);
99 + return version(mappingFunction.apply(key));
100 + }
101 + return v;
102 + });
103 + if (updated.get()) {
104 + notifyListeners(mapName, key, result, null);
105 + }
99 return result; 106 return result;
100 } 107 }
101 108
102 @Override 109 @Override
103 public Versioned<V> compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { 110 public Versioned<V> compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
104 - return version(map.compute(key, remappingFunction)); 111 + AtomicBoolean updated = new AtomicBoolean(false);
112 + AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
113 + Versioned<V> result = map.compute(key, (k, v) -> {
114 + updated.set(true);
115 + previousValue.set(v);
116 + return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
117 + });
118 + if (updated.get()) {
119 + notifyListeners(mapName, key, result, previousValue.get());
120 + }
121 + return result;
105 } 122 }
106 123
107 @Override 124 @Override
108 public Versioned<V> computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { 125 public Versioned<V> computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
109 - return version(map.computeIfPresent(key, remappingFunction)); 126 + AtomicBoolean updated = new AtomicBoolean(false);
127 + AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
128 + Versioned<V> result = map.compute(key, (k, v) -> {
129 + if (v != null) {
130 + updated.set(true);
131 + previousValue.set(v);
132 + return version(remappingFunction.apply(k, v.value()));
133 + }
134 + return v;
135 + });
136 + if (updated.get()) {
137 + notifyListeners(mapName, key, result, previousValue.get());
138 + }
139 + return result;
110 } 140 }
111 141
112 @Override 142 @Override
113 public Versioned<V> computeIf(K key, Predicate<? super V> condition, 143 public Versioned<V> computeIf(K key, Predicate<? super V> condition,
114 BiFunction<? super K, ? super V, ? extends V> remappingFunction) { 144 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
115 - return version(map.compute(key, (k, existingValue) -> { 145 + AtomicBoolean updated = new AtomicBoolean(false);
116 - if (condition.test(existingValue)) { 146 + AtomicReference<Versioned<V>> previousValue = new AtomicReference<>();
117 - return remappingFunction.apply(k, existingValue); 147 + Versioned<V> result = map.compute(key, (k, v) -> {
118 - } else { 148 + if (condition.test(Versioned.valueOrNull(v))) {
119 - return existingValue; 149 + previousValue.set(v);
150 + updated.set(true);
151 + return version(remappingFunction.apply(k, Versioned.valueOrNull(v)));
120 } 152 }
121 - })); 153 + return v;
154 + });
155 + if (updated.get()) {
156 + notifyListeners(mapName, key, result, previousValue.get());
157 + }
158 + return result;
122 } 159 }
123 160
124 @Override 161 @Override
125 public Versioned<V> put(K key, V value) { 162 public Versioned<V> put(K key, V value) {
126 - Versioned<V> result = version(value); 163 + Versioned<V> newValue = version(value);
127 - if (map.put(key, value) == null) { 164 + Versioned<V> previousValue = map.put(key, newValue);
128 - notifyListeners(mapName, INSERT, key, result); 165 + notifyListeners(mapName, key, newValue, previousValue);
129 - } else { 166 + return previousValue;
130 - notifyListeners(mapName, UPDATE, key, result);
131 - }
132 - return result;
133 } 167 }
134 168
135 @Override 169 @Override
136 public Versioned<V> putAndGet(K key, V value) { 170 public Versioned<V> putAndGet(K key, V value) {
137 - Versioned<V> result = version(map.put(key, value)); 171 + Versioned<V> newValue = version(value);
138 - notifyListeners(mapName, UPDATE, key, result); 172 + Versioned<V> previousValue = map.put(key, newValue);
139 - return result; 173 + notifyListeners(mapName, key, newValue, previousValue);
174 + return newValue;
140 } 175 }
141 176
142 @Override 177 @Override
143 public Versioned<V> remove(K key) { 178 public Versioned<V> remove(K key) {
144 - Versioned<V> result = version(map.remove(key)); 179 + Versioned<V> result = map.remove(key);
145 - notifyListeners(mapName, REMOVE, key, result); 180 + notifyListeners(mapName, key, null, result);
146 return result; 181 return result;
147 } 182 }
148 183
149 @Override 184 @Override
150 public void clear() { 185 public void clear() {
151 - map.clear(); 186 + map.keySet().forEach(this::remove);
152 } 187 }
153 188
154 @Override 189 @Override
...@@ -158,70 +193,85 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> { ...@@ -158,70 +193,85 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
158 193
159 @Override 194 @Override
160 public Collection<Versioned<V>> values() { 195 public Collection<Versioned<V>> values() {
161 - return map 196 + return map.values()
162 - .values()
163 .stream() 197 .stream()
164 - .map(this::version)
165 .collect(Collectors.toList()); 198 .collect(Collectors.toList());
166 } 199 }
167 200
168 @Override 201 @Override
169 public Set<Map.Entry<K, Versioned<V>>> entrySet() { 202 public Set<Map.Entry<K, Versioned<V>>> entrySet() {
170 - return super.entrySet(); 203 + return map.entrySet();
171 } 204 }
172 205
173 @Override 206 @Override
174 public Versioned<V> putIfAbsent(K key, V value) { 207 public Versioned<V> putIfAbsent(K key, V value) {
175 - Versioned<V> result = version(map.putIfAbsent(key, value)); 208 + Versioned<V> newValue = version(value);
176 - if (map.get(key).equals(value)) { 209 + Versioned<V> result = map.putIfAbsent(key, newValue);
177 - notifyListeners(mapName, INSERT, key, result); 210 + if (result == null) {
211 + notifyListeners(mapName, key, newValue, result);
178 } 212 }
179 return result; 213 return result;
180 } 214 }
181 215
182 @Override 216 @Override
183 public boolean remove(K key, V value) { 217 public boolean remove(K key, V value) {
184 - boolean removed = map.remove(key, value); 218 + Versioned<V> existingValue = map.get(key);
185 - if (removed) { 219 + if (Objects.equal(Versioned.valueOrNull(existingValue), value)) {
186 - notifyListeners(mapName, REMOVE, key, null); 220 + map.remove(key);
221 + notifyListeners(mapName, key, null, existingValue);
222 + return true;
187 } 223 }
188 - return removed; 224 + return false;
189 } 225 }
190 226
191 @Override 227 @Override
192 public boolean remove(K key, long version) { 228 public boolean remove(K key, long version) {
193 - boolean removed = map.remove(key, version); 229 + Versioned<V> existingValue = map.get(key);
194 - if (removed) { 230 + if (existingValue == null) {
195 - notifyListeners(mapName, REMOVE, key, null); 231 + return false;
232 + }
233 + if (existingValue.version() == version) {
234 + map.remove(key);
235 + notifyListeners(mapName, key, null, existingValue);
236 + return true;
196 } 237 }
197 - return removed; 238 + return false;
198 } 239 }
199 240
200 @Override 241 @Override
201 public Versioned<V> replace(K key, V value) { 242 public Versioned<V> replace(K key, V value) {
202 - Versioned<V> result = version(map.replace(key, value)); 243 + Versioned<V> existingValue = map.get(key);
203 - if (map.get(key).equals(value)) { 244 + if (existingValue == null) {
204 - notifyListeners(mapName, UPDATE, key, result); 245 + return null;
205 } 246 }
247 + Versioned<V> newValue = version(value);
248 + Versioned<V> result = map.put(key, newValue);
249 + notifyListeners(mapName, key, newValue, result);
206 return result; 250 return result;
207 } 251 }
208 252
209 @Override 253 @Override
210 public boolean replace(K key, V oldValue, V newValue) { 254 public boolean replace(K key, V oldValue, V newValue) {
211 - boolean replaced = map.replace(key, oldValue, newValue); 255 + Versioned<V> existingValue = map.get(key);
212 - if (replaced) { 256 + if (existingValue == null || !existingValue.value().equals(oldValue)) {
213 - notifyListeners(mapName, REMOVE, key, null); 257 + return false;
214 } 258 }
215 - return replaced; 259 + Versioned<V> value = version(newValue);
260 + Versioned<V> result = map.put(key, value);
261 + notifyListeners(mapName, key, value, result);
262 + return true;
216 } 263 }
217 264
218 @Override 265 @Override
219 public boolean replace(K key, long oldVersion, V newValue) { 266 public boolean replace(K key, long oldVersion, V newValue) {
220 - boolean replaced = map.replace(key, map.get(key), newValue); 267 + Versioned<V> existingValue = map.get(key);
221 - if (replaced) { 268 + if (existingValue == null || existingValue.version() != oldVersion) {
222 - notifyListeners(mapName, REMOVE, key, null); 269 + return false;
223 } 270 }
224 - return replaced; 271 + Versioned<V> value = version(newValue);
272 + Versioned<V> result = map.put(key, value);
273 + notifyListeners(mapName, key, value, result);
274 + return true;
225 } 275 }
226 276
227 @Override 277 @Override
...@@ -236,7 +286,7 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> { ...@@ -236,7 +286,7 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
236 286
237 @Override 287 @Override
238 public Map<K, V> asJavaMap() { 288 public Map<K, V> asJavaMap() {
239 - return map; 289 + return new ConsistentMapBackedJavaMap<>(this);
240 } 290 }
241 291
242 public static Builder builder() { 292 public static Builder builder() {
......
...@@ -28,6 +28,7 @@ import java.util.function.BiFunction; ...@@ -28,6 +28,7 @@ import java.util.function.BiFunction;
28 import java.util.function.Function; 28 import java.util.function.Function;
29 import java.util.function.Predicate; 29 import java.util.function.Predicate;
30 30
31 +import org.onosproject.store.primitives.ConsistentMapBackedJavaMap;
31 import org.onosproject.store.service.AsyncConsistentMap; 32 import org.onosproject.store.service.AsyncConsistentMap;
32 import org.onosproject.store.service.ConsistentMap; 33 import org.onosproject.store.service.ConsistentMap;
33 import org.onosproject.store.service.ConsistentMapException; 34 import org.onosproject.store.service.ConsistentMapException;
......
...@@ -76,10 +76,7 @@ public class UpdateResult<K, V> { ...@@ -76,10 +76,7 @@ public class UpdateResult<K, V> {
76 if (!updated) { 76 if (!updated) {
77 return null; 77 return null;
78 } else { 78 } else {
79 - MapEvent.Type eventType = oldValue == null ? 79 + return new MapEvent<>(mapName(), key(), newValue, oldValue);
80 - MapEvent.Type.INSERT : newValue == null ? MapEvent.Type.REMOVE : MapEvent.Type.UPDATE;
81 - Versioned<V> eventValue = eventType == MapEvent.Type.REMOVE ? oldValue : newValue;
82 - return new MapEvent<>(mapName(), eventType, key(), eventValue);
83 } 80 }
84 } 81 }
85 } 82 }
...\ No newline at end of file ...\ No newline at end of file
......