/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.bigdata.rwstore.sector;
import java.nio.ByteBuffer;
import com.bigdata.counters.ICounterSetAccess;
import com.bigdata.io.DirectBufferPool;
import com.bigdata.rawstore.IAllocationContext;
import com.bigdata.rawstore.IAllocationManagerStore;
import com.bigdata.rwstore.IAllocationManager;
import com.bigdata.rwstore.IStore;
/**
* Abstraction for managing data in {@link ByteBuffer}s. Typically those buffers
* will be allocated on the native process heap.
* <p>
* <strong>CAUTION: The memory manager helps you manage direct storage. However,
* it does not prevent you from doing something stupid with it.</strong> The
* most likely error is one in which you {@link #get(long)} an address and hold
* onto the returned {@link ByteBuffer} after the data at that address has been
* {@link #free(long) freed}. This can leave you in a position where you are
* reading on (or writing on!) someone else's data on the JVM native heap. The
* memory manager works with {@link DirectBufferPool}s. This class provides the
* efficient reuse of direct allocations, but does not release them back to the
* JVM. For this reason, if you do stomp on someone's memory, it will not be
* memory in use by the JVM but only memory in use by another part of your
* application using the same {@link DirectBufferPool} instance.
*
* @author martyncutcher
*/
public interface IMemoryManager extends IStore, ICounterSetAccess, IAllocationManagerStore {
/**
* Allocates space on the backing resource and copies the provided data.
*
* @param data
* The data will be copied to the backing resource. For each
* buffer in this array, the position will be advanced to the
* limit.
* @param blocks
* When <code>true</code> the request will block until the memory
* is available for the allocation.
*
* @return the address to be passed to the get method to retrieve the data.
*
* @throws IllegalArgumentException
* if <i>data</i> is <code>null</code>.
* @throws IllegalArgumentException
* if {@link ByteBuffer#remaining()} is ZERO (0).
* @throws MemoryManagerResourceError
* If the memory is not available for the allocation and
* <i>blocks:=false</i>. Whether or not this exception can be
* thrown depends on whether the backing buffer pool has a
* bounded capacity and whether the {@link IMemoryManager} using
* that pool has a bounded capacity.
*/
public long allocate(ByteBuffer data, boolean blocks);
/**
* Version of {@link #allocate(ByteBuffer, boolean)} which is either
* blocking or non-blocking depending on whether or not the memory
* manager is set in a blocking mode.
*
* @param data
* The data will be copied to the backing resource. For each
* buffer in this array, the position will be advanced to the
* limit.
*
* @throws IllegalArgumentException
* if <i>data</i> is <code>null</code>.
* @throws IllegalArgumentException
* if {@link ByteBuffer#remaining()} is ZERO (0).
* @throws MemoryManagerResourceError
* If the memory is not available for the allocation and
* <i>blocks:=false</i>. Whether or not this exception can be
* thrown depends on whether the backing buffer pool has a
* bounded capacity and whether the {@link IMemoryManager} using
* that pool has a bounded capacity.
*/
public long allocate(ByteBuffer data);
/**
* Return the address of a new allocation sufficient to store the specified
* number of bytes of application data.
*
* @param nbytes
* The size of the allocation request.
* @param blocks
* When <code>true</code> the method will block until the
* allocation request can be satisfied. When <code>false</code> a
* {@link MemoryManagerOutOfMemory} will be thrown.
*
* @return The address of the allocation.
*
* @throws IllegalArgumentException
* if <i>nbytes</i> is non-positive.
* @throws MemoryManagerResourceError
* If the memory is not available for the allocation and
* <i>blocks:=false</i>. Whether or not this exception can be
* thrown depends on whether the backing buffer pool has a
* bounded capacity and whether the {@link IMemoryManager} using
* that pool has a bounded capacity.
*/
public long allocate(int nbytes, boolean blocks);
/**
* Return the address of a new allocation sufficient to store the specified
* number of bytes of application data. This is the blocking version of
* {@link #allocate(int)}.
*
* @param nbytes
* The size of the allocation request.
* @param blocks
* When <code>true</code> the method will block until the
* allocation request can be satisfied. When <code>false</code> a
* {@link MemoryManagerOutOfMemory} will be thrown.
*
* @return The address of the allocation.
*
* @throws IllegalArgumentException
* if <i>nbytes</i> is non-positive.
* @throws MemoryManagerResourceError
* If the memory is not available for the allocation and
* <i>blocks:=false</i>. Whether or not this exception can be
* thrown depends on whether the backing buffer pool has a
* bounded capacity and whether the {@link IMemoryManager} using
* that pool has a bounded capacity.
*/
public long allocate(int nbytes);
public long allocate(ByteBuffer data, IAllocationContext context);
/**
* Return an array of {@link ByteBuffer}s providing an updatable view onto
* the backing allocation.
* <p>
* The ByteBuffer[] return enables the handling of blobs that span more than
* a single slot, without the need to create an intermediate ByteBuffer.
* This method is designed for use with zero-copy NIO. Furthermore, since
* the {@link ByteBuffer}s in the returned array are not read-only, they can
* be updated directly. In this way the {@link #allocate(int)} can be used
* in conjunction with get to provide more flexibility when storing data.
* <p>
* Using ByteBuffer:put the returned array can be efficiently copied to
* another ByteBuffer:
*
* <pre>
* ByteBuffer mybb;
* ByteBuffer[] bufs = get(addr);
* for (ByteBuffer b : bufs) {
* mybb.put(b);
* }
* </pre>
*
* <strong>CAUTION: Do not hold onto the {@link ByteBuffer} longer than is
* necessary.</strong> If the allocation is released by {@link #free(long)}
* or {@link #clear()}, then the memory backing the {@link ByteBuffer} could
* be reallocated by another {@link DirectBufferPool} consumer.
*
* @param addr
* An previously allocated address.
*
* @return array of ByteBuffers
*/
public ByteBuffer[] get(long addr);
/**
* Return a copy of the data stored at that address. This method is intended
* for use with patterns where the {@link IMemoryManager} is treated as a
* persistence store.
*
* @param addr
* The address.
*
* @return A copy of the data stored at that address.
*/
public byte[] read(long addr);
/**
* Frees the address and makes available for recycling
*
* @param addr
* to be freed
*
* @throws IllegalArgumentException
* If the address is known to be invalid (never written or
* deleted). Note that the address 0L is always invalid as
* is any address which encodes a 0 byte length.
*/
public void free(long addr);
public void free(long addr, IAllocationContext context);
/**
* Clears all current allocations. Clearing an allocation context makes the
* backing heap storage available to immediate reallocation. Clearing the
* allocation context of the top-level {@link IMemoryManager} will release
* any direct {@link ByteBuffer}s back to the pool from which they were
* allocated.
* <p>
* <strong>CAUTION: Do not clear an allocation context until you know that
* all threads with access to that allocation context have either been
* terminated or released their reference to that allocation context.
* </strong>
*/
public void clear();
// public void close();
//
// public void commit();
/**
* Create a child allocation context within which the caller may make and
* release allocations.
*
* TODO Why is the return not an {@link IAllocationContext} as well (that
* is, why does {@link IMemoryManager} not extend {@link IAllocationContext}
* ). Also, note that {@link #commit()} is similar to
* {@link IAllocationManager#detachContext(IAllocationContext)}.
*/
public IMemoryManager createAllocationContext();
/**
* Return the size of the application data for the allocation with the given
* address.
*
* @param addr
* The address.
*
* @return The #of bytes of in the applications allocation request.
*/
public int allocationSize(long addr);
/**
* The #of allocation spanned by this allocation context (including any
* any child allocation contexts).
*/
public long getAllocationCount();
/**
* Return the #of bytes of application data allocated against this
* {@link IMemoryManager} (including any child allocation contexts). Due to
* the overhead of the storage allocation scheme, this value may be smaller
* than {@link #getSlotBytes()}.
*/
public long getUserBytes();
/**
* Return the #of bytes of consumed by allocation slots allocated against
* this {@link IMemoryManager} (including any child allocation contexts).
*/
public long getSlotBytes();
// /**
// * @return an outputstream to stream data to the memory manager and to retrieve
// * an address to later stream the data back.
// */
// public IPSOutputStream getOutputStream();
//
// /**
// * @param context within which any allocations are made by the
// * returned IPSOutputStream
// * @return an outputstream to stream data to and to retrieve
// * an address to later stream the data back.
// */
// public IPSOutputStream getOutputStream(final IAllocationContext context);
//
// /**
// * @return an inputstream for the data for provided address
// */
// public InputStream getInputStream(long addr);
/**
* The size of a backing buffer in bytes.
*/
public int getSectorSize();
/**
* The #of backing buffers in use.
*/
public int getSectorCount();
/**
* The maximum number of backing buffers which may be allocated by the
* {@link IMemoryManager} and {@link Integer#MAX_VALUE} if there is no
* effective limit on the #of backing buffers which may be allocated.
*/
public int getMaxSectors();
// public long saveDeferrals();
// public long getLastReleaseTime();
// public void abortContext(IAllocationContext context);
//
// public void detachContext(IAllocationContext context);
//
// public void registerContext(IAllocationContext context);
// public void setRetention(long parseLong);
/**
* Return <code>true</code> iff the allocation having that address is
* flagged as committed. The caller must be holding the allocation lock in
* order for the result to remain valid outside of the method call.
*
* @param addr
* The address.
*
* @return <code>true</code> iff the address is currently committed.
*/
public boolean isCommitted(long addr);
/**
* Determine the unencoded physical address
*
* @param addr
* The encoded address
*
* @return an unencoded address offset
*/
public long getPhysicalAddress(long addr);
}