All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.cluster.impl.ClusterServiceImpl Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2008-2015, 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.cluster.impl;

import com.hazelcast.cluster.ClusterService;
import com.hazelcast.cluster.ClusterState;
import com.hazelcast.cluster.MemberAttributeOperationType;
import com.hazelcast.cluster.MemberInfo;
import com.hazelcast.cluster.impl.operations.MemberInfoUpdateOperation;
import com.hazelcast.cluster.impl.operations.MemberRemoveOperation;
import com.hazelcast.cluster.impl.operations.ShutdownNodeOperation;
import com.hazelcast.cluster.impl.operations.TriggerMemberListPublishOperation;
import com.hazelcast.core.InitialMembershipEvent;
import com.hazelcast.core.InitialMembershipListener;
import com.hazelcast.core.Member;
import com.hazelcast.core.MemberAttributeEvent;
import com.hazelcast.core.MemberSelector;
import com.hazelcast.core.MembershipEvent;
import com.hazelcast.core.MembershipListener;
import com.hazelcast.instance.GroupProperty;
import com.hazelcast.instance.HazelcastInstanceImpl;
import com.hazelcast.instance.LifecycleServiceImpl;
import com.hazelcast.instance.MemberImpl;
import com.hazelcast.instance.Node;
import com.hazelcast.internal.metrics.MetricsRegistry;
import com.hazelcast.internal.metrics.Probe;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.Connection;
import com.hazelcast.nio.ConnectionListener;
import com.hazelcast.partition.impl.InternalPartitionServiceImpl;
import com.hazelcast.spi.EventPublishingService;
import com.hazelcast.spi.EventRegistration;
import com.hazelcast.spi.EventService;
import com.hazelcast.spi.ExecutionService;
import com.hazelcast.spi.ManagedService;
import com.hazelcast.spi.MemberAttributeServiceEvent;
import com.hazelcast.spi.MembershipAwareService;
import com.hazelcast.spi.MembershipServiceEvent;
import com.hazelcast.spi.NodeEngine;
import com.hazelcast.spi.Operation;
import com.hazelcast.spi.TransactionalService;
import com.hazelcast.spi.impl.NodeEngineImpl;
import com.hazelcast.transaction.TransactionOptions;
import com.hazelcast.transaction.TransactionalObject;
import com.hazelcast.transaction.impl.Transaction;
import com.hazelcast.util.Clock;
import com.hazelcast.util.executor.ExecutorType;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.hazelcast.cluster.memberselector.MemberSelectors.NON_LOCAL_MEMBER_SELECTOR;
import static com.hazelcast.util.Preconditions.checkNotNull;
import static java.lang.String.format;
import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;

public class ClusterServiceImpl implements ClusterService, ConnectionListener, ManagedService,
        EventPublishingService, TransactionalService {

    public static final String SERVICE_NAME = "hz:core:clusterService";

    static final String EXECUTOR_NAME = "hz:cluster";

    private static final int DEFAULT_MERGE_RUN_DELAY_MILLIS = 100;
    private static final int CLUSTER_EXECUTOR_QUEUE_CAPACITY = 1000;
    private static final long CLUSTER_SHUTDOWN_SLEEP_DURATION_IN_MILLIS = 1000;

    private static final String MEMBERSHIP_EVENT_EXECUTOR_NAME = "hz:cluster:event";

    private final Address thisAddress;

    private final MemberImpl thisMember;

    private final Lock lock = new ReentrantLock();

    private final AtomicReference> membersMapRef
            = new AtomicReference>(Collections.emptyMap());

    private final AtomicReference> membersRef
            = new AtomicReference>(Collections.emptySet());

    private final AtomicReference> membersRemovedInNotActiveStateRef
            = new AtomicReference>(Collections.emptyMap());

    private final Node node;

    private final NodeEngineImpl nodeEngine;

    private final ILogger logger;

    private final ClusterClockImpl clusterClock;

    private final ClusterStateManager clusterStateManager;

    private final ClusterJoinManager clusterJoinManager;

    private final ClusterHeartbeatManager clusterHeartbeatManager;

    private String clusterId;

    public ClusterServiceImpl(Node node) {

        this.node = node;
        nodeEngine = node.nodeEngine;

        logger = node.getLogger(ClusterService.class.getName());
        clusterClock = new ClusterClockImpl(logger);

        thisAddress = node.getThisAddress();
        thisMember = node.getLocalMember();

        clusterStateManager = new ClusterStateManager(node, lock);
        clusterJoinManager = new ClusterJoinManager(node, this, lock);
        clusterHeartbeatManager = new ClusterHeartbeatManager(node, this);

        registerThisMember();

        node.connectionManager.addConnectionListener(this);
        //MEMBERSHIP_EVENT_EXECUTOR is a single threaded executor to ensure that events are executed in correct order.
        nodeEngine.getExecutionService().register(MEMBERSHIP_EVENT_EXECUTOR_NAME, 1, Integer.MAX_VALUE, ExecutorType.CACHED);
        registerMetrics();
    }

    private void registerThisMember() {
        setMembers(thisMember);
        sendMembershipEvents(Collections.emptySet(), Collections.singleton(thisMember));
    }

    private void registerMetrics() {
        MetricsRegistry metricsRegistry = node.nodeEngine.getMetricsRegistry();
        metricsRegistry.scanAndRegister(clusterClock, "cluster.clock");
        metricsRegistry.scanAndRegister(clusterHeartbeatManager, "cluster.heartbeat");
        metricsRegistry.scanAndRegister(this, "cluster");
    }

    @Override
    public ClusterClockImpl getClusterClock() {
        return clusterClock;
    }

    @Override
    public long getClusterTime() {
        return clusterClock.getClusterTime();
    }

    @Override
    public String getClusterId() {
        return clusterId;
    }

    public void setClusterId(String clusterId) {
        if (this.clusterId == null) {
            this.clusterId = clusterId;
        }
    }

    @Override
    public void init(NodeEngine nodeEngine, Properties properties) {
        long mergeFirstRunDelayMs = node.groupProperties.getMillis(GroupProperty.MERGE_FIRST_RUN_DELAY_SECONDS);
        mergeFirstRunDelayMs = (mergeFirstRunDelayMs > 0 ? mergeFirstRunDelayMs : DEFAULT_MERGE_RUN_DELAY_MILLIS);

        ExecutionService executionService = nodeEngine.getExecutionService();
        executionService.register(EXECUTOR_NAME, 2, CLUSTER_EXECUTOR_QUEUE_CAPACITY, ExecutorType.CACHED);

        long mergeNextRunDelayMs = node.groupProperties.getMillis(GroupProperty.MERGE_NEXT_RUN_DELAY_SECONDS);
        mergeNextRunDelayMs = (mergeNextRunDelayMs > 0 ? mergeNextRunDelayMs : DEFAULT_MERGE_RUN_DELAY_MILLIS);
        executionService.scheduleWithFixedDelay(EXECUTOR_NAME, new SplitBrainHandler(node), mergeFirstRunDelayMs,
                mergeNextRunDelayMs, TimeUnit.MILLISECONDS);

        clusterHeartbeatManager.init();
    }

    public void sendMemberListToMember(Address target) {
        if (!isMaster()) {
            return;
        }
        if (thisAddress.equals(target)) {
            return;
        }
        Collection members = getMemberImpls();
        MemberInfoUpdateOperation op = new MemberInfoUpdateOperation(
                createMemberInfoList(members), clusterClock.getClusterTime(), false);
        nodeEngine.getOperationService().send(op, target);
    }

    public void removeAddress(Address deadAddress) {
        doRemoveAddress(deadAddress, true);
    }

    void doRemoveAddress(Address deadAddress, boolean destroyConnection) {
        if (!ensureMemberIsRemovable(deadAddress)) {
            return;
        }

        lock.lock();
        try {
            if (deadAddress.equals(node.getMasterAddress())) {
                assignNewMaster();
            }
            if (node.isMaster()) {
                clusterJoinManager.removeJoin(new MemberInfo(deadAddress));
            }
            Connection conn = node.connectionManager.getConnection(deadAddress);
            if (destroyConnection && conn != null) {
                node.connectionManager.destroyConnection(conn);
            }
            MemberImpl deadMember = getMember(deadAddress);
            if (deadMember != null) {
                removeMember(deadMember);
                logger.info(membersString());
            }
        } finally {
            lock.unlock();
        }
    }

    private boolean ensureMemberIsRemovable(Address deadAddress) {
        if (!node.joined()) {
            return false;
        }
        if (deadAddress.equals(thisAddress)) {
            return false;
        }
        return true;
    }

    private void assignNewMaster() {
        Address oldMasterAddress = node.getMasterAddress();
        if (node.joined()) {
            Collection members = getMembers();
            Member newMaster = null;
            int size = members.size();
            if (size > 1) {
                Iterator iterator = members.iterator();
                Member member = iterator.next();
                if (member.getAddress().equals(oldMasterAddress)) {
                    newMaster = iterator.next();
                } else {
                    logger.severe(format("Old master %s is dead, but the first of member list is a different member %s!",
                            oldMasterAddress, member));
                    newMaster = member;
                }
            } else {
                logger.warning(format("Old master %s is dead and this node is not master, "
                        + "but member list contains only %d members: %s", oldMasterAddress, size, members));
            }
            logger.info(format("Old master %s left the cluster, assigning new master %s", oldMasterAddress, newMaster));
            if (newMaster != null) {
                node.setMasterAddress(newMaster.getAddress());
            } else {
                node.setMasterAddress(null);
            }
        } else {
            node.setMasterAddress(null);
        }

        if (logger.isFinestEnabled()) {
            logger.finest(format("Old master: %s, new master: %s ", oldMasterAddress, node.getMasterAddress()));
        }

        if (node.isMaster()) {
            clusterHeartbeatManager.resetMemberMasterConfirmations();
            clusterClock.reset();
        } else {
            clusterHeartbeatManager.sendMasterConfirmation();
        }
    }

    public void merge(Address newTargetAddress) {
        node.getJoiner().setTargetAddress(newTargetAddress);
        LifecycleServiceImpl lifecycleService = node.hazelcastInstance.getLifecycleService();
        lifecycleService.runUnderLifecycleLock(new ClusterMergeTask(node));
    }

    @Override
    public void reset() {
        lock.lock();
        try {
            setMembersRef(Collections.singletonMap(thisAddress, thisMember));
            clusterHeartbeatManager.reset();
            clusterStateManager.reset();
            clusterJoinManager.reset();
        } finally {
            lock.unlock();
        }
    }

    static List createMemberInfoList(Collection members) {
        List memberInfos = new LinkedList();
        for (MemberImpl member : members) {
            memberInfos.add(new MemberInfo(member));
        }
        return memberInfos;
    }

    static Set createMemberInfoSet(Collection members) {
        Set memberInfos = new HashSet();
        for (MemberImpl member : members) {
            memberInfos.add(new MemberInfo(member));
        }
        return memberInfos;
    }

    public void updateMembers(Collection members) {
        lock.lock();
        try {
            Map currentMemberMap = membersMapRef.get();

            if (!shouldProcessMemberUpdate(currentMemberMap, members)) {
                return;
            }

            String scopeId = thisAddress.getScopeId();
            Collection newMembers = new LinkedList();
            MemberImpl[] updatedMembers = new MemberImpl[members.size()];
            int memberIndex = 0;
            for (MemberInfo memberInfo : members) {
                MemberImpl member = currentMemberMap.get(memberInfo.getAddress());
                if (member == null) {
                    member = createMember(memberInfo, scopeId);
                    newMembers.add(member);
                    long now = Clock.currentTimeMillis();
                    clusterHeartbeatManager.onHeartbeat(member, now);
                    clusterHeartbeatManager.acceptMasterConfirmation(member, now);

                    Map membersRemovedInNotActiveState
                            = new LinkedHashMap(membersRemovedInNotActiveStateRef.get());
                    membersRemovedInNotActiveState.remove(member.getAddress());
                    membersRemovedInNotActiveStateRef.set(Collections.unmodifiableMap(membersRemovedInNotActiveState));
                }
                updatedMembers[memberIndex++] = member;
            }

            setMembers(updatedMembers);
            sendMembershipEvents(currentMemberMap.values(), newMembers);

            clusterJoinManager.reset();
            clusterHeartbeatManager.heartBeat();
            node.setJoined();
            logger.info(membersString());
        } finally {
            lock.unlock();
        }
    }

    private boolean shouldProcessMemberUpdate(Map currentMembers,
                                              Collection newMemberInfos) {
        int currentMembersSize = currentMembers.size();
        int newMembersSize = newMemberInfos.size();

        if (currentMembersSize > newMembersSize) {
            logger.warning("Received an older member update, no need to process...");
            nodeEngine.getOperationService().send(new TriggerMemberListPublishOperation(), getMasterAddress());
            return false;
        }

        // member-update process only accepts new member updates
        if (currentMembersSize == newMembersSize) {
            Set currentMemberInfos = createMemberInfoSet(currentMembers.values());
            if (currentMemberInfos.containsAll(newMemberInfos)) {
                logger.finest("Received a periodic member update, no need to process...");
            } else {
                logger.warning("Received an inconsistent member update "
                        + "which contains new members and removes some of the current members! "
                        + "Ignoring and requesting a new member update...");
                nodeEngine.getOperationService().send(new TriggerMemberListPublishOperation(), getMasterAddress());
            }
            return false;
        }

        Set currentMemberInfos = createMemberInfoSet(currentMembers.values());
        currentMemberInfos.removeAll(newMemberInfos);
        if (currentMemberInfos.isEmpty()) {
            return true;
        } else {
            logger.warning("Received an inconsistent member update."
                    + " It has more members but also removes some of the current members!"
                    + " Ignoring and requesting a new member update...");
            nodeEngine.getOperationService().send(new TriggerMemberListPublishOperation(), getMasterAddress());
            return false;
        }
    }

    private void sendMembershipEvents(Collection currentMembers, Collection newMembers) {
        Set eventMembers = new LinkedHashSet(currentMembers);
        if (!newMembers.isEmpty()) {
            if (newMembers.size() == 1) {
                MemberImpl newMember = newMembers.iterator().next();
                // sync call
                node.getPartitionService().memberAdded(newMember);

                // async events
                eventMembers.add(newMember);
                sendMembershipEventNotifications(newMember, unmodifiableSet(eventMembers), true);
            } else {
                for (MemberImpl newMember : newMembers) {
                    // sync call
                    node.getPartitionService().memberAdded(newMember);

                    // async events
                    eventMembers.add(newMember);
                    sendMembershipEventNotifications(newMember, unmodifiableSet(new LinkedHashSet(eventMembers)), true);
                }
            }
        }
    }

    public void updateMemberAttribute(String uuid, MemberAttributeOperationType operationType, String key, Object value) {
        lock.lock();
        try {
            Map memberMap = membersMapRef.get();
            for (MemberImpl member : memberMap.values()) {
                if (member.getUuid().equals(uuid)) {
                    if (!member.equals(getLocalMember())) {
                        member.updateAttribute(operationType, key, value);
                    }
                    sendMemberAttributeEvent(member, operationType, key, value);
                    break;
                }
            }
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void connectionAdded(Connection connection) {
    }

    @Override
    public void connectionRemoved(Connection connection) {
        if (logger.isFinestEnabled()) {
            logger.finest("Removed connection " + connection.getEndPoint());
        }
        if (!node.joined()) {
            Address masterAddress = node.getMasterAddress();
            if (masterAddress != null && masterAddress.equals(connection.getEndPoint())) {
                node.setMasterAddress(null);
            }
        }
    }

    public NodeEngineImpl getNodeEngine() {
        return nodeEngine;
    }

    private void setMembers(MemberImpl... members) {
        if (members == null || members.length == 0) {
            return;
        }
        if (logger.isFinestEnabled()) {
            logger.finest("Updating members " + Arrays.toString(members));
        }
        lock.lock();
        try {
            // !!! ORDERED !!!
            Map memberMap = new LinkedHashMap();
            for (MemberImpl member : members) {
                memberMap.put(member.getAddress(), member);
            }
            setMembersRef(memberMap);
        } finally {
            lock.unlock();
        }
    }

    private void removeMember(MemberImpl deadMember) {
        logger.info("Removing " + deadMember);
        lock.lock();
        try {
            Map members = membersMapRef.get();
            final Address deadAddress = deadMember.getAddress();

            if (members.containsKey(deadAddress)) {
                // !!! ORDERED !!!
                Map newMembers = new LinkedHashMap(members);
                newMembers.remove(deadAddress);
                clusterHeartbeatManager.removeMember(deadMember);
                setMembersRef(newMembers);

                if (node.isMaster()) {
                    if (logger.isFinestEnabled()) {
                        logger.finest(deadMember + " is dead, sending remove to all other members...");
                    }
                    invokeMemberRemoveOperation(deadAddress);
                }

                final ClusterState clusterState = clusterStateManager.getState();
                if (clusterState == ClusterState.FROZEN || clusterState == ClusterState.PASSIVE) {
                    if (logger.isFinestEnabled()) {
                        logger.finest(deadMember + " is dead, added to members left while cluster is " + clusterState + " state");
                    }
                    Map membersRemovedInNotActiveState
                            = new LinkedHashMap(membersRemovedInNotActiveStateRef.get());
                    membersRemovedInNotActiveState.put(deadAddress, deadMember);
                    membersRemovedInNotActiveStateRef.set(Collections.unmodifiableMap(membersRemovedInNotActiveState));
                    final InternalPartitionServiceImpl partitionService = node.partitionService;
                    partitionService.cancelReplicaSyncRequestsTo(deadAddress);
                } else {
                    onMemberRemove(deadMember, newMembers);
                }

                // async events
                sendMembershipEventNotifications(deadMember,
                        unmodifiableSet(new LinkedHashSet(newMembers.values())), false);
            }
        } finally {
            lock.unlock();
        }
    }

    private void onMemberRemove(MemberImpl deadMember, Map newMembers) {
        // sync call
        node.getPartitionService().memberRemoved(deadMember);
        // sync call
        nodeEngine.onMemberLeft(deadMember);
    }

    public boolean isMemberRemovedWhileClusterIsNotActive(Address target) {
        Map membersRemovedInNotActiveState = membersRemovedInNotActiveStateRef.get();
        return membersRemovedInNotActiveState.containsKey(target);
    }

    public Collection getMembersRemovedWhileClusterIsNotActive() {
        Map membersRemovedInNotActiveState = membersRemovedInNotActiveStateRef.get();
        return membersRemovedInNotActiveState.values();
    }

    void removeMembersDeadWhileClusterIsNotActive() {
        lock.lock();
        try {
            Map memberMap = membersMapRef.get();
            Map membersRemovedInNotActiveState = membersRemovedInNotActiveStateRef.get();
            Collection members = membersRemovedInNotActiveState.values();
            membersRemovedInNotActiveStateRef.set(Collections.emptyMap());
            for (MemberImpl member : members) {
                onMemberRemove(member, memberMap);
            }

        } finally {
            lock.unlock();
        }
    }

    private void invokeMemberRemoveOperation(Address deadAddress) {
        for (Member member : getMembers()) {
            Address address = member.getAddress();
            if (!thisAddress.equals(address) && !address.equals(deadAddress)) {
                nodeEngine.getOperationService().send(new MemberRemoveOperation(deadAddress), address);
            }
        }
    }

    public void sendShutdownMessage() {
        invokeMemberRemoveOperation(thisAddress);
    }

    private void sendMembershipEventNotifications(MemberImpl member, Set members, final boolean added) {
        int eventType = added ? MembershipEvent.MEMBER_ADDED : MembershipEvent.MEMBER_REMOVED;
        MembershipEvent membershipEvent = new MembershipEvent(this, member, eventType, members);
        Collection membershipAwareServices = nodeEngine.getServices(MembershipAwareService.class);
        if (membershipAwareServices != null && !membershipAwareServices.isEmpty()) {
            final MembershipServiceEvent event = new MembershipServiceEvent(membershipEvent);
            for (final MembershipAwareService service : membershipAwareServices) {
                nodeEngine.getExecutionService().execute(MEMBERSHIP_EVENT_EXECUTOR_NAME, new Runnable() {
                    public void run() {
                        if (added) {
                            service.memberAdded(event);
                        } else {
                            service.memberRemoved(event);
                        }
                    }
                });
            }
        }
        EventService eventService = nodeEngine.getEventService();
        Collection registrations = eventService.getRegistrations(SERVICE_NAME, SERVICE_NAME);
        for (EventRegistration reg : registrations) {
            eventService.publishEvent(SERVICE_NAME, reg, membershipEvent, reg.getId().hashCode());
        }
    }

    private void sendMemberAttributeEvent(MemberImpl member, MemberAttributeOperationType operationType, String key,
                                          Object value) {
        final MemberAttributeServiceEvent event
                = new MemberAttributeServiceEvent(this, member, operationType, key, value);
        MemberAttributeEvent attributeEvent = new MemberAttributeEvent(this, member, operationType, key, value);
        Collection membershipAwareServices = nodeEngine.getServices(MembershipAwareService.class);
        if (membershipAwareServices != null && !membershipAwareServices.isEmpty()) {
            for (final MembershipAwareService service : membershipAwareServices) {
                // service events should not block each other
                nodeEngine.getExecutionService().execute(ExecutionService.SYSTEM_EXECUTOR, new Runnable() {
                    public void run() {
                        service.memberAttributeChanged(event);
                    }
                });
            }
        }
        EventService eventService = nodeEngine.getEventService();
        Collection registrations = eventService.getRegistrations(SERVICE_NAME, SERVICE_NAME);
        for (EventRegistration reg : registrations) {
            eventService.publishEvent(SERVICE_NAME, reg, attributeEvent, reg.getId().hashCode());
        }
    }

    private MemberImpl createMember(MemberInfo memberInfo, String ipV6ScopeId) {
        Address address = memberInfo.getAddress();
        address.setScopeId(ipV6ScopeId);
        return new MemberImpl(address, thisAddress.equals(address), memberInfo.getUuid(),
                (HazelcastInstanceImpl) nodeEngine.getHazelcastInstance(), memberInfo.getAttributes(), memberInfo.isLiteMember());
    }

    @Override
    public MemberImpl getMember(Address address) {
        if (address == null) {
            return null;
        }
        Map memberMap = membersMapRef.get();
        return memberMap.get(address);
    }

    @Override
    public MemberImpl getMember(String uuid) {
        if (uuid == null) {
            return null;
        }

        Map memberMap = membersMapRef.get();
        for (MemberImpl member : memberMap.values()) {
            if (uuid.equals(member.getUuid())) {
                return member;
            }
        }
        return null;
    }

    private void setMembersRef(Map memberMap) {
        memberMap = unmodifiableMap(memberMap);
        // make values(), keySet() and entrySet() to be cached
        memberMap.values();
        memberMap.keySet();
        memberMap.entrySet();
        membersMapRef.set(memberMap);
        membersRef.set(unmodifiableSet(new LinkedHashSet(memberMap.values())));
    }

    @Override
    public Collection getMemberImpls() {
        return membersRef.get();
    }

    public Collection
getMemberAddresses() { Map map = membersMapRef.get(); return map.keySet(); } @SuppressWarnings("unchecked") @Override public Set getMembers() { return (Set) membersRef.get(); } @Override public Collection getMembers(MemberSelector selector) { return (Collection) new MemberSelectingCollection(membersRef.get(), selector); } @Override public void shutdown(boolean terminate) { reset(); } @Override public Address getMasterAddress() { return node.getMasterAddress(); } @Override public boolean isMaster() { return node.isMaster(); } @Override public Address getThisAddress() { return thisAddress; } public Member getLocalMember() { return node.getLocalMember(); } @Probe(name = "size") @Override public int getSize() { return getMembers().size(); } @Override public int getSize(MemberSelector selector) { int size = 0; for (MemberImpl member : membersRef.get()) { if (selector.select(member)) { size++; } } return size; } public String addMembershipListener(MembershipListener listener) { checkNotNull(listener, "listener cannot be null"); EventService eventService = nodeEngine.getEventService(); EventRegistration registration; if (listener instanceof InitialMembershipListener) { lock.lock(); try { ((InitialMembershipListener) listener).init(new InitialMembershipEvent(this, getMembers())); registration = eventService.registerLocalListener(SERVICE_NAME, SERVICE_NAME, listener); } finally { lock.unlock(); } } else { registration = eventService.registerLocalListener(SERVICE_NAME, SERVICE_NAME, listener); } return registration.getId(); } public boolean removeMembershipListener(String registrationId) { checkNotNull(registrationId, "registrationId cannot be null"); EventService eventService = nodeEngine.getEventService(); return eventService.deregisterListener(SERVICE_NAME, SERVICE_NAME, registrationId); } @SuppressFBWarnings("BC_UNCONFIRMED_CAST") @Override public void dispatchEvent(MembershipEvent event, MembershipListener listener) { switch (event.getEventType()) { case MembershipEvent.MEMBER_ADDED: listener.memberAdded(event); break; case MembershipEvent.MEMBER_REMOVED: listener.memberRemoved(event); break; case MembershipEvent.MEMBER_ATTRIBUTE_CHANGED: MemberAttributeEvent memberAttributeEvent = (MemberAttributeEvent) event; listener.memberAttributeChanged(memberAttributeEvent); break; default: throw new IllegalArgumentException("Unhandled event: " + event); } } public String membersString() { StringBuilder sb = new StringBuilder("\n\nMembers ["); Collection members = getMemberImpls(); sb.append(members != null ? members.size() : 0); sb.append("] {"); if (members != null) { for (Member member : members) { sb.append("\n\t").append(member); } } sb.append("\n}\n"); return sb.toString(); } @Override public ClusterState getClusterState() { return clusterStateManager.getState(); } @Override public T createTransactionalObject(String name, Transaction transaction) { throw new UnsupportedOperationException(SERVICE_NAME + " does not support TransactionalObjects!"); } @Override public void rollbackTransaction(String transactionId) { logger.info("Rolling back cluster state. Transaction: " + transactionId); clusterStateManager.rollbackClusterState(transactionId); } @Override public void changeClusterState(ClusterState newState) { int partitionStateVersion = node.getPartitionService().getPartitionStateVersion(); clusterStateManager.changeClusterState(newState, partitionStateVersion); } @Override public void changeClusterState(ClusterState newState, TransactionOptions options) { int partitionStateVersion = node.getPartitionService().getPartitionStateVersion(); clusterStateManager.changeClusterState(newState, options, partitionStateVersion); } // for testing public void changeClusterState(ClusterState newState, int partitionStateVersion) { clusterStateManager.changeClusterState(newState, partitionStateVersion); } @Override public void shutdown() { changeClusterState(ClusterState.PASSIVE); shutdownNodes(); } @Override public void shutdown(TransactionOptions options) { changeClusterState(ClusterState.PASSIVE, options); shutdownNodes(); } private void shutdownNodes() { final Operation op = new ShutdownNodeOperation(); logger.info("Sending shutting down operations to all members..."); Collection members = getMembers(NON_LOCAL_MEMBER_SELECTOR); final long timeout = node.groupProperties.getNanos(GroupProperty.CLUSTER_SHUTDOWN_TIMEOUT_SECONDS); final long startTime = System.nanoTime(); while ((System.nanoTime() - startTime) < timeout && !members.isEmpty()) { for (Member member : members) { nodeEngine.getOperationService().send(op, member.getAddress()); } try { Thread.sleep(CLUSTER_SHUTDOWN_SLEEP_DURATION_IN_MILLIS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.warning("Shutdown sleep interrupted. ", e); break; } members = getMembers(NON_LOCAL_MEMBER_SELECTOR); } logger.info("Number of other nodes remaining: " + getSize(NON_LOCAL_MEMBER_SELECTOR) + ". Shutting down itself."); node.shutdown(false); } public void initialClusterState(ClusterState clusterState) { if (node.joined()) { throw new IllegalStateException("Cannot set initial state after node joined! -> " + clusterState); } clusterStateManager.initialClusterState(clusterState); } public ClusterStateManager getClusterStateManager() { return clusterStateManager; } public ClusterJoinManager getClusterJoinManager() { return clusterJoinManager; } public ClusterHeartbeatManager getClusterHeartbeatManager() { return clusterHeartbeatManager; } @Override public String toString() { return "ClusterService" + "{address=" + thisAddress + '}'; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy