Package com.yahoo.omid.replication

Source Code of com.yahoo.omid.replication.SharedMessageBuffer$ReadingBuffer

/**
* Copyright (c) 2011 Yahoo! 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. See accompanying LICENSE file.
*/

package com.yahoo.omid.replication;

import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.Channels;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SharedMessageBuffer {

    private static final Logger LOG = LoggerFactory.getLogger(SharedMessageBuffer.class);

    private static final int MAX_MESSAGE_SIZE = 30;

    ReadersAwareBuffer pastBuffer = new ReadersAwareBuffer();
    ReadersAwareBuffer currentBuffer = new ReadersAwareBuffer();
    ChannelBuffer writeBuffer = currentBuffer.buffer;
    BlockingQueue<ReadersAwareBuffer> bufferPool = new LinkedBlockingQueue<ReadersAwareBuffer>();
    Zipper zipper = new Zipper();
    Set<ReadingBuffer> readingBuffers = new TreeSet<SharedMessageBuffer.ReadingBuffer>();

    public class ReadingBuffer implements Comparable<ReadingBuffer> {
        private ChannelBuffer readBuffer;
        private int readerIndex = 0;
        private ReadersAwareBuffer readingBuffer;
        private ChannelHandlerContext ctx;
        private Channel channel;

        private ReadingBuffer(ChannelHandlerContext ctx) {
            this.channel = ctx.getChannel();
            this.ctx = ctx;
        }

        public void initializeIndexes() {
            this.readingBuffer = currentBuffer;
            this.readBuffer = readingBuffer.buffer;
            this.readerIndex = readBuffer.writerIndex();
        }

        /**
         * Computes and returns the deltaSO for the associated client.
         *
         * This function registers some callbacks in the future passed for cleanup purposes, so the ChannelFuture object
         * must be notified after the communication is finished.
         *
         * @param future
         *            It registers some callbacks on it
         * @return the deltaSO for the associated client
         */
        public ChannelBuffer flush(ChannelFuture future) {
            int readable = readBuffer.readableBytes() - readerIndex;

            if (readable == 0 && readingBuffer != pastBuffer) {
                return ChannelBuffers.EMPTY_BUFFER;
            }

            ChannelBuffer deltaSO = readBuffer.slice(readerIndex, readable);
            addFinishedWriteListener(future, readingBuffer);
            readingBuffer.increaseReaders();
            readerIndex += readable;
            if (readingBuffer == pastBuffer) {
                readingBuffer = currentBuffer;
                readBuffer = readingBuffer.buffer;
                readerIndex = 0;
                readable = readBuffer.readableBytes();
                deltaSO = ChannelBuffers.wrappedBuffer(deltaSO, readBuffer.slice(readerIndex, readable));
                addFinishedWriteListener(future, readingBuffer);
                readingBuffer.increaseReaders();
                readerIndex += readable;
            }

            return deltaSO;
        }

        private void addFinishedWriteListener(ChannelFuture future, final ReadersAwareBuffer buffer) {
            future.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    buffer.decreaseReaders();
                    if (buffer.isReadyForPool()) {
                        bufferPool.add(buffer);
                    }
                }
            });
        }

        public ZipperState getZipperState() {
            return zipper.getZipperState();
        }

        @Override
        public int compareTo(ReadingBuffer o) {
            return this.channel.compareTo(o.channel);
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof ReadingBuffer))
                return false;
            ReadingBuffer buf = (ReadingBuffer) obj;
            return this.channel.equals(buf.channel);
        }

    }

    public ReadingBuffer getReadingBuffer(ChannelHandlerContext ctx) {
        ReadingBuffer rb = new ReadingBuffer(ctx);
        readingBuffers.add(rb);
        return rb;
    }

    public void removeReadingBuffer(ChannelHandlerContext ctx) {
        readingBuffers.remove(new ReadingBuffer(ctx));
    }

    public void writeCommit(long startTimestamp, long commitTimestamp) {
        checkBufferSpace();
        zipper.encodeCommit(writeBuffer, startTimestamp, commitTimestamp);
    }

    public void writeHalfAbort(long startTimestamp) {
        checkBufferSpace();
        zipper.encodeHalfAbort(writeBuffer, startTimestamp);
    }

    public void writeFullAbort(long startTimestamp) {
        checkBufferSpace();
        zipper.encodeFullAbort(writeBuffer, startTimestamp);
    }

    public void writeLargestIncrease(long largestTimestamp) {
        checkBufferSpace();
        zipper.encodeLargestIncrease(writeBuffer, largestTimestamp);
    }

    private void checkBufferSpace() {
        if (writeBuffer.writableBytes() < MAX_MESSAGE_SIZE) {
            nextBuffer();
        }
    }

    private void nextBuffer() {
        LOG.debug("Switching buffers");

        // mark past buffer as scheduled for pool when all pending operations finish
        pastBuffer.scheduleForPool();

        for (final ReadingBuffer rb : readingBuffers) {
            if (rb.readingBuffer == pastBuffer) {
                ChannelFuture future = Channels.future(rb.channel);
                ChannelBuffer cb = rb.flush(future);
                Channels.write(rb.ctx, future, cb);
            }
        }

        pastBuffer = currentBuffer;
        currentBuffer = bufferPool.poll();
        if (currentBuffer == null) {
            currentBuffer = new ReadersAwareBuffer();
        }
        writeBuffer = currentBuffer.buffer;
    }
}
TOP

Related Classes of com.yahoo.omid.replication.SharedMessageBuffer$ReadingBuffer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.