Search in sources :

Example 1 with SupportedMessage

use of org.apache.cassandra.transport.messages.SupportedMessage in project cassandra by apache.

the class InitialConnectionHandler method decode.

protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> list) throws Exception {
    Envelope inbound = decoder.decode(buffer);
    if (inbound == null)
        return;
    try {
        Envelope outbound;
        switch(inbound.header.type) {
            case OPTIONS:
                logger.trace("OPTIONS received {}", inbound.header.version);
                List<String> cqlVersions = new ArrayList<>();
                cqlVersions.add(QueryProcessor.CQL_VERSION.toString());
                List<String> compressions = new ArrayList<>();
                if (Compressor.SnappyCompressor.instance != null)
                    compressions.add("snappy");
                // LZ4 is always available since worst case scenario it default to a pure JAVA implem.
                compressions.add("lz4");
                Map<String, List<String>> supportedOptions = new HashMap<>();
                supportedOptions.put(StartupMessage.CQL_VERSION, cqlVersions);
                supportedOptions.put(StartupMessage.COMPRESSION, compressions);
                supportedOptions.put(StartupMessage.PROTOCOL_VERSIONS, ProtocolVersion.supportedVersions());
                SupportedMessage supported = new SupportedMessage(supportedOptions);
                supported.setStreamId(inbound.header.streamId);
                outbound = supported.encode(inbound.header.version);
                ctx.writeAndFlush(outbound);
                break;
            case STARTUP:
                Attribute<Connection> attrConn = ctx.channel().attr(Connection.attributeKey);
                Connection connection = attrConn.get();
                if (connection == null) {
                    connection = factory.newConnection(ctx.channel(), inbound.header.version);
                    attrConn.set(connection);
                }
                assert connection instanceof ServerConnection;
                StartupMessage startup = (StartupMessage) Message.Decoder.decodeMessage(ctx.channel(), inbound);
                InetAddress remoteAddress = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
                final ClientResourceLimits.Allocator allocator = ClientResourceLimits.getAllocatorForEndpoint(remoteAddress);
                ChannelPromise promise;
                if (inbound.header.version.isGreaterOrEqualTo(ProtocolVersion.V5)) {
                    // in this case we need to defer configuring the pipeline until after the response
                    // has been sent, as the frame encoding specified in v5 should not be applied to
                    // the STARTUP response.
                    allocator.allocate(inbound.header.bodySizeInBytes);
                    promise = AsyncChannelPromise.withListener(ctx, future -> {
                        if (future.isSuccess()) {
                            logger.trace("Response to STARTUP sent, configuring pipeline for {}", inbound.header.version);
                            configurator.configureModernPipeline(ctx, allocator, inbound.header.version, startup.options);
                            allocator.release(inbound.header.bodySizeInBytes);
                        } else {
                            Throwable cause = future.cause();
                            if (null == cause)
                                cause = new ServerError("Unexpected error establishing connection");
                            logger.warn("Writing response to STARTUP failed, unable to configure pipeline", cause);
                            ErrorMessage error = ErrorMessage.fromException(cause);
                            Envelope response = error.encode(inbound.header.version);
                            ChannelPromise closeChannel = AsyncChannelPromise.withListener(ctx, f -> ctx.close());
                            ctx.writeAndFlush(response, closeChannel);
                            if (ctx.channel().isOpen())
                                ctx.channel().close();
                        }
                    });
                } else {
                    // no need to configure the pipeline asynchronously in this case
                    // the capacity obtained from allocator for the STARTUP message
                    // is released when flushed by the legacy dispatcher/flusher so
                    // there's no need to explicitly release that here either.
                    configurator.configureLegacyPipeline(ctx, allocator);
                    promise = new VoidChannelPromise(ctx.channel(), false);
                }
                final Message.Response response = Dispatcher.processRequest(ctx.channel(), startup, Overload.NONE);
                outbound = response.encode(inbound.header.version);
                ctx.writeAndFlush(outbound, promise);
                logger.trace("Configured pipeline: {}", ctx.pipeline());
                break;
            default:
                ErrorMessage error = ErrorMessage.fromException(new ProtocolException(String.format("Unexpected message %s, expecting STARTUP or OPTIONS", inbound.header.type)));
                outbound = error.encode(inbound.header.version);
                ctx.writeAndFlush(outbound);
        }
    } finally {
        inbound.release();
    }
}
Also used : Attribute(io.netty.util.Attribute) Logger(org.slf4j.Logger) AsyncChannelPromise(org.apache.cassandra.net.AsyncChannelPromise) LoggerFactory(org.slf4j.LoggerFactory) HashMap(java.util.HashMap) Overload(org.apache.cassandra.transport.ClientResourceLimits.Overload) QueryProcessor(org.apache.cassandra.cql3.QueryProcessor) InetSocketAddress(java.net.InetSocketAddress) ArrayList(java.util.ArrayList) InetAddress(java.net.InetAddress) VoidChannelPromise(io.netty.channel.VoidChannelPromise) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) List(java.util.List) ByteBuf(io.netty.buffer.ByteBuf) ChannelPromise(io.netty.channel.ChannelPromise) Map(java.util.Map) StartupMessage(org.apache.cassandra.transport.messages.StartupMessage) SupportedMessage(org.apache.cassandra.transport.messages.SupportedMessage) ErrorMessage(org.apache.cassandra.transport.messages.ErrorMessage) ByteToMessageDecoder(io.netty.handler.codec.ByteToMessageDecoder) StartupMessage(org.apache.cassandra.transport.messages.StartupMessage) SupportedMessage(org.apache.cassandra.transport.messages.SupportedMessage) ErrorMessage(org.apache.cassandra.transport.messages.ErrorMessage) HashMap(java.util.HashMap) InetSocketAddress(java.net.InetSocketAddress) ArrayList(java.util.ArrayList) StartupMessage(org.apache.cassandra.transport.messages.StartupMessage) VoidChannelPromise(io.netty.channel.VoidChannelPromise) AsyncChannelPromise(org.apache.cassandra.net.AsyncChannelPromise) VoidChannelPromise(io.netty.channel.VoidChannelPromise) ChannelPromise(io.netty.channel.ChannelPromise) ArrayList(java.util.ArrayList) List(java.util.List) SupportedMessage(org.apache.cassandra.transport.messages.SupportedMessage) ErrorMessage(org.apache.cassandra.transport.messages.ErrorMessage) InetAddress(java.net.InetAddress)

Aggregations

ByteBuf (io.netty.buffer.ByteBuf)1 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)1 ChannelPromise (io.netty.channel.ChannelPromise)1 VoidChannelPromise (io.netty.channel.VoidChannelPromise)1 ByteToMessageDecoder (io.netty.handler.codec.ByteToMessageDecoder)1 Attribute (io.netty.util.Attribute)1 InetAddress (java.net.InetAddress)1 InetSocketAddress (java.net.InetSocketAddress)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 QueryProcessor (org.apache.cassandra.cql3.QueryProcessor)1 AsyncChannelPromise (org.apache.cassandra.net.AsyncChannelPromise)1 Overload (org.apache.cassandra.transport.ClientResourceLimits.Overload)1 ErrorMessage (org.apache.cassandra.transport.messages.ErrorMessage)1 StartupMessage (org.apache.cassandra.transport.messages.StartupMessage)1 SupportedMessage (org.apache.cassandra.transport.messages.SupportedMessage)1 Logger (org.slf4j.Logger)1 LoggerFactory (org.slf4j.LoggerFactory)1