use of org.onosproject.store.service.EventuallyConsistentMapEvent in project onos by opennetworkinglab.
the class EventuallyConsistentMapImpl method antiEntropyCheckLocalItems.
/**
* Processes anti-entropy ad from peer by taking following actions:
* 1. If peer has an old entry, updates peer.
* 2. If peer indicates an entry is removed and has a more recent
* timestamp than the local entry, update local state.
*/
private List<EventuallyConsistentMapEvent<K, V>> antiEntropyCheckLocalItems(AntiEntropyAdvertisement<K> ad) {
final List<EventuallyConsistentMapEvent<K, V>> externalEvents = Lists.newLinkedList();
final NodeId sender = ad.sender();
final List<NodeId> peers = ImmutableList.of(sender);
Set<K> staleOrMissing = new HashSet<>();
Set<K> locallyUnknown = new HashSet<>(ad.digest().keySet());
items.forEach((key, localValue) -> {
locallyUnknown.remove(key);
MapValue.Digest remoteValueDigest = ad.digest().get(key);
if (remoteValueDigest == null || localValue.isNewerThan(remoteValueDigest.timestamp())) {
// local value is more recent, push to sender
queueUpdate(new UpdateEntry<>(key, localValue), peers);
} else if (remoteValueDigest.isNewerThan(localValue.digest()) && remoteValueDigest.isTombstone()) {
// remote value is more recent and a tombstone: update local value
MapValue<V> tombstone = MapValue.tombstone(remoteValueDigest.timestamp());
MapValue<V> previousValue = removeInternal(key, Optional.empty(), Optional.of(tombstone));
if (previousValue != null && previousValue.isAlive()) {
externalEvents.add(new EventuallyConsistentMapEvent<>(mapName, REMOVE, key, previousValue.get()));
}
} else if (remoteValueDigest.isNewerThan(localValue.digest())) {
// Not a tombstone and remote is newer
staleOrMissing.add(key);
}
});
// Keys missing in local map
staleOrMissing.addAll(locallyUnknown);
// Request updates that we missed out on
sendUpdateRequestToPeer(sender, staleOrMissing);
return externalEvents;
}
use of org.onosproject.store.service.EventuallyConsistentMapEvent in project onos by opennetworkinglab.
the class EventuallyConsistentMapImpl method compute.
@Override
public V compute(K key, BiFunction<K, V, V> recomputeFunction) {
checkState(!destroyed, destroyedMessage);
checkNotNull(key, ERROR_NULL_KEY);
checkNotNull(recomputeFunction, "Recompute function cannot be null");
AtomicBoolean updated = new AtomicBoolean(false);
AtomicReference<MapValue<V>> previousValue = new AtomicReference<>();
MapValue<V> computedValue = items.compute(serializer.copy(key), (k, mv) -> {
previousValue.set(mv);
V newRawValue = recomputeFunction.apply(key, mv == null ? null : mv.get());
if (mv != null && Objects.equals(newRawValue, mv.get())) {
// value was not updated
return mv;
}
MapValue<V> newValue = new MapValue<>(newRawValue, timestampProvider.apply(key, newRawValue));
if (mv == null || newValue.isNewerThan(mv)) {
updated.set(true);
// This prevents replica divergence due to serialization failures.
return serializer.copy(newValue);
} else {
return mv;
}
});
if (updated.get()) {
notifyPeers(new UpdateEntry<>(key, computedValue), peerUpdateFunction.apply(key, computedValue.get()));
EventuallyConsistentMapEvent.Type updateType = computedValue.isTombstone() ? REMOVE : PUT;
V value = computedValue.isTombstone() ? previousValue.get() == null ? null : previousValue.get().get() : computedValue.get();
if (value != null) {
notifyListeners(new EventuallyConsistentMapEvent<>(mapName, updateType, key, value));
}
}
return computedValue.get();
}
Aggregations