/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hazelcast.internal.partition.impl; import com.hazelcast.core.MigrationEvent; import com.hazelcast.core.MigrationListener; import com.hazelcast.instance.MemberImpl; import com.hazelcast.instance.Node; import com.hazelcast.internal.cluster.impl.ClusterServiceImpl; import com.hazelcast.internal.partition.MigrationInfo; import com.hazelcast.logging.ILogger; import com.hazelcast.partition.PartitionLostEvent; import com.hazelcast.partition.PartitionLostListener; import com.hazelcast.spi.EventRegistration; import com.hazelcast.spi.EventService; import com.hazelcast.spi.PartitionAwareService; import com.hazelcast.spi.impl.NodeEngineImpl; import com.hazelcast.spi.partition.IPartitionLostEvent; import java.util.Collection; import static com.hazelcast.internal.partition.InternalPartitionService.MIGRATION_EVENT_TOPIC; import static com.hazelcast.internal.partition.InternalPartitionService.PARTITION_LOST_EVENT_TOPIC; import static com.hazelcast.spi.ExecutionService.SYSTEM_EXECUTOR; import static com.hazelcast.spi.partition.IPartitionService.SERVICE_NAME; /** * Maintains registration of partition-system related listeners and dispatches corresponding events. */ public class PartitionEventManager { private final Node node; private final NodeEngineImpl nodeEngine; public PartitionEventManager(Node node) { this.node = node; this.nodeEngine = node.nodeEngine; } /** Sends a {@link MigrationEvent} to the registered event listeners. */ void sendMigrationEvent(final MigrationInfo migrationInfo, final MigrationEvent.MigrationStatus status) { if (migrationInfo.getSourceCurrentReplicaIndex() != 0 && migrationInfo.getDestinationNewReplicaIndex() != 0) { // only fire events for 0th replica migrations return; } ClusterServiceImpl clusterService = node.getClusterService(); MemberImpl current = clusterService.getMember(migrationInfo.getSource()); MemberImpl newOwner = clusterService.getMember(migrationInfo.getDestination()); MigrationEvent event = new MigrationEvent(migrationInfo.getPartitionId(), current, newOwner, status); EventService eventService = nodeEngine.getEventService(); Collection<EventRegistration> registrations = eventService.getRegistrations(SERVICE_NAME, MIGRATION_EVENT_TOPIC); eventService.publishEvent(SERVICE_NAME, registrations, event, event.getPartitionId()); } public String addMigrationListener(MigrationListener listener) { if (listener == null) { throw new NullPointerException("listener can't be null"); } final MigrationListenerAdapter adapter = new MigrationListenerAdapter(listener); EventService eventService = nodeEngine.getEventService(); EventRegistration registration = eventService.registerListener(SERVICE_NAME, MIGRATION_EVENT_TOPIC, adapter); return registration.getId(); } public boolean removeMigrationListener(String registrationId) { if (registrationId == null) { throw new NullPointerException("registrationId can't be null"); } EventService eventService = nodeEngine.getEventService(); return eventService.deregisterListener(SERVICE_NAME, MIGRATION_EVENT_TOPIC, registrationId); } public String addPartitionLostListener(PartitionLostListener listener) { if (listener == null) { throw new NullPointerException("listener can't be null"); } final PartitionLostListenerAdapter adapter = new PartitionLostListenerAdapter(listener); EventService eventService = nodeEngine.getEventService(); EventRegistration registration = eventService.registerListener(SERVICE_NAME, PARTITION_LOST_EVENT_TOPIC, adapter); return registration.getId(); } public String addLocalPartitionLostListener(PartitionLostListener listener) { if (listener == null) { throw new NullPointerException("listener can't be null"); } final PartitionLostListenerAdapter adapter = new PartitionLostListenerAdapter(listener); EventService eventService = nodeEngine.getEventService(); EventRegistration registration = eventService.registerLocalListener(SERVICE_NAME, PARTITION_LOST_EVENT_TOPIC, adapter); return registration.getId(); } public boolean removePartitionLostListener(String registrationId) { if (registrationId == null) { throw new NullPointerException("registrationId can't be null"); } EventService eventService = nodeEngine.getEventService(); return eventService.deregisterListener(SERVICE_NAME, PARTITION_LOST_EVENT_TOPIC, registrationId); } public void onPartitionLost(IPartitionLostEvent event) { final PartitionLostEvent partitionLostEvent = new PartitionLostEvent(event.getPartitionId(), event.getLostReplicaIndex(), event.getEventSource()); final EventService eventService = nodeEngine.getEventService(); final Collection<EventRegistration> registrations = eventService .getRegistrations(SERVICE_NAME, PARTITION_LOST_EVENT_TOPIC); eventService.publishEvent(SERVICE_NAME, registrations, partitionLostEvent, event.getPartitionId()); } public void sendPartitionLostEvent(int partitionId, int lostReplicaIndex) { final IPartitionLostEvent event = new IPartitionLostEvent(partitionId, lostReplicaIndex, nodeEngine.getThisAddress()); final InternalPartitionLostEventPublisher publisher = new InternalPartitionLostEventPublisher(nodeEngine, event); nodeEngine.getExecutionService().execute(SYSTEM_EXECUTOR, publisher); } /** Task which notifies all {@link PartitionAwareService}s that replicas have been lost. */ private static class InternalPartitionLostEventPublisher implements Runnable { private final NodeEngineImpl nodeEngine; private final IPartitionLostEvent event; InternalPartitionLostEventPublisher(NodeEngineImpl nodeEngine, IPartitionLostEvent event) { this.nodeEngine = nodeEngine; this.event = event; } @Override public void run() { for (PartitionAwareService service : nodeEngine.getServices(PartitionAwareService.class)) { try { service.onPartitionLost(event); } catch (Exception e) { final ILogger logger = nodeEngine.getLogger(InternalPartitionLostEventPublisher.class); logger.warning("Handling partitionLostEvent failed. Service: " + service.getClass() + " Event: " + event, e); } } } public IPartitionLostEvent getEvent() { return event; } } }