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
This commit is contained in:
HIGUCHI Yuta 2015-02-25 07:33:50 -08:00 committed by Gerrit Code Review
parent 6a8fd1de53
commit 00c3f57d35

View File

@ -16,6 +16,7 @@
package org.onosproject.store.ecmap; package org.onosproject.store.ecmap;
import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.onlab.util.KryoNamespace; import org.onlab.util.KryoNamespace;
import org.onosproject.cluster.ClusterService; import org.onosproject.cluster.ClusterService;
@ -42,6 +43,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -64,8 +66,8 @@ public class EventuallyConsistentMapImpl<K, V>
private static final Logger log = LoggerFactory.getLogger(EventuallyConsistentMapImpl.class); private static final Logger log = LoggerFactory.getLogger(EventuallyConsistentMapImpl.class);
private final Map<K, Timestamped<V>> items; private final ConcurrentMap<K, Timestamped<V>> items;
private final Map<K, Timestamp> removedItems; private final ConcurrentMap<K, Timestamp> removedItems;
private final ClusterService clusterService; private final ClusterService clusterService;
private final ClusterCommunicationService clusterCommunicator; private final ClusterCommunicationService clusterCommunicator;
@ -267,16 +269,21 @@ public class EventuallyConsistentMapImpl<K, V>
return false; return false;
} }
boolean success; final MutableBoolean updated = new MutableBoolean(false);
synchronized (this) {
Timestamped<V> existing = items.get(key); items.compute(key, (k, existing) -> {
if (existing != null && existing.isNewerThan(timestamp)) { if (existing != null && existing.isNewerThan(timestamp)) {
log.debug("ecmap - existing was newer {}", value); updated.setFalse();
success = false; return existing;
} else { } else {
items.put(key, new Timestamped<>(value, timestamp)); updated.setTrue();
success = true; return new Timestamped<>(value, timestamp);
} }
});
boolean success = updated.booleanValue();
if (!success) {
log.debug("ecmap - existing was newer {}", value);
} }
if (success && removed != null) { if (success && removed != null) {
@ -303,13 +310,21 @@ public class EventuallyConsistentMapImpl<K, V>
} }
private boolean removeInternal(K key, Timestamp timestamp) { private boolean removeInternal(K key, Timestamp timestamp) {
Timestamped<V> value = items.get(key); final MutableBoolean updated = new MutableBoolean(false);
if (value != null) {
if (value.isNewerThan(timestamp)) { items.compute(key, (k, existing) -> {
return false; if (existing != null && existing.isNewerThan(timestamp)) {
updated.setFalse();
return existing;
} else { } else {
items.remove(key, value); updated.setTrue();
// remove from items map
return null;
} }
});
if (updated.isFalse()) {
return false;
} }
Timestamp removedTimestamp = removedItems.get(key); Timestamp removedTimestamp = removedItems.get(key);
@ -554,7 +569,6 @@ public class EventuallyConsistentMapImpl<K, V>
List<EventuallyConsistentMapEvent<K, V>> externalEvents; List<EventuallyConsistentMapEvent<K, V>> externalEvents;
boolean sync = false; boolean sync = false;
synchronized (this) {
externalEvents = antiEntropyCheckLocalItems(ad); externalEvents = antiEntropyCheckLocalItems(ad);
antiEntropyCheckLocalRemoved(ad); antiEntropyCheckLocalRemoved(ad);
@ -568,9 +582,8 @@ public class EventuallyConsistentMapImpl<K, V>
break; break;
} }
} }
} // synchronized (this)
// Send the advertisement outside the synchronized block // Send the advertisement back if this peer is out-of-sync
if (sync) { if (sync) {
final NodeId sender = ad.sender(); final NodeId sender = ad.sender();
AntiEntropyAdvertisement<K> myAd = createAdvertisement(); AntiEntropyAdvertisement<K> myAd = createAdvertisement();
@ -596,7 +609,6 @@ public class EventuallyConsistentMapImpl<K, V>
* @param ad remote anti-entropy advertisement * @param ad remote anti-entropy advertisement
* @return list of external events relating to local operations performed * @return list of external events relating to local operations performed
*/ */
// Guarded by synchronized (this)
private List<EventuallyConsistentMapEvent<K, V>> antiEntropyCheckLocalItems( private List<EventuallyConsistentMapEvent<K, V>> antiEntropyCheckLocalItems(
AntiEntropyAdvertisement<K> ad) { AntiEntropyAdvertisement<K> ad) {
final List<EventuallyConsistentMapEvent<K, V>> externalEvents final List<EventuallyConsistentMapEvent<K, V>> externalEvents
@ -652,7 +664,6 @@ public class EventuallyConsistentMapImpl<K, V>
* *
* @param ad remote anti-entropy advertisement * @param ad remote anti-entropy advertisement
*/ */
// Guarded by synchronized (this)
private void antiEntropyCheckLocalRemoved(AntiEntropyAdvertisement<K> ad) { private void antiEntropyCheckLocalRemoved(AntiEntropyAdvertisement<K> ad) {
final NodeId sender = ad.sender(); final NodeId sender = ad.sender();
@ -690,7 +701,6 @@ public class EventuallyConsistentMapImpl<K, V>
* @param ad remote anti-entropy advertisement * @param ad remote anti-entropy advertisement
* @return list of external events relating to local operations performed * @return list of external events relating to local operations performed
*/ */
// Guarded by synchronized (this)
private List<EventuallyConsistentMapEvent<K, V>> private List<EventuallyConsistentMapEvent<K, V>>
antiEntropyCheckRemoteRemoved(AntiEntropyAdvertisement<K> ad) { antiEntropyCheckRemoteRemoved(AntiEntropyAdvertisement<K> ad) {
final List<EventuallyConsistentMapEvent<K, V>> externalEvents final List<EventuallyConsistentMapEvent<K, V>> externalEvents