/** 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); }