use of org.infinispan.notifications.cachelistener.annotation.TopologyChanged in project wildfly by wildfly.
the class CacheRegistry method topologyChanged.
@TopologyChanged
public void topologyChanged(TopologyChangedEvent<Node, Map.Entry<K, V>> event) {
if (event.isPre())
return;
ConsistentHash previousHash = event.getConsistentHashAtStart();
List<Address> previousMembers = previousHash.getMembers();
ConsistentHash hash = event.getConsistentHashAtEnd();
List<Address> members = hash.getMembers();
Address localAddress = event.getCache().getCacheManager().getAddress();
// Determine which nodes have left the cache view
Set<Address> addresses = new HashSet<>(previousMembers);
addresses.removeAll(members);
try {
this.topologyChangeExecutor.submit(() -> {
if (!addresses.isEmpty()) {
// We're only interested in the entries for which we are the primary owner
List<Node> nodes = addresses.stream().filter(address -> hash.locatePrimaryOwner(address).equals(localAddress)).map(address -> this.factory.createNode(address)).collect(Collectors.toList());
if (!nodes.isEmpty()) {
Cache<Node, Map.Entry<K, V>> cache = this.cache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS);
Map<K, V> removed = new HashMap<>();
try (Batch batch = this.batcher.createBatch()) {
for (Node node : nodes) {
Map.Entry<K, V> old = cache.remove(node);
if (old != null) {
removed.put(old.getKey(), old.getValue());
}
}
} catch (CacheException e) {
ClusteringServerLogger.ROOT_LOGGER.registryPurgeFailed(e, this.cache.getCacheManager().toString(), this.cache.getName(), nodes);
}
// Invoke listeners outside above tx context
if (!removed.isEmpty()) {
this.notifyListeners(Event.Type.CACHE_ENTRY_REMOVED, removed);
}
}
} else {
// This is a merge after cluster split: re-populate the cache registry with lost registry entries
if (!previousMembers.contains(localAddress)) {
// If this node is not a member at merge start, its mapping is lost and needs to be recreated and listeners notified
try {
this.populateRegistry();
// Local cache events do not trigger notifications
this.notifyListeners(Event.Type.CACHE_ENTRY_CREATED, this.entry);
} catch (CacheException e) {
ClusteringServerLogger.ROOT_LOGGER.failedToRestoreLocalRegistryEntry(e, this.cache.getCacheManager().toString(), this.cache.getName());
}
}
}
});
} catch (RejectedExecutionException e) {
// Executor was shutdown
}
}
use of org.infinispan.notifications.cachelistener.annotation.TopologyChanged in project wildfly by wildfly.
the class SchedulerTopologyChangeListener method topologyChanged.
@TopologyChanged
public CompletionStage<Void> topologyChanged(TopologyChangedEvent<K, V> event) {
Cache<K, V> cache = event.getCache();
Address address = cache.getCacheManager().getAddress();
ConsistentHash oldHash = event.getWriteConsistentHashAtStart();
Set<Integer> oldSegments = oldHash.getMembers().contains(address) ? oldHash.getPrimarySegmentsForOwner(address) : Collections.emptySet();
ConsistentHash newHash = event.getWriteConsistentHashAtEnd();
Set<Integer> newSegments = newHash.getMembers().contains(address) ? newHash.getPrimarySegmentsForOwner(address) : Collections.emptySet();
if (event.isPre()) {
// If there are segments that we no longer own, then run cancellation task
if (!newSegments.containsAll(oldSegments)) {
Future<?> future = this.scheduleTaskFuture.getAndSet(null);
if (future != null) {
future.cancel(true);
}
return CompletableFuture.runAsync(() -> this.cancelTask.accept(new ConsistentHashLocality(cache, newHash)), this.executor);
}
} else {
// If we have newly owned segments, then run schedule task
if (!oldSegments.containsAll(newSegments)) {
Locality oldLocality = new ConsistentHashLocality(cache, oldHash);
Locality newLocality = new ConsistentHashLocality(cache, newHash);
try {
Future<?> future = this.scheduleTaskFuture.getAndSet(this.executor.submit(() -> this.scheduleTask.accept(oldLocality, newLocality)));
if (future != null) {
future.cancel(true);
}
} catch (RejectedExecutionException e) {
// Executor was shutdown
}
}
}
return CompletableFutures.completedNull();
}
use of org.infinispan.notifications.cachelistener.annotation.TopologyChanged in project wildfly by wildfly.
the class CacheServiceProviderRegistry method topologyChanged.
@TopologyChanged
public void topologyChanged(TopologyChangedEvent<T, Set<Address>> event) {
if (!event.isPre()) {
ConsistentHash previousHash = event.getWriteConsistentHashAtStart();
List<Address> previousMembers = previousHash.getMembers();
ConsistentHash hash = event.getWriteConsistentHashAtEnd();
List<Address> members = hash.getMembers();
if (!members.equals(previousMembers)) {
Cache<T, Set<Address>> cache = event.getCache().getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS);
Address localAddress = cache.getCacheManager().getAddress();
// Determine which nodes have left the cache view
Set<Address> leftMembers = new HashSet<>(previousMembers);
leftMembers.removeAll(members);
if (!leftMembers.isEmpty()) {
Locality locality = new ConsistentHashLocality(cache, hash);
// We're only interested in the entries for which we are the primary owner
Iterator<Address> addresses = leftMembers.iterator();
while (addresses.hasNext()) {
if (!locality.isLocal(addresses.next())) {
addresses.remove();
}
}
}
// If this is a merge after cluster split: Re-assert services for local member
Set<T> localServices = !previousMembers.contains(localAddress) ? this.listeners.keySet() : Collections.emptySet();
if (!leftMembers.isEmpty() || !localServices.isEmpty()) {
Batcher<? extends Batch> batcher = this.batcher;
Invoker invoker = this.invoker;
try {
this.topologyChangeExecutor.submit(new Runnable() {
@Override
public void run() {
if (!leftMembers.isEmpty()) {
try (Batch batch = batcher.createBatch()) {
try (CloseableIterator<Map.Entry<T, Set<Address>>> entries = cache.getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK).entrySet().iterator()) {
while (entries.hasNext()) {
Map.Entry<T, Set<Address>> entry = entries.next();
Set<Address> addresses = entry.getValue();
if (addresses.removeAll(leftMembers)) {
entry.setValue(addresses);
}
}
}
}
}
if (!localServices.isEmpty()) {
for (T localService : localServices) {
invoker.invoke(new RegisterLocalServiceTask(localService));
}
}
}
});
} catch (RejectedExecutionException e) {
// Executor is shutdown
}
}
}
}
}
use of org.infinispan.notifications.cachelistener.annotation.TopologyChanged in project wildfly by wildfly.
the class CacheRegistry method topologyChanged.
@TopologyChanged
public CompletionStage<Void> topologyChanged(TopologyChangedEvent<Address, Map.Entry<K, V>> event) {
if (!event.isPre()) {
ConsistentHash previousHash = event.getWriteConsistentHashAtStart();
List<Address> previousMembers = previousHash.getMembers();
ConsistentHash hash = event.getWriteConsistentHashAtEnd();
List<Address> members = hash.getMembers();
if (!members.equals(previousMembers)) {
Cache<Address, Map.Entry<K, V>> cache = event.getCache().getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS);
Address localAddress = cache.getCacheManager().getAddress();
// Determine which nodes have left the cache view
Set<Address> leftMembers = new HashSet<>(previousMembers);
leftMembers.removeAll(members);
if (!leftMembers.isEmpty()) {
Locality locality = new ConsistentHashLocality(cache, hash);
// We're only interested in the entries for which we are the primary owner
Iterator<Address> addresses = leftMembers.iterator();
while (addresses.hasNext()) {
if (!locality.isLocal(addresses.next())) {
addresses.remove();
}
}
}
// If this is a merge after cluster split: re-populate the cache registry with lost registry entries
boolean restoreLocalEntry = !previousMembers.contains(localAddress);
if (!leftMembers.isEmpty() || restoreLocalEntry) {
try {
this.topologyChangeExecutor.submit(() -> {
if (!leftMembers.isEmpty()) {
Map<K, V> removed = new HashMap<>();
try {
for (Address leftMember : leftMembers) {
Map.Entry<K, V> old = cache.remove(leftMember);
if (old != null) {
removed.put(old.getKey(), old.getValue());
}
}
} catch (CacheException e) {
ClusteringServerLogger.ROOT_LOGGER.registryPurgeFailed(e, this.cache.getCacheManager().toString(), this.cache.getName(), leftMembers);
}
if (!removed.isEmpty()) {
this.notifyListeners(Event.Type.CACHE_ENTRY_REMOVED, removed);
}
}
if (restoreLocalEntry) {
// If this node is not a member at merge start, its mapping may have been lost and need to be recreated
try {
if (cache.put(localAddress, this.entry) == null) {
// Local cache events do not trigger notifications
this.notifyListeners(Event.Type.CACHE_ENTRY_CREATED, this.entry);
}
} catch (CacheException e) {
ClusteringServerLogger.ROOT_LOGGER.failedToRestoreLocalRegistryEntry(e, this.cache.getCacheManager().toString(), this.cache.getName());
}
}
});
} catch (RejectedExecutionException e) {
// Executor was shutdown
}
}
}
}
return CompletableFutures.completedNull();
}
use of org.infinispan.notifications.cachelistener.annotation.TopologyChanged in project wildfly by wildfly.
the class CacheGroup method topologyChanged.
@TopologyChanged
public CompletionStage<Void> topologyChanged(TopologyChangedEvent<?, ?> event) {
if (!event.isPre()) {
int viewId = event.getCache().getAdvancedCache().getRpcManager().getTransport().getViewId();
Address localAddress = event.getCache().getCacheManager().getAddress();
Membership previousMembership = new CacheMembership(localAddress, event.getWriteConsistentHashAtStart(), this);
Membership membership = new CacheMembership(localAddress, event.getWriteConsistentHashAtEnd(), this);
Boolean status = this.views.get(viewId);
boolean merged = (status != null) ? status : false;
for (Map.Entry<GroupListener, ExecutorService> entry : this.listeners.entrySet()) {
GroupListener listener = entry.getKey();
ExecutorService executor = entry.getValue();
Runnable listenerTask = new Runnable() {
@Override
public void run() {
try {
listener.membershipChanged(previousMembership, membership, merged);
} catch (Throwable e) {
ClusteringServerLogger.ROOT_LOGGER.warn(e.getLocalizedMessage(), e);
}
}
};
try {
executor.submit(listenerTask);
} catch (RejectedExecutionException e) {
// Listener was unregistered
}
}
// Purge obsolete views
this.views.headMap(viewId).clear();
}
return CompletableFutures.completedNull();
}
Aggregations