/*
   * (non-Javadoc)
   *
   * @see com.prashant.memory.MemoryBuffer#store(byte[], int)
   */
  public synchronized Pointer store(byte[] payload, int capacity) throws DMBufferOverFlowException {
    // First good match is page that has capacity equal or greater than
    // payload.
    Pointer goodOne = firstMatch(capacity);
    if (goodOne == null) {
      RuntimeException e = new NullPointerException();
      // logger.error("Did not find a suitable buffer");
      throw new DMBufferOverFlowException("did not find a suitable buffer", e.getCause());
    }

    Pointer fresh = slice(goodOne, capacity);

    fresh.setFree(false);
    used.addAndGet(payload.length);
    ByteBuffer buf = buffer.slice();
    buf.position(fresh.getStart());
    try {
      buf.put(payload);
    } catch (BufferOverflowException e) {
      goodOne.setStart(fresh.getStart());
      goodOne.setEnd(buffer.limit());
      // return null; //Uncomment incase we want to ignore this exception.
      throw new DMBufferOverFlowException(
          "An attempt to store more than the configured capacity", e.getCause());
    }
    pointers.add(fresh);
    return fresh;
  }
 /*
  * (non-Javadoc)
  *
  * @see com.prashant.memory.MemoryBuffer#update(com.prashant.memory.Pointer, byte[], int)
  */
 public void update(Pointer pointer, byte[] payload, int offset)
     throws DMFrameLimitExcededException {
   if (pointer.getStart() + offset + payload.length - 1 <= pointer.getEnd()) {
     ByteBuffer buf;
     synchronized (buffer) {
       buf = buffer.duplicate();
     }
     buf.position(pointer.getStart() + offset);
     buf.put(payload);
     return;
   }
   throw new DMFrameLimitExcededException(
       "Trying to write to a position out of bounds for this pointer.", null);
 }
 /**
  * Resize an existing block to new capacity by slicing the <code>Pointer</code> pointed to by
  * existing pointer. The new <code>Pointer</code> is a slice present before the existing.
  *
  * @param existing points to existing Pointer(referring existing block).
  * @param capacity to be resized to.
  * @return Pointer to resized block.
  */
 private Pointer slice(Pointer existing, int capacity) {
   if ((existing.getEnd() - existing.getStart()) == capacity + 1 && existing.isFree()) {
     return existing;
   }
   Pointer fresh = new Pointer();
   fresh.setBlockNumber(existing.getBlockNumber());
   fresh.setStart(existing.getStart());
   fresh.setEnd(fresh.getStart() + capacity);
   fresh.setFree(true);
   fresh.setPrev(existing.getPrev());
   existing.setPrev(fresh);
   fresh.setNext(existing);
   existing.setStart(existing.getStart() + (capacity + 1));
   return fresh;
 }
 /*
  * (non-Javadoc)
  *
  * @see com.prashant.memory.MemoryBuffer#retrieve(com.prashant.memory.Pointer, int, int)
  */
 public byte[] retrieve(Pointer pointer, int offset, int len) throws DMFrameLimitExcededException {
   int checkLength = pointer.getStart() + offset + len;
   ByteBuffer buf = null;
   if (checkLength <= pointer.getEnd()) {
     synchronized (buffer) {
       buf = buffer.duplicate();
     }
     buf.position(pointer.getStart() + offset);
     final byte[] swp = new byte[len];
     buf.get(swp);
     return swp;
   }
   throw new DMFrameLimitExcededException(
       "Trying to read to a position out of bounds for this pointer.", null);
 }
 /**
  * Returns the block of size equal or greater than current size for reallocation which is marked
  * as free.
  *
  * @param capacity
  * @return null when it fails to search a valid sized block
  */
 private Pointer firstMatch(int capacity) {
   synchronized (pointers) {
     for (Pointer ptr : pointers) {
       // Find a frame with right size. Comapaction problems to be dealt.
       if (ptr.isFree() && (ptr.getEnd() - ptr.getStart()) > capacity) {
         return ptr;
       }
     }
   }
   return null;
 }
 /*
  * (non-Javadoc)
  *
  * @see com.prashant.memory.MemoryBuffer#free(com.prashant.memory.Pointer)
  */
 public long free(Pointer pointer2free) {
   used.addAndGet(-(pointer2free.getEnd() - pointer2free.getStart()));
   freeAndMerge(pointer2free);
   return pointer2free.getEnd() - pointer2free.getStart();
 }
 /*
  * (non-Javadoc)
  *
  * @see com.prashant.memory.MemoryBuffer#retrieve(com.prashant.memory.Pointer)
  */
 public byte[] retrieve(Pointer pointer) throws DMFrameLimitExcededException {
   return retrieve(pointer, 0, pointer.getEnd() - pointer.getStart());
 }