Committed by
Gerrit Code Review
Concurrently update EventuallyConsistentMap
- Removed synchronized block on Map updates which may result in anti-entropy AD sent to the peer containing out-of-sync update/remove, such as update and remove for the same key, but stale information will be ignored on the remote peer by timestamp if timestamps are properly generated. Change-Id: Id4f993eb44b7858d37486be0d4baaff1f9025efa
Showing
1 changed file
with
39 additions
and
29 deletions
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | package org.onosproject.store.ecmap; | 16 | package org.onosproject.store.ecmap; |
| 17 | 17 | ||
| 18 | import org.apache.commons.lang3.RandomUtils; | 18 | import org.apache.commons.lang3.RandomUtils; |
| 19 | +import org.apache.commons.lang3.mutable.MutableBoolean; | ||
| 19 | import org.apache.commons.lang3.tuple.Pair; | 20 | import org.apache.commons.lang3.tuple.Pair; |
| 20 | import org.onlab.util.KryoNamespace; | 21 | import org.onlab.util.KryoNamespace; |
| 21 | import org.onosproject.cluster.ClusterService; | 22 | import org.onosproject.cluster.ClusterService; |
| ... | @@ -42,6 +43,7 @@ import java.util.List; | ... | @@ -42,6 +43,7 @@ import java.util.List; |
| 42 | import java.util.Map; | 43 | import java.util.Map; |
| 43 | import java.util.Set; | 44 | import java.util.Set; |
| 44 | import java.util.concurrent.ConcurrentHashMap; | 45 | import java.util.concurrent.ConcurrentHashMap; |
| 46 | +import java.util.concurrent.ConcurrentMap; | ||
| 45 | import java.util.concurrent.CopyOnWriteArraySet; | 47 | import java.util.concurrent.CopyOnWriteArraySet; |
| 46 | import java.util.concurrent.ExecutorService; | 48 | import java.util.concurrent.ExecutorService; |
| 47 | import java.util.concurrent.Executors; | 49 | import java.util.concurrent.Executors; |
| ... | @@ -64,8 +66,8 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -64,8 +66,8 @@ public class EventuallyConsistentMapImpl<K, V> |
| 64 | 66 | ||
| 65 | private static final Logger log = LoggerFactory.getLogger(EventuallyConsistentMapImpl.class); | 67 | private static final Logger log = LoggerFactory.getLogger(EventuallyConsistentMapImpl.class); |
| 66 | 68 | ||
| 67 | - private final Map<K, Timestamped<V>> items; | 69 | + private final ConcurrentMap<K, Timestamped<V>> items; |
| 68 | - private final Map<K, Timestamp> removedItems; | 70 | + private final ConcurrentMap<K, Timestamp> removedItems; |
| 69 | 71 | ||
| 70 | private final ClusterService clusterService; | 72 | private final ClusterService clusterService; |
| 71 | private final ClusterCommunicationService clusterCommunicator; | 73 | private final ClusterCommunicationService clusterCommunicator; |
| ... | @@ -267,16 +269,21 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -267,16 +269,21 @@ public class EventuallyConsistentMapImpl<K, V> |
| 267 | return false; | 269 | return false; |
| 268 | } | 270 | } |
| 269 | 271 | ||
| 270 | - boolean success; | 272 | + final MutableBoolean updated = new MutableBoolean(false); |
| 271 | - synchronized (this) { | 273 | + |
| 272 | - Timestamped<V> existing = items.get(key); | 274 | + items.compute(key, (k, existing) -> { |
| 273 | if (existing != null && existing.isNewerThan(timestamp)) { | 275 | if (existing != null && existing.isNewerThan(timestamp)) { |
| 274 | - log.debug("ecmap - existing was newer {}", value); | 276 | + updated.setFalse(); |
| 275 | - success = false; | 277 | + return existing; |
| 276 | } else { | 278 | } else { |
| 277 | - items.put(key, new Timestamped<>(value, timestamp)); | 279 | + updated.setTrue(); |
| 278 | - success = true; | 280 | + return new Timestamped<>(value, timestamp); |
| 279 | } | 281 | } |
| 282 | + }); | ||
| 283 | + | ||
| 284 | + boolean success = updated.booleanValue(); | ||
| 285 | + if (!success) { | ||
| 286 | + log.debug("ecmap - existing was newer {}", value); | ||
| 280 | } | 287 | } |
| 281 | 288 | ||
| 282 | if (success && removed != null) { | 289 | if (success && removed != null) { |
| ... | @@ -303,13 +310,21 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -303,13 +310,21 @@ public class EventuallyConsistentMapImpl<K, V> |
| 303 | } | 310 | } |
| 304 | 311 | ||
| 305 | private boolean removeInternal(K key, Timestamp timestamp) { | 312 | private boolean removeInternal(K key, Timestamp timestamp) { |
| 306 | - Timestamped<V> value = items.get(key); | 313 | + final MutableBoolean updated = new MutableBoolean(false); |
| 307 | - if (value != null) { | 314 | + |
| 308 | - if (value.isNewerThan(timestamp)) { | 315 | + items.compute(key, (k, existing) -> { |
| 309 | - return false; | 316 | + if (existing != null && existing.isNewerThan(timestamp)) { |
| 317 | + updated.setFalse(); | ||
| 318 | + return existing; | ||
| 310 | } else { | 319 | } else { |
| 311 | - items.remove(key, value); | 320 | + updated.setTrue(); |
| 321 | + // remove from items map | ||
| 322 | + return null; | ||
| 312 | } | 323 | } |
| 324 | + }); | ||
| 325 | + | ||
| 326 | + if (updated.isFalse()) { | ||
| 327 | + return false; | ||
| 313 | } | 328 | } |
| 314 | 329 | ||
| 315 | Timestamp removedTimestamp = removedItems.get(key); | 330 | Timestamp removedTimestamp = removedItems.get(key); |
| ... | @@ -554,23 +569,21 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -554,23 +569,21 @@ public class EventuallyConsistentMapImpl<K, V> |
| 554 | List<EventuallyConsistentMapEvent<K, V>> externalEvents; | 569 | List<EventuallyConsistentMapEvent<K, V>> externalEvents; |
| 555 | boolean sync = false; | 570 | boolean sync = false; |
| 556 | 571 | ||
| 557 | - synchronized (this) { | 572 | + externalEvents = antiEntropyCheckLocalItems(ad); |
| 558 | - externalEvents = antiEntropyCheckLocalItems(ad); | ||
| 559 | 573 | ||
| 560 | - antiEntropyCheckLocalRemoved(ad); | 574 | + antiEntropyCheckLocalRemoved(ad); |
| 561 | 575 | ||
| 562 | - externalEvents.addAll(antiEntropyCheckRemoteRemoved(ad)); | 576 | + externalEvents.addAll(antiEntropyCheckRemoteRemoved(ad)); |
| 563 | 577 | ||
| 564 | - // if remote ad has something unknown, actively sync | 578 | + // if remote ad has something unknown, actively sync |
| 565 | - for (K key : ad.timestamps().keySet()) { | 579 | + for (K key : ad.timestamps().keySet()) { |
| 566 | - if (!items.containsKey(key)) { | 580 | + if (!items.containsKey(key)) { |
| 567 | - sync = true; | 581 | + sync = true; |
| 568 | - break; | 582 | + break; |
| 569 | - } | ||
| 570 | } | 583 | } |
| 571 | - } // synchronized (this) | 584 | + } |
| 572 | 585 | ||
| 573 | - // Send the advertisement outside the synchronized block | 586 | + // Send the advertisement back if this peer is out-of-sync |
| 574 | if (sync) { | 587 | if (sync) { |
| 575 | final NodeId sender = ad.sender(); | 588 | final NodeId sender = ad.sender(); |
| 576 | AntiEntropyAdvertisement<K> myAd = createAdvertisement(); | 589 | AntiEntropyAdvertisement<K> myAd = createAdvertisement(); |
| ... | @@ -596,7 +609,6 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -596,7 +609,6 @@ public class EventuallyConsistentMapImpl<K, V> |
| 596 | * @param ad remote anti-entropy advertisement | 609 | * @param ad remote anti-entropy advertisement |
| 597 | * @return list of external events relating to local operations performed | 610 | * @return list of external events relating to local operations performed |
| 598 | */ | 611 | */ |
| 599 | - // Guarded by synchronized (this) | ||
| 600 | private List<EventuallyConsistentMapEvent<K, V>> antiEntropyCheckLocalItems( | 612 | private List<EventuallyConsistentMapEvent<K, V>> antiEntropyCheckLocalItems( |
| 601 | AntiEntropyAdvertisement<K> ad) { | 613 | AntiEntropyAdvertisement<K> ad) { |
| 602 | final List<EventuallyConsistentMapEvent<K, V>> externalEvents | 614 | final List<EventuallyConsistentMapEvent<K, V>> externalEvents |
| ... | @@ -652,7 +664,6 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -652,7 +664,6 @@ public class EventuallyConsistentMapImpl<K, V> |
| 652 | * | 664 | * |
| 653 | * @param ad remote anti-entropy advertisement | 665 | * @param ad remote anti-entropy advertisement |
| 654 | */ | 666 | */ |
| 655 | - // Guarded by synchronized (this) | ||
| 656 | private void antiEntropyCheckLocalRemoved(AntiEntropyAdvertisement<K> ad) { | 667 | private void antiEntropyCheckLocalRemoved(AntiEntropyAdvertisement<K> ad) { |
| 657 | final NodeId sender = ad.sender(); | 668 | final NodeId sender = ad.sender(); |
| 658 | 669 | ||
| ... | @@ -690,7 +701,6 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -690,7 +701,6 @@ public class EventuallyConsistentMapImpl<K, V> |
| 690 | * @param ad remote anti-entropy advertisement | 701 | * @param ad remote anti-entropy advertisement |
| 691 | * @return list of external events relating to local operations performed | 702 | * @return list of external events relating to local operations performed |
| 692 | */ | 703 | */ |
| 693 | - // Guarded by synchronized (this) | ||
| 694 | private List<EventuallyConsistentMapEvent<K, V>> | 704 | private List<EventuallyConsistentMapEvent<K, V>> |
| 695 | antiEntropyCheckRemoteRemoved(AntiEntropyAdvertisement<K> ad) { | 705 | antiEntropyCheckRemoteRemoved(AntiEntropyAdvertisement<K> ad) { |
| 696 | final List<EventuallyConsistentMapEvent<K, V>> externalEvents | 706 | final List<EventuallyConsistentMapEvent<K, V>> externalEvents | ... | ... |
-
Please register or login to post a comment