com.mellanox.jxio.MsgPool.java Source code

Java tutorial

Introduction

Here is the source code for com.mellanox.jxio.MsgPool.java

Source

/*
 ** Copyright (C) 2013 Mellanox Technologies
 **
 ** 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.
 **
 */
package com.mellanox.jxio;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.mellanox.jxio.impl.Bridge;

/**
 * Both client and server use MsgPool (different instance of the same object).
 * Server side must bind the pool to EventQueueHandler.
 * Each Msg in MsgPool will be zero copied via the RDMA transport to the remote peer.
 * <p>
 * On ServerSize the capacity should be bigger by 64 than on Client Size. InSize and outSize for client and server need
 * to be reversed. For example:
 * <p>
 * Client: MsgPool p1 = new MsgPool(100, 8192, 64)
 * <p>
 * Server: MsgPool p2 = new MsgPool(164, 64, 8192)
 */
public class MsgPool {
    private static final Log LOG = LogFactory.getLog(MsgPool.class.getCanonicalName());
    public static final int MAX_CAPACITY = 100064;
    private final int capacity;
    private final int inSize;
    private final int outSize;
    private final ByteBuffer buffer;
    private final long refToCObject;
    List<Msg> listMsg = new ArrayList<Msg>();
    // this flag indicated if this pool is already bound to eqh
    private boolean already_bound;

    /**
     * Constructor of MsgPool. Creates MsgPool (including allocating and RDMA registering the memory in C).
     * 
     * @param capacity
     *            - number of msg that this pool will contain. Max is {@value MAX_CAPACITY}
     * @param inSize
     *            - size (in bytes) of the receive buffer. For client this will be the response from the server
     *            and for the server this will be the request from the client
     * @param outSize
     *            - size (in bytes) of the send buffer. For client this will be the request to the server
     *            and for the server this will be the response to the client.
     * 
     */
    public MsgPool(int capacity, int inSize, int outSize) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("MP CTOR entry");
        }
        if (capacity > MsgPool.MAX_CAPACITY) {
            LOG.warn("Can't create pool with capacity bigger than maximum. Creating pool with capacity "
                    + MsgPool.MAX_CAPACITY);
            this.capacity = MsgPool.MAX_CAPACITY;
        } else {
            this.capacity = capacity;
        }
        this.inSize = inSize;
        this.outSize = outSize;
        long refToCObjects[] = new long[this.capacity + 1]; // the first element represents the id of MsgPool
        buffer = Bridge.createMsgPool(this.capacity, inSize, outSize, refToCObjects);
        if (buffer == null) {
            LOG.fatal("there was an error creating the MsgPool");
            refToCObject = 0;
            return;
            // TODO: throw exception
        }
        refToCObject = refToCObjects[0];
        int msgBufferSize = inSize + outSize;

        for (int i = 0; i < this.capacity; i++) {
            buffer.position(msgBufferSize * i);
            ByteBuffer partialBuffer = buffer.slice();
            partialBuffer.limit(msgBufferSize);
            Msg m = new Msg(partialBuffer, inSize, outSize, refToCObjects[i + 1], this);
            listMsg.add(m);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug(this.toLogString() + "MP CTOR done");
        }
    }

    /**
     * Returns true if this MsgPool is empty
     * 
     * @return true if this MsgPool is empty
     */
    public boolean isEmpty() {
        return listMsg.size() == 0;
    }

    /**
     * Returns the number of Msgs this MsgPool was created with.
     */
    public int capacity() {
        return this.capacity;
    }

    /**
     * Returns the number of Msgs the in this MsgPool.
     * 
     * @return number of Msgs in MsgPool
     */
    public int count() {
        return listMsg.size();
    }

    /**
     * Returns a Msg from the pool (or null if pool is empty).
     * This method should be called on client side.
     * 
     * @return Msg from the pool (or null if pool is empty).
     */
    public Msg getMsg() {
        if (listMsg.isEmpty()) {
            LOG.warn(this.toLogString() + "there are no more messages in pool");
            return null;
        }
        Msg msg = listMsg.remove(0);
        msg.setMsgReturnable();
        return msg;
    }

    /**
     * Returns msg back to pool.
     * This method should be called on client side, once the application
     * finished handling the msg. This method should only be called for Msg that
     * was obtained by MsgPool.getMsg() method
     * 
     * @param msg
     *            to be returned back to pool
     * @return true if Msg was returned to pool and false if this msg can not be returned to pool
     */
    public boolean releaseMsg(Msg msg) {
        if (msg.getParentPool() == this) {
            if (msg.isReturnable()) {
                msg.resetPositions();
                msg.setMsgNotReturnable();
                listMsg.add(msg);
                return true;
            } else {
                LOG.error(this.toLogString() + "Msg " + msg.toString()
                        + " can not be returned to pool, since it was not obtained using pool.getMsg method");
                return false;
            }
        }
        LOG.error(this.toLogString() + "parent pool " + msg.getParentPool().getId() + " and actual msg pool "
                + this.getId() + " do not match!");
        return false;
    }

    /**
     * Returns id of the object. The id is unique and represents pointer
     * to the corresponding C object.
     * 
     * @return id of the object
     */
    public long getId() {
        return refToCObject;
    }

    /**
     * Deletes this MsgPool. This method releases all memory allocated in C
     * and therefore this should be the last method called for this MsgPool
     */
    public void deleteMsgPool() {
        Bridge.deleteMsgPool(refToCObject);
    }

    List<Msg> getAllMsg() {
        return listMsg;
    }

    boolean isBounded() {
        return already_bound;
    }

    void setIsBounded(boolean already_bound) {
        this.already_bound = already_bound;
    }

    int getInSize() {
        return this.inSize;
    }

    int getOutSize() {
        return this.outSize;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("jxio.MsgPool(" + Long.toHexString(refToCObject) + ")");
        sb.append("[count=" + count());
        sb.append(", capacity=" + capacity);
        sb.append(", inSize=" + inSize);
        sb.append(", outSize=" + outSize + "]");
        return sb.toString();
    }

    private String toLogString() {
        return this.toString() + ": ";
    }
}