ONOS-4396: Fix for EC Map synchronization failing silently due to serialization failures.
With this change we proactively fail map updates when serialization failures can occur and immediately notify the caller Change-Id: I62a8a84731b9c2a6eeff7fa6f8336dc74234bf30
Showing
3 changed files
with
22 additions
and
3 deletions
... | @@ -339,8 +339,11 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -339,8 +339,11 @@ public class EventuallyConsistentMapImpl<K, V> |
339 | checkNotNull(value, ERROR_NULL_VALUE); | 339 | checkNotNull(value, ERROR_NULL_VALUE); |
340 | 340 | ||
341 | MapValue<V> newValue = new MapValue<>(value, timestampProvider.apply(key, value)); | 341 | MapValue<V> newValue = new MapValue<>(value, timestampProvider.apply(key, value)); |
342 | + // Before mutating local map, ensure the update can be serialized without errors. | ||
343 | + // This prevents replica divergence due to serialization failures. | ||
344 | + UpdateEntry<K, V> update = serializer.copy(new UpdateEntry<K, V>(key, newValue)); | ||
342 | if (putInternal(key, newValue)) { | 345 | if (putInternal(key, newValue)) { |
343 | - notifyPeers(new UpdateEntry<>(key, newValue), peerUpdateFunction.apply(key, value)); | 346 | + notifyPeers(update, peerUpdateFunction.apply(key, value)); |
344 | notifyListeners(new EventuallyConsistentMapEvent<>(mapName, PUT, key, value)); | 347 | notifyListeners(new EventuallyConsistentMapEvent<>(mapName, PUT, key, value)); |
345 | } | 348 | } |
346 | } | 349 | } |
... | @@ -417,13 +420,15 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -417,13 +420,15 @@ public class EventuallyConsistentMapImpl<K, V> |
417 | 420 | ||
418 | AtomicBoolean updated = new AtomicBoolean(false); | 421 | AtomicBoolean updated = new AtomicBoolean(false); |
419 | AtomicReference<MapValue<V>> previousValue = new AtomicReference<>(); | 422 | AtomicReference<MapValue<V>> previousValue = new AtomicReference<>(); |
420 | - MapValue<V> computedValue = items.compute(key, (k, mv) -> { | 423 | + MapValue<V> computedValue = items.compute(serializer.copy(key), (k, mv) -> { |
421 | previousValue.set(mv); | 424 | previousValue.set(mv); |
422 | V newRawValue = recomputeFunction.apply(key, mv == null ? null : mv.get()); | 425 | V newRawValue = recomputeFunction.apply(key, mv == null ? null : mv.get()); |
423 | MapValue<V> newValue = new MapValue<>(newRawValue, timestampProvider.apply(key, newRawValue)); | 426 | MapValue<V> newValue = new MapValue<>(newRawValue, timestampProvider.apply(key, newRawValue)); |
424 | if (mv == null || newValue.isNewerThan(mv)) { | 427 | if (mv == null || newValue.isNewerThan(mv)) { |
425 | updated.set(true); | 428 | updated.set(true); |
426 | - return newValue; | 429 | + // We return a copy to ensure updates to peers can be serialized. |
430 | + // This prevents replica divergence due to serialization failures. | ||
431 | + return serializer.copy(newValue); | ||
427 | } else { | 432 | } else { |
428 | return mv; | 433 | return mv; |
429 | } | 434 | } | ... | ... |
... | @@ -78,6 +78,11 @@ public class KryoSerializer implements StoreSerializer { | ... | @@ -78,6 +78,11 @@ public class KryoSerializer implements StoreSerializer { |
78 | } | 78 | } |
79 | 79 | ||
80 | @Override | 80 | @Override |
81 | + public <T> T copy(T object) { | ||
82 | + return decode(encode(object)); | ||
83 | + } | ||
84 | + | ||
85 | + @Override | ||
81 | public String toString() { | 86 | public String toString() { |
82 | return MoreObjects.toStringHelper(getClass()) | 87 | return MoreObjects.toStringHelper(getClass()) |
83 | .add("serializerPool", serializerPool) | 88 | .add("serializerPool", serializerPool) | ... | ... |
... | @@ -75,4 +75,13 @@ public interface StoreSerializer { | ... | @@ -75,4 +75,13 @@ public interface StoreSerializer { |
75 | * @param <T> decoded type | 75 | * @param <T> decoded type |
76 | */ | 76 | */ |
77 | <T> T decode(final InputStream stream); | 77 | <T> T decode(final InputStream stream); |
78 | + | ||
79 | + /** | ||
80 | + * Returns a copy of the specfied object. | ||
81 | + * | ||
82 | + * @param object object to copy | ||
83 | + * @return a copy of the object | ||
84 | + * @param <T> object type | ||
85 | + */ | ||
86 | + <T> T copy(final T object); | ||
78 | } | 87 | } | ... | ... |
-
Please register or login to post a comment