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

org.neo4j.kernel.ha.cluster.SwitchToMaster Maven / Gradle / Ivy

Go to download

This component provides the means to set up a cluster of Neo4j instances that act together as a cluster, providing Master-Slave replication and other features.

There is a newer version: 3.5.0-beta03
Show newest version
/*
 * Copyright (c) 2002-2016 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see .
 */
package org.neo4j.kernel.ha.cluster;

import java.net.URI;
import java.util.function.BiFunction;
import java.util.function.Supplier;

import org.neo4j.cluster.ClusterSettings;
import org.neo4j.cluster.InstanceId;
import org.neo4j.cluster.member.ClusterMemberAvailability;
import org.neo4j.com.ServerUtil;
import org.neo4j.function.Factory;
import org.neo4j.kernel.NeoStoreDataSource;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.ha.DelegateInvocationHandler;
import org.neo4j.kernel.ha.HaSettings;
import org.neo4j.kernel.ha.com.master.ConversationManager;
import org.neo4j.kernel.ha.com.master.Master;
import org.neo4j.kernel.ha.com.master.MasterServer;
import org.neo4j.kernel.ha.com.master.SlaveFactory;
import org.neo4j.kernel.ha.id.HaIdGeneratorFactory;
import org.neo4j.kernel.impl.logging.LogService;
import org.neo4j.kernel.lifecycle.LifeSupport;
import org.neo4j.logging.Log;

import static org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher.MASTER;

public class SwitchToMaster implements AutoCloseable
{
    Factory conversationManagerFactory;
    BiFunction masterFactory;
    BiFunction masterServerFactory;
    private Log userLog;
    private HaIdGeneratorFactory idGeneratorFactory;
    private Config config;
    private Supplier slaveFactorySupplier;
    private DelegateInvocationHandler masterDelegateHandler;
    private ClusterMemberAvailability clusterMemberAvailability;
    private Supplier dataSourceSupplier;

    public SwitchToMaster( LogService logService,
            HaIdGeneratorFactory idGeneratorFactory, Config config, Supplier slaveFactorySupplier,
            Factory conversationManagerFactory,
            BiFunction masterFactory,
            BiFunction masterServerFactory,
            DelegateInvocationHandler masterDelegateHandler, ClusterMemberAvailability clusterMemberAvailability,
            Supplier dataSourceSupplier )
    {
        this.conversationManagerFactory = conversationManagerFactory;
        this.masterFactory = masterFactory;
        this.masterServerFactory = masterServerFactory;
        this.userLog = logService.getUserLog( getClass() );
        this.idGeneratorFactory = idGeneratorFactory;
        this.config = config;
        this.slaveFactorySupplier = slaveFactorySupplier;
        this.masterDelegateHandler = masterDelegateHandler;
        this.clusterMemberAvailability = clusterMemberAvailability;
        this.dataSourceSupplier = dataSourceSupplier;
    }

    /**
     * Performs a switch to the master state. Starts communication endpoints, switches components to the master state
     * and broadcasts the appropriate Master Is Available event.
     * @param haCommunicationLife The LifeSupport instance to register communication endpoints.
     * @param me The URI that the communication endpoints should bind to
     * @return The URI at which the master communication was bound.
     */
    public URI switchToMaster( LifeSupport haCommunicationLife, URI me )
    {
        userLog.info( "I am %s, moving to master", myId( config ) );

        // Do not wait for currently active transactions to complete before continuing switching.
        // - A master in a cluster is very important, without it the cluster cannot process any write requests
        // - Awaiting open transactions to complete assumes that this instance just now was a slave that is
        //   switching to master, which means the previous master where these active transactions were hosted
        //   is no longer available so these open transactions cannot continue and complete anyway,
        //   so what's the point waiting for them?
        // - Read transactions may still be able to complete, but the correct response to failures in those
        //   is to have them throw transient error exceptions hinting that they should be retried,
        //   at which point they may get redirected to another instance, or to this instance if it has completed
        //   the switch until then.

        idGeneratorFactory.switchToMaster();
        NeoStoreDataSource neoStoreXaDataSource = dataSourceSupplier.get();
        neoStoreXaDataSource.afterModeSwitch();

        ConversationManager conversationManager = conversationManagerFactory.newInstance();
        Master master = masterFactory.apply( conversationManager, haCommunicationLife );

        MasterServer masterServer = masterServerFactory.apply( master, conversationManager );

        haCommunicationLife.add( masterServer );
        masterDelegateHandler.setDelegate( master );

        haCommunicationLife.start();

        URI masterHaURI = getMasterUri( me, masterServer, config );
        clusterMemberAvailability.memberIsAvailable( MASTER, masterHaURI, neoStoreXaDataSource.getStoreId() );
        userLog.info( "I am %s, successfully moved to master", myId( config ) );

        slaveFactorySupplier.get().setStoreId( neoStoreXaDataSource.getStoreId() );

        return masterHaURI;
    }

    static URI getMasterUri( URI me, MasterServer masterServer, Config config )
    {

        String hostname = config.get( HaSettings.ha_server ).getHost();
        if ( hostname == null || hostname.contains( "0.0.0.0" ) )
        {
            String masterAddress = ServerUtil.getHostString( masterServer.getSocketAddress() );
            hostname = masterAddress.contains( "0.0.0.0" ) ? me.getHost() : masterAddress;
        }

        int port = masterServer.getSocketAddress().getPort();

        return URI.create( "ha://" + hostname + ":" + port + "?serverId=" + myId( config ) );
    }

    private static InstanceId myId( Config config )
    {
        return config.get( ClusterSettings.server_id );
    }

    @Override
    public void close() throws Exception
    {
        userLog = null;
        conversationManagerFactory = null;
        masterFactory = null;
        masterServerFactory = null;
        idGeneratorFactory = null;
        config = null;
        slaveFactorySupplier = null;
        masterDelegateHandler = null;
        clusterMemberAvailability = null;
        dataSourceSupplier = null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy