/**
  * 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#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;
  }
  /**
   * It is synchronized as it does merging of adjacent blocks. An easiest way to somewhat address
   * fragmentation problem.
   *
   * @param pointer2free
   */
  private void freeAndMerge(Pointer pointer2free) {
    synchronized (pointers) {
      pointers.remove(pointer2free);
      // merge adjacent blocks
      if (null != pointer2free.getPrev() && pointer2free.getPrev().isFree()) {
        // Merge previous
        pointers.remove(pointer2free.getPrev());
        pointer2free.setStart(pointer2free.getPrev().getStart());
        pointer2free.setPrev(pointer2free.getPrev().getPrev());
        // Recursive call
        freeAndMerge(pointer2free);
      }

      if (null != pointer2free.getNext() && pointer2free.getNext().isFree()) {
        // Merge Next
        pointers.remove(pointer2free.getNext());
        pointer2free.setEnd(pointer2free.getNext().getEnd());
        pointer2free.setNext(pointer2free.getNext().getNext());
        // Recursive call
        freeAndMerge(pointer2free);
      }
      if (!pointer2free.isFree()) {
        pointer2free.setFree(true);
        pointer2free.setClazz(null);
        pointers.add(pointer2free);
      }
    }
  }
 private Pointer createAndAddFirstPointer() {
   Pointer first = new Pointer();
   first.setBlockNumber(0);
   first.setStart(0);
   first.setFree(true);
   first.setEnd(buffer.capacity() - 1);
   first.setNext(null);
   first.setPrev(null);
   pointers.add(first);
   return first;
 }