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

org.apache.pulsar.common.protocol.ByteBufPair Maven / Gradle / Ivy

There is a newer version: 4.0.0.4
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.pulsar.common.protocol;

import org.apache.pulsar.shade.com.google.common.annotations.VisibleForTesting;
import org.apache.pulsar.shade.io.netty.buffer.ByteBuf;
import org.apache.pulsar.shade.io.netty.buffer.Unpooled;
import org.apache.pulsar.shade.io.netty.channel.ChannelHandler.Sharable;
import org.apache.pulsar.shade.io.netty.channel.ChannelHandlerContext;
import org.apache.pulsar.shade.io.netty.channel.ChannelOutboundHandlerAdapter;
import org.apache.pulsar.shade.io.netty.channel.ChannelPromise;
import org.apache.pulsar.shade.io.netty.util.AbstractReferenceCounted;
import org.apache.pulsar.shade.io.netty.util.Recycler;
import org.apache.pulsar.shade.io.netty.util.Recycler.Handle;
import org.apache.pulsar.shade.io.netty.util.ReferenceCountUtil;
import org.apache.pulsar.shade.io.netty.util.ReferenceCounted;

/**
 * ByteBuf holder that contains 2 buffers.
 */
public final class ByteBufPair extends AbstractReferenceCounted {

    private ByteBuf b1;
    private ByteBuf b2;
    private final Handle recyclerHandle;

    private static final Recycler RECYCLER = new Recycler() {
        @Override
        protected ByteBufPair newObject(Recycler.Handle handle) {
            return new ByteBufPair(handle);
        }
    };

    private ByteBufPair(Handle recyclerHandle) {
        this.recyclerHandle = recyclerHandle;
    }

    /**
     * Get a new {@link ByteBufPair} from the pool and assign 2 buffers to it.
     *
     * 

The buffers b1 and b2 lifecycles are now managed by the ByteBufPair: * when the {@link ByteBufPair} is deallocated, b1 and b2 will be released as well. * * @param b1 * @param b2 * @return */ public static ByteBufPair get(ByteBuf b1, ByteBuf b2) { ByteBufPair buf = RECYCLER.get(); buf.setRefCnt(1); buf.b1 = b1; buf.b2 = b2; return buf; } public ByteBuf getFirst() { return b1; } public ByteBuf getSecond() { return b2; } public int readableBytes() { return b1.readableBytes() + b2.readableBytes(); } /** * @return a single buffer with the content of both individual buffers */ @VisibleForTesting public static ByteBuf coalesce(ByteBufPair pair) { ByteBuf b = Unpooled.buffer(pair.readableBytes()); b.writeBytes(pair.b1, pair.b1.readerIndex(), pair.b1.readableBytes()); b.writeBytes(pair.b2, pair.b2.readerIndex(), pair.b2.readableBytes()); return b; } @Override protected void deallocate() { b1.release(); b2.release(); b1 = b2 = null; recyclerHandle.recycle(this); } @Override public ReferenceCounted touch(Object hint) { b1.touch(hint); b2.touch(hint); return this; } /** * Encoder that writes a {@link ByteBufPair} to the socket. * Use {@link #getEncoder(boolean)} to get the appropriate encoder instead of referencing this. */ @Deprecated public static final Encoder ENCODER = new Encoder(); private static final boolean COPY_ENCODER_REQUIRED_FOR_TLS; static { boolean copyEncoderRequiredForTls = false; try { // io.netty.handler.ssl.SslHandlerCoalescingBufferQueue is only available in netty 4.1.111 and later // when the class is available, there's no need to use the CopyingEncoder when TLS is enabled ByteBuf.class.getClassLoader().loadClass("org.apache.pulsar.shade.io.netty.handler.ssl.SslHandlerCoalescingBufferQueue"); } catch (ClassNotFoundException e) { copyEncoderRequiredForTls = true; } COPY_ENCODER_REQUIRED_FOR_TLS = copyEncoderRequiredForTls; } /** * Encoder that makes a copy of the ByteBufs before writing them to the socket. * This is needed with Netty <4.1.111.Final when TLS is enabled, because the SslHandler will modify the input * ByteBufs. * Use {@link #getEncoder(boolean)} to get the appropriate encoder instead of referencing this. */ @Deprecated public static final CopyingEncoder COPYING_ENCODER = new CopyingEncoder(); public static ChannelOutboundHandlerAdapter getEncoder(boolean tlsEnabled) { return tlsEnabled && COPY_ENCODER_REQUIRED_FOR_TLS ? COPYING_ENCODER : ENCODER; } @Sharable @SuppressWarnings("checkstyle:JavadocType") public static class Encoder extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { if (msg instanceof ByteBufPair) { ByteBufPair b = (ByteBufPair) msg; // Write each buffer individually on the socket. The retain() here is needed to preserve the fact that // ByteBuf are automatically released after a write. If the ByteBufPair ref count is increased and it // gets written multiple times, the individual buffers refcount should be reflected as well. try { ctx.write(b.getFirst().retainedDuplicate(), ctx.voidPromise()); ctx.write(b.getSecond().retainedDuplicate(), promise); } finally { ReferenceCountUtil.safeRelease(b); } } else { ctx.write(msg, promise); } } } @Sharable @SuppressWarnings("checkstyle:JavadocType") public static class CopyingEncoder extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { if (msg instanceof ByteBufPair) { ByteBufPair b = (ByteBufPair) msg; // Some handlers in the pipeline will modify the bytebufs passed in to them (i.e. SslHandler). // For these handlers, we need to pass a copy of the buffers as the source buffers may be cached // for multiple requests. try { ctx.write(b.getFirst().copy(), ctx.voidPromise()); ctx.write(b.getSecond().copy(), promise); } finally { ReferenceCountUtil.safeRelease(b); } } else { ctx.write(msg, promise); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy