Package com.cetsoft.imcache.bytebuffer

Source Code of com.cetsoft.imcache.bytebuffer.OffHeapByteBuffer$Allocation

/*
* Copyright (C) 2013 Cetsoft, http://www.cetsoft.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Author : Yusuf Aytas
* Date   : Sep 22, 2013
*/
package com.cetsoft.imcache.bytebuffer;

import java.nio.BufferOverflowException;
import java.util.concurrent.atomic.AtomicInteger;

import com.cetsoft.imcache.concurrent.lock.StripedReadWriteLock;

/**
* The Class OffHeapByteBuffer.
*/
public class OffHeapByteBuffer implements OffHeapStore{
 
  /** The index. */
  private volatile int index;
  /** The capacity. */
  private volatile long capacity;
 
  /** The direct byte buffer. */
  private DirectByteBuffer directByteBuffer;
 
  /** The read write lock. */
  private StripedReadWriteLock readWriteLock;
 
  /** The Constant DEFAULT_CONCURRENCY_LEVEL. */
  public final static int DEFAULT_CONCURRENCY_LEVEL = 4;
 
  /** The Constant POINTER_SIZE. */
  private final static int POINTER_SIZE = 5;
 
  /** The offset. */
  private AtomicInteger offset = new AtomicInteger(0);
 
  /** The used memory. */
  private AtomicInteger usedMemory = new AtomicInteger(0);
 
  /** The dirty memory. */
  private AtomicInteger dirtyMemory = new AtomicInteger(0);
 
  /** The Constant USED. */
  private final static byte USED = 1;
 
  /** The Constant FREE. */
  private final static byte FREE = 0;
 
  /** The Constant DIRTY. */
  private final static byte DIRTY = -1;
 
  /**
   * Instantiates a new off heap byte buffer.
   *
   * @param index the index
   * @param capacity the capacity
   */
  public OffHeapByteBuffer(int index, int capacity){
    this(index, capacity, DEFAULT_CONCURRENCY_LEVEL);
  }
 
  /**
   * Instantiates a new off heap byte buffer.
   *
   * @param index the index
   * @param capacity the capacity
   * @param concurrencyLevel the concurrency level
   */
  public OffHeapByteBuffer(int index, int capacity, int concurrencyLevel){
    this.index = index;
    this.capacity = capacity;
    directByteBuffer = new DirectByteBuffer(capacity);
    readWriteLock = new StripedReadWriteLock(concurrencyLevel);
  }

  /* (non-Javadoc)
   * @see com.cetsoft.imcache.bytebuffer.OffHeapStore#retrieve(com.cetsoft.imcache.bytebuffer.Pointer)
   */
  public byte[] retrieve(Pointer pointer) {
    readWriteLock.readLock(pointer.getPosition());
    try{
      byte [] header = new byte[POINTER_SIZE];
      directByteBuffer.get(pointer.getPosition(), header, 0, POINTER_SIZE);
      int length = header(header);
      byte [] payload = new  byte[length];
      directByteBuffer.get(pointer.getPosition()+POINTER_SIZE, payload, 0, length);
      pointer.setAccessTime(System.currentTimeMillis());
      return payload;
    }finally{
      readWriteLock.readUnlock(pointer.getPosition());
    }
  }
 
  /* (non-Javadoc)
   * @see com.cetsoft.imcache.bytebuffer.OffHeapStore#remove(com.cetsoft.imcache.bytebuffer.Pointer)
   */
  public byte[] remove(Pointer pointer) {
    readWriteLock.writeLock(pointer.getPosition());
    try{
      byte [] payload = retrieve(pointer);
      markAsDirty(pointer.getPosition());
      return payload;
    }finally{
      readWriteLock.writeUnlock(pointer.getPosition());
    }
  }

  /* (non-Javadoc)
   * @see com.cetsoft.imcache.bytebuffer.OffHeapStore#store(byte[])
   */
  public Pointer store(byte[] payload) {
    Allocation allocation = allocate(payload);
    Pointer pointer = store(allocation, payload);
    return pointer;
  }
 
  /**
   * Stores the payload by the help of allocation.
   *
   * @param allocation the allocation
   * @param payload the payload
   * @return the pointer
   */
  public Pointer store(Allocation allocation, byte[] payload) {
    usedMemory.addAndGet(allocation.getLength());
    Pointer pointer = new Pointer(allocation.getOffset(), this);
    byte [] header = header(payload.length);
    directByteBuffer.put(allocation.getOffset(), header, 0, POINTER_SIZE);
    directByteBuffer.put(allocation.getOffset()+POINTER_SIZE, payload, 0, allocation.getLength()-POINTER_SIZE);
    return pointer;
  }
 
  /* (non-Javadoc)
   * @see com.cetsoft.imcache.bytebuffer.OffHeapStore#update(com.cetsoft.imcache.bytebuffer.Pointer, byte[])
   */
  public Pointer update(Pointer pointer, byte[] payload) {
    readWriteLock.writeLock(pointer.getPosition());
    try{
      byte[] exPayload = retrieve(pointer);
      if(exPayload.length>=payload.length){
        // Note that updated payload should be always less than exPayload,
        // otherwise new location is allocated.
        dirtyMemory.addAndGet(exPayload.length-payload.length);
        Allocation allocation = new Allocation(pointer.getPosition(), payload.length+POINTER_SIZE);
        return store(allocation,payload);
      }else{
        dirtyMemory.addAndGet(exPayload.length+POINTER_SIZE);
        markAsDirty(pointer.getPosition());
        return store(payload);
      }
    }finally{
      readWriteLock.writeUnlock(pointer.getPosition());
   
  }
 
  /**
   * Calculates the header bytes from the length.
   *
   * @param length the length
   * @return the byte[]
   */
  protected byte[] header(int length){
    byte[] header = new byte[5];
    header[0] = USED;
    header[1] = (byte) ((length >>> 24) & 0xFF);
    header[2] = (byte) ((length >>> 16) & 0xFF);
    header[3] = (byte) ((length >>> 8) & 0xFF);
    header[4] = (byte) ((length >>> 0) & 0xFF);
    return header;
  }
 
  /**
   * Calculates the header length from the bytes.
   *
   * @param header the header
   * @return the int
   */
  protected int header(byte [] header){
    if(header[0]==DIRTY){
      throw new OffHeapByteBufferException("Object is dirty!");
    }
    else if(header[0]==FREE){
      throw new OffHeapByteBufferException("Object is free!");
    }
    else if(header[0]!=USED){
      throw new OffHeapByteBufferException("Wrong header!");
    }
    int length = ((header[1]) << 24) | ((header[2] & 0xff) << 16) | ((header[3] & 0xff) << 8) | ((header[4] & 0xff));
    return length;
  }
 
  /**
   * Mark as dirty.
   *
   * @param offset the offset
   */
  protected void markAsDirty(int offset){
    byte[] dirtyMark = {DIRTY};
    directByteBuffer.put(offset, dirtyMark, 0, 1);
  }

  /**
   * Allocates memory for the payload.
   *
   * @param payload the payload
   * @return the allocation
   */
  protected Allocation allocate(byte[] payload) {
    int payloadLength = payload.length+POINTER_SIZE;
    int allocationOffset = offset.addAndGet(payloadLength);
    if(this.capacity<allocationOffset){
      throw new BufferOverflowException();
    }
    Allocation allocation = new Allocation(allocationOffset-payloadLength, payloadLength);
    return allocation;
  }
 
  /**
   * Frees the buffer.
   */
  public void free(){
    directByteBuffer.free();
  }
 
  /* (non-Javadoc)
   * @see com.cetsoft.imcache.bytebuffer.OffHeapStore#dirtyMemory()
   */
  public long dirtyMemory() {
    return dirtyMemory.get();
  }

  /* (non-Javadoc)
   * @see com.cetsoft.imcache.bytebuffer.OffHeapStore#usedMemory()
   */
  public long usedMemory() {
    return usedMemory.get();
  }

  /* (non-Javadoc)
   * @see com.cetsoft.imcache.bytebuffer.OffHeapStore#freeMemory()
   */
  public long freeMemory() {
    return capacity-(dirtyMemory()+usedMemory());
  }
 
  /**
   * The Class Allocation.
   */
  private static class Allocation {
   
    /** The offset. */
    private int offset;
   
    /** The length. */
    private int length;
   
    /**
     * Instantiates a new allocation.
     *
     * @param offset the offset
     * @param length the length
     */
    public Allocation(int offset, int length) {
      this.offset = offset;
      this.length = length;
    }
   
    /**
     * Gets the offset.
     *
     * @return the offset
     */
    public int getOffset() {
      return offset;
    }
   
    /**
     * Gets the length.
     *
     * @return the length
     */
    public int getLength() {
      return length;
    }
  }

  /**
   * Gets the index.
   *
   * @return the index
   */
  public int getIndex() {
    return index;
  }
}
TOP

Related Classes of com.cetsoft.imcache.bytebuffer.OffHeapByteBuffer$Allocation

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.