private AntiEntropyResponse handleAntiEntropyAdvertisement(AntiEntropyAdvertisement<K> ad) { if (destroyed || underHighLoad()) { return AntiEntropyResponse.IGNORED; } try { if (log.isTraceEnabled()) { log.trace( "Received anti-entropy advertisement from {} for {} with {} entries in it", ad.sender(), mapName, ad.digest().size()); } antiEntropyCheckLocalItems(ad).forEach(this::notifyListeners); } catch (Exception e) { log.warn("Error handling anti-entropy advertisement", e); return AntiEntropyResponse.FAILED; } return AntiEntropyResponse.PROCESSED; }
/** * 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 != null && 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; }