/**
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.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import com.bigdata.cache.ConcurrentWeakValueCache;
import com.bigdata.counters.CounterSet;
import com.bigdata.io.ChecksumUtility;
import com.bigdata.journal.AbstractJournal;
import com.bigdata.journal.BufferMode;
import com.bigdata.journal.ForceEnum;
import com.bigdata.journal.IBufferStrategy;
import com.bigdata.journal.ICommitter;
import com.bigdata.journal.IRootBlockView;
import com.bigdata.journal.RootBlockView;
import com.bigdata.journal.StoreTypeEnum;
import com.bigdata.mdi.IResourceMetadata;
import com.bigdata.rawstore.IAddressManager;
import com.bigdata.rawstore.IAllocationContext;
import com.bigdata.rawstore.IAllocationManagerStore;
import com.bigdata.rawstore.IPSOutputStream;
import com.bigdata.rwstore.IRWStrategy;
import com.bigdata.rwstore.IRawTx;
/**
* A buffer implementation backed by an {@link IMemoryManager}.
*
* @author <a href="mailto:matyncutcher@users.sourceforge.net">Martyn Cutcher</a>
* @version $Id$
*/
public class MemStrategy implements IBufferStrategy, IRWStrategy, IAllocationManagerStore {
final private IMemoryManager m_mmgr;
final private IAddressManager m_am;
private volatile boolean m_modifiable = true;
private volatile boolean m_open = true;
private volatile boolean m_dirty = true;
private volatile IRootBlockView m_rb0 = null;
private volatile IRootBlockView m_rb1 = null;
public MemStrategy(final IMemoryManager mmgr) {
if (mmgr == null)
throw new IllegalArgumentException();
m_mmgr = mmgr;
m_am = new IAddressManager() {
@Override
public int getByteCount(long addr) {
return (int) (0xFFFF & addr);
}
@Override
public long getOffset(long addr) {
return addr >> 32;
}
@Override
public long getPhysicalAddress(final long addr) {
return m_mmgr.getPhysicalAddress(addr);
}
@Override
public long toAddr(int nbytes, long offset) {
return (offset << 32) + nbytes;
}
@Override
public String toString(final long addr) {
return "PhysicalAddress: " + getPhysicalAddress(addr) + ", length: " + getByteCount(addr);
}
};
// initialize RootBlocks
final UUID uuid = UUID.randomUUID(); // Journal's UUID.
final long createTime = System.currentTimeMillis();
final ChecksumUtility checker = new ChecksumUtility();
m_rb0 = new RootBlockView(true, 0,
0, 0, 0, 0, 0, 0,
uuid,
IRootBlockView.NO_BLOCK_SEQUENCE,//
0, 0, 0,
StoreTypeEnum.RW,
createTime, 0, RootBlockView.currentVersion, checker);
m_rb1 = new RootBlockView(false, 0,
0, 0, 0, 0, 0, 0,
uuid,
IRootBlockView.NO_BLOCK_SEQUENCE,//
0, 0, 0,
StoreTypeEnum.RW,
createTime, 0, RootBlockView.currentVersion, checker);
// // store minimum release age
// if (props != null) {
// m_mmgr.setRetention(Long.parseLong(props.getProperty(
// AbstractTransactionService.Options.MIN_RELEASE_AGE,
// AbstractTransactionService.Options.DEFAULT_MIN_RELEASE_AGE)));
// }
}
public IMemoryManager getStore() {
return m_mmgr;
}
// @Deprecated
// public IMemoryManager getMemoryManager() {
// return m_mmgr;
// }
@Override
public void abort() {
// NOP
}
@Override
public void closeForWrites() {
m_modifiable = false;
}
@Override
public void commit() {
// Note: synchronization point moved to postCommit
m_mmgr.commit();
}
@Override
public Lock getCommitLock() {
return m_mmgr.getCommitLock();
}
@Override
public void postCommit() {
m_mmgr.postCommit();
m_dirty = false;
}
@Override
public IAddressManager getAddressManager() {
return m_am;
}
@Override
public BufferMode getBufferMode() {
return BufferMode.MemStore;
}
@Override
synchronized public CounterSet getCounters() {
if (root == null) {
root = new CounterSet();
}
return root;
}
private CounterSet root;
@Override
public long getExtent() {
// return the amount of currently reserved memory
final long ssze = m_mmgr.getSectorSize();
return ssze * m_mmgr.getSectorCount();
}
@Override
public int getHeaderSize() {
// No header
return 0;
}
@Override
public long getInitialExtent() {
return m_mmgr.getSectorSize();
}
@Override
public int getMaxRecordSize() {
return (int) getMaximumExtent();
}
@Override
public long getMaximumExtent() {
final long ssze = m_mmgr.getSectorSize();
return ssze * m_mmgr.getMaxSectors();
}
@Override
public long getMetaBitsAddr() {
// NOP
return 0;
}
@Override
public long getMetaStartAddr() {
// NOP
return 0;
}
@Override
public long getNextOffset() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getOffsetBits() {
return 0;
}
@Override
public long getUserExtent() {
return 0;
}
@Override
public ByteBuffer readRootBlock(boolean rootBlock0) {
return (rootBlock0 ? m_rb0 : m_rb1).asReadOnlyBuffer();
}
@Override
public boolean requiresCommit(IRootBlockView block) {
return m_dirty;
}
@Override
public long transferTo(RandomAccessFile out) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void truncate(long extent) {
throw new UnsupportedOperationException();
}
@Override
public boolean useChecksums() {
return false;
}
@Override
public void writeRootBlock(IRootBlockView rootBlock,
ForceEnum forceOnCommitEnum) {
if (rootBlock.isRootBlock0()) {
m_rb0 = rootBlock;
} else {
m_rb1 = rootBlock;
}
}
@Override
public void close() {
m_open = false;
destroy();
}
@Override
public void delete(long addr) {
if (!m_modifiable) {
throw new IllegalStateException("The store is not modifiable");
}
m_mmgr.free(addr);
m_dirty = true;
}
@Override
public void deleteResources() {
m_mmgr.close();
}
@Override
public void destroy() {
deleteResources();
}
@Override
public void force(boolean metadata) {
// NOP
}
@Override
public File getFile() {
return null;
}
@Override
public IResourceMetadata getResourceMetadata() {
throw new UnsupportedOperationException();
}
@Override
public UUID getUUID() {
throw new UnsupportedOperationException();
}
@Override
public boolean isFullyBuffered() {
return true;
}
@Override
public boolean isOpen() {
return m_open;
}
@Override
public boolean isReadOnly() {
return !m_modifiable;
}
@Override
public boolean isStable() {
return false;
}
@Override
public ByteBuffer read(final long addr) {
return ByteBuffer.wrap(m_mmgr.read(addr));
}
@Override
public long size() {
return getExtent();
}
@Override
public long write(final ByteBuffer data) {
m_dirty = true;
return m_mmgr.allocate(data);
}
// @Override
// public long write(ByteBuffer data, long oldAddr) {
// m_dirty = true;
//
// final long ret = write(data);
//
// m_mmgr.free(oldAddr);
//
// return ret;
// }
// AddressManager delegates
@Override
public int getByteCount(final long addr) {
return m_am.getByteCount(addr);
}
@Override
public long getOffset(final long addr) {
return m_am.getOffset(addr);
}
@Override
public long getPhysicalAddress(final long addr) {
return m_am.getPhysicalAddress(addr);
}
@Override
public long toAddr(final int nbytes, final long offset) {
return m_am.toAddr(nbytes, offset);
}
@Override
public String toString(long addr) {
return m_am.toString(addr);
}
@Override
public IRawTx newTx() {
return m_mmgr.newTx();
}
@Override
public void abortContext(IAllocationContext context) {
m_mmgr.abortContext(context);
}
@Override
public void detachContext(IAllocationContext context) {
m_mmgr.detachContext(context);
}
@Override
public int checkDeferredFrees(final AbstractJournal abstractJournal) {
return m_mmgr.checkDeferredFrees(abstractJournal);
}
@Override
public void delete(long addr, IAllocationContext context) {
m_mmgr.free(addr, context);
}
@Override
public long getLastReleaseTime() {
return m_mmgr.getLastReleaseTime();
}
@Override
public void registerExternalCache(
ConcurrentWeakValueCache<Long, ICommitter> historicalIndexCache,
int byteCount) {
m_mmgr.registerExternalCache(historicalIndexCache, byteCount);
}
@Override
public long saveDeferrals() {
return m_mmgr.saveDeferrals();
}
// @Override
// public long write(ByteBuffer data, long oldAddr, IAllocationContext context) {
// throw new UnsupportedOperationException();
// }
/**
* FIXME There are two unit tests for the {@link MemStore} which are failing
* due to this method not being implemented. Those methods are using an
* abstract task within an isolated action journal context.
*/
@Override
public long write(final ByteBuffer data, final IAllocationContext context) {
return m_mmgr.allocate(data, context);
}
public boolean isCommitted(final long addr) {
return m_mmgr.isCommitted(addr);
}
@Override
public InputStream getInputStream(final long addr) {
return m_mmgr.getInputStream(addr);
}
@Override
public IPSOutputStream getOutputStream() {
return m_mmgr.getOutputStream();
}
@Override
public IPSOutputStream getOutputStream(final IAllocationContext context) {
return m_mmgr.getOutputStream(context);
}
@Override
public boolean isDirty() {
return m_dirty;
}
@Override
public IAllocationContext newAllocationContext(final boolean isolated) {
return m_mmgr.newAllocationContext(isolated);
}
// @Override
// public boolean isFlushed() {
// return true;
// }
// @Override
// public void resetFromHARootBlock(final IRootBlockView rootBlock) {
// throw new UnsupportedOperationException("MemStrategy cannot be used in HA pipeline");
// }
}