mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-27 14:21:48 +01:00
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:
parent
6a8fd1de53
commit
00c3f57d35
@ -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,23 +569,21 @@ 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);
|
||||||
|
|
||||||
externalEvents.addAll(antiEntropyCheckRemoteRemoved(ad));
|
externalEvents.addAll(antiEntropyCheckRemoteRemoved(ad));
|
||||||
|
|
||||||
// if remote ad has something unknown, actively sync
|
// if remote ad has something unknown, actively sync
|
||||||
for (K key : ad.timestamps().keySet()) {
|
for (K key : ad.timestamps().keySet()) {
|
||||||
if (!items.containsKey(key)) {
|
if (!items.containsKey(key)) {
|
||||||
sync = true;
|
sync = true;
|
||||||
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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user