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

org.neo4j.kernel.ha.MasterClient210 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;

import java.io.IOException;
import java.nio.ByteBuffer;

import org.jboss.netty.buffer.ChannelBuffer;

import org.neo4j.com.Client;
import org.neo4j.com.Deserializer;
import org.neo4j.com.Protocol;
import org.neo4j.com.Protocol201;
import org.neo4j.com.ProtocolVersion;
import org.neo4j.com.RequestContext;
import org.neo4j.com.RequestType;
import org.neo4j.com.Response;
import org.neo4j.com.Serializer;
import org.neo4j.com.monitor.RequestMonitor;
import org.neo4j.com.storecopy.ResponseUnpacker;
import org.neo4j.com.storecopy.ResponseUnpacker.TxHandler;
import org.neo4j.com.storecopy.StoreWriter;
import org.neo4j.kernel.impl.store.id.IdType;
import org.neo4j.kernel.ha.HaRequestTypes.Type;
import org.neo4j.kernel.ha.com.master.HandshakeResult;
import org.neo4j.kernel.ha.com.master.Master;
import org.neo4j.kernel.ha.com.master.MasterServer;
import org.neo4j.kernel.ha.com.slave.MasterClient;
import org.neo4j.kernel.ha.id.IdAllocation;
import org.neo4j.kernel.ha.lock.LockResult;
import org.neo4j.kernel.impl.store.StoreId;
import org.neo4j.kernel.impl.store.id.IdRange;
import org.neo4j.kernel.impl.transaction.TransactionRepresentation;
import org.neo4j.kernel.impl.transaction.log.ReadableClosablePositionAwareChannel;
import org.neo4j.kernel.impl.transaction.log.entry.LogEntryReader;
import org.neo4j.kernel.monitoring.ByteCounterMonitor;
import org.neo4j.logging.LogProvider;
import org.neo4j.storageengine.api.lock.ResourceType;

import static org.neo4j.com.Protocol.EMPTY_SERIALIZER;
import static org.neo4j.com.Protocol.VOID_DESERIALIZER;
import static org.neo4j.com.Protocol.writeString;
import static org.neo4j.com.ProtocolVersion.INTERNAL_PROTOCOL_VERSION;

/**
 * The {@link org.neo4j.kernel.ha.com.master.Master} a slave should use to communicate with its master. It
 * serializes requests and sends them to the master, more specifically
 * {@link org.neo4j.kernel.ha.com.master.MasterServer} (which delegates to {@link org.neo4j.kernel.ha.com.master.MasterImpl}
 * on the master side.
 */
public class MasterClient210 extends Client implements MasterClient
{
    /* Version 1 first version
     * Version 2 since 2012-01-24
     * Version 3 since 2012-02-16
     * Version 4 since 2012-07-05
     * Version 5 since ?
     * Version 6 since 2014-01-07
     * Version 7 since 2014-03-18
     */
    public static final ProtocolVersion PROTOCOL_VERSION = new ProtocolVersion( (byte) 7, INTERNAL_PROTOCOL_VERSION );

    private final long lockReadTimeoutMillis;
    private final HaRequestTypes requestTypes;

    public MasterClient210( String destinationHostNameOrIp, int destinationPort, String originHostNameOrIp,
                            LogProvider logProvider, StoreId storeId, long readTimeoutMillis,
                            long lockReadTimeoutMillis, int maxConcurrentChannels, int chunkSize,
                            ResponseUnpacker responseUnpacker,
                            ByteCounterMonitor byteCounterMonitor, RequestMonitor requestMonitor,
                            LogEntryReader entryReader )
    {
        super( destinationHostNameOrIp, destinationPort, originHostNameOrIp, logProvider, storeId,
                MasterServer.FRAME_LENGTH, PROTOCOL_VERSION, readTimeoutMillis, maxConcurrentChannels, chunkSize,
                responseUnpacker, byteCounterMonitor, requestMonitor, entryReader );
        this.lockReadTimeoutMillis = lockReadTimeoutMillis;
        this.requestTypes = new HaRequestType210( entryReader );
    }

    MasterClient210( String destinationHostNameOrIp, int destinationPort, String originHostNameOrIp,
                     LogProvider logProvider, StoreId storeId, long readTimeoutMillis,
                     long lockReadTimeoutMillis, int maxConcurrentChannels, int chunkSize,
                     ProtocolVersion protocolVersion, ResponseUnpacker responseUnpacker,
                     ByteCounterMonitor byteCounterMonitor, RequestMonitor requestMonitor,
                     LogEntryReader entryReader )
    {
        super( destinationHostNameOrIp, destinationPort, originHostNameOrIp, logProvider, storeId,
                MasterServer.FRAME_LENGTH, protocolVersion, readTimeoutMillis, maxConcurrentChannels, chunkSize,
                responseUnpacker, byteCounterMonitor, requestMonitor, entryReader );
        this.lockReadTimeoutMillis = lockReadTimeoutMillis;
        this.requestTypes = new HaRequestType210( entryReader );
    }

    @Override
    protected Protocol createProtocol( int chunkSize, byte applicationProtocolVersion )
    {
        return new Protocol201( chunkSize, applicationProtocolVersion, getInternalProtocolVersion() );
    }

    @Override
    protected long getReadTimeout( RequestType type, long readTimeout )
    {
        if ( Type.ACQUIRE_EXCLUSIVE_LOCK.is( type ) || Type.ACQUIRE_SHARED_LOCK.is( type ) )
        {
            return lockReadTimeoutMillis;
        }
        if ( Type.COPY_STORE.is( type ) )
        {
            return readTimeout * 2;
        }
        return readTimeout;
    }

    @Override
    protected boolean shouldCheckStoreId( RequestType type )
    {
        return !Type.COPY_STORE.is( type );
    }

    @Override
    public Response allocateIds( RequestContext context, final IdType idType )
    {
        return sendRequest( requestTypes.type( Type.ALLOCATE_IDS ), context, new Serializer()
                {
                    @Override
                    public void write( ChannelBuffer buffer ) throws IOException
                    {
                        buffer.writeByte( idType.ordinal() );
                    }
                }, new Deserializer()
                {
                    @Override
                    public IdAllocation read( ChannelBuffer buffer, ByteBuffer temporaryBuffer )
                    {
                        return readIdAllocation( buffer );
                    }
                }
        );
    }

    @Override
    public Response createRelationshipType( RequestContext context, final String name )
    {
        return sendRequest( requestTypes.type( Type.CREATE_RELATIONSHIP_TYPE ), context, new Serializer()
        {
            @Override
            public void write( ChannelBuffer buffer ) throws IOException
            {
                writeString( buffer, name );
            }
        }, new Deserializer()
        {
            @Override
            @SuppressWarnings("boxing")
            public Integer read( ChannelBuffer buffer, ByteBuffer temporaryBuffer ) throws IOException
            {
                return buffer.readInt();
            }
        } );
    }

    @Override
    public Response createPropertyKey( RequestContext context, final String name )
    {
        return sendRequest( requestTypes.type( Type.CREATE_PROPERTY_KEY ), context, new Serializer()
        {
            @Override
            public void write( ChannelBuffer buffer ) throws IOException
            {
                writeString( buffer, name );
            }
        }, new Deserializer()
        {
            @Override
            @SuppressWarnings("boxing")
            public Integer read( ChannelBuffer buffer, ByteBuffer temporaryBuffer ) throws IOException
            {
                return buffer.readInt();
            }
        } );
    }

    @Override
    public Response createLabel( RequestContext context, final String name )
    {
        return sendRequest( requestTypes.type( Type.CREATE_LABEL ), context, new Serializer()
                {
                    @Override
                    public void write( ChannelBuffer buffer ) throws IOException
                    {
                writeString( buffer, name );
            }
        }, new Deserializer()
        {
            @Override
            @SuppressWarnings("boxing")
            public Integer read( ChannelBuffer buffer, ByteBuffer temporaryBuffer ) throws IOException
            {
                return buffer.readInt();
            }
        });
    }

    @Override
    public Response newLockSession( RequestContext context )
    {
        return sendRequest( requestTypes.type( Type.NEW_LOCK_SESSION ), context, EMPTY_SERIALIZER, VOID_DESERIALIZER );
    }

    @Override
    public Response acquireSharedLock( RequestContext context, ResourceType type, long...
            resourceIds )
    {
        return sendRequest( requestTypes.type( Type.ACQUIRE_SHARED_LOCK ), context,
                new AcquireLockSerializer( type, resourceIds ), LOCK_RESULT_DESERIALIZER );
    }

    @Override
    public Response acquireExclusiveLock( RequestContext context, ResourceType type, long...
            resourceIds )
    {
        return sendRequest( requestTypes.type( Type.ACQUIRE_EXCLUSIVE_LOCK ), context,
                new AcquireLockSerializer( type, resourceIds ), LOCK_RESULT_DESERIALIZER );
    }

    @Override
    public Response commit( RequestContext context, TransactionRepresentation tx )
    {
        return sendRequest( requestTypes.type( Type.COMMIT ), context, new Protocol.TransactionSerializer( tx ),
                new Deserializer()
                {
                    @Override
                    @SuppressWarnings("boxing")
                    public Long read( ChannelBuffer buffer, ByteBuffer temporaryBuffer ) throws IOException
                    {
                        return buffer.readLong();
                    }
                }
        );
    }

    @Override
    public Response endLockSession( RequestContext context, final boolean success )
    {
        return sendRequest( requestTypes.type( Type.END_LOCK_SESSION ), context, new Serializer()
        {
            @Override
            public void write( ChannelBuffer buffer ) throws IOException
            {
                buffer.writeByte( success ? 1 : 0 );
            }
        }, VOID_DESERIALIZER );
    }

    @Override
    public Response pullUpdates( RequestContext context )
    {
        return pullUpdates( context, ResponseUnpacker.NO_OP_TX_HANDLER );
    }

    @Override
    public Response pullUpdates( RequestContext context, TxHandler txHandler )
    {
        return sendRequest( requestTypes.type( Type.PULL_UPDATES ), context,
                EMPTY_SERIALIZER, VOID_DESERIALIZER, null, txHandler );
    }

    @Override
    public Response handshake( final long txId, StoreId storeId )
    {
        return sendRequest( requestTypes.type( Type.HANDSHAKE ), RequestContext.EMPTY, new Serializer()
                {
                    @Override
                    public void write( ChannelBuffer buffer ) throws IOException
                    {
                        buffer.writeLong( txId );
                    }
                }, new Deserializer()
                {
                    @Override
                    public HandshakeResult read( ChannelBuffer buffer, ByteBuffer temporaryBuffer ) throws
                            IOException
                    {
                        return new HandshakeResult( buffer.readLong(), buffer.readLong() );
                    }
                }, storeId, ResponseUnpacker.NO_OP_TX_HANDLER
        );
    }

    @Override
    public Response copyStore( RequestContext context, final StoreWriter writer )
    {
        context = stripFromTransactions( context );
        return sendRequest( requestTypes.type( Type.COPY_STORE ), context, EMPTY_SERIALIZER,
                new Protocol.FileStreamsDeserializer( writer ) );
    }

    private RequestContext stripFromTransactions( RequestContext context )
    {
        return new RequestContext( context.getEpoch(), context.machineId(), context.getEventIdentifier(),
                0, context.getChecksum() );
    }

    @Override
    public ProtocolVersion getProtocolVersion()
    {
        return PROTOCOL_VERSION;
    }

    protected static IdAllocation readIdAllocation( ChannelBuffer buffer )
    {
        int numberOfDefragIds = buffer.readInt();
        long[] defragIds = new long[numberOfDefragIds];
        for ( int i = 0; i < numberOfDefragIds; i++ )
        {
            defragIds[i] = buffer.readLong();
        }
        long rangeStart = buffer.readLong();
        int rangeLength = buffer.readInt();
        long highId = buffer.readLong();
        long defragCount = buffer.readLong();
        return new IdAllocation( new IdRange( defragIds, rangeStart, rangeLength ),
                highId, defragCount );
    }

    protected static class AcquireLockSerializer implements Serializer
    {
        private final ResourceType type;
        private final long[] resourceIds;

        AcquireLockSerializer( ResourceType type, long... resourceIds )
        {
            this.type = type;
            this.resourceIds = resourceIds;
        }

        @Override
        public void write( ChannelBuffer buffer ) throws IOException
        {
            buffer.writeInt( type.typeId() );
            buffer.writeInt( resourceIds.length );
            for ( long entity : resourceIds )
            {
                buffer.writeLong( entity );
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy