package com.neocoretechs.bigsack.io;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import com.neocoretechs.bigsack.DBPhysicalConstants;
import com.neocoretechs.bigsack.io.cluster.IOWorkerInterface;
import com.neocoretechs.bigsack.io.pooled.BlockAccessIndex;
import com.neocoretechs.bigsack.io.pooled.BlockStream;
import com.neocoretechs.bigsack.io.pooled.Datablock;
import com.neocoretechs.bigsack.io.pooled.GlobalDBIO;
import com.neocoretechs.bigsack.io.pooled.MappedBlockBuffer;
import com.neocoretechs.bigsack.io.pooled.ObjectDBIO;
import com.neocoretechs.bigsack.io.request.CommitRequest;
import com.neocoretechs.bigsack.io.request.FSeekAndReadFullyRequest;
import com.neocoretechs.bigsack.io.request.FSeekAndReadRequest;
import com.neocoretechs.bigsack.io.request.FSeekAndWriteFullyRequest;
import com.neocoretechs.bigsack.io.request.FSeekAndWriteRequest;
import com.neocoretechs.bigsack.io.request.FsizeRequest;
import com.neocoretechs.bigsack.io.request.GetNextFreeBlockRequest;
import com.neocoretechs.bigsack.io.request.GetNextFreeBlocksRequest;
import com.neocoretechs.bigsack.io.request.FSyncRequest;
import com.neocoretechs.bigsack.io.request.IoRequestInterface;
import com.neocoretechs.bigsack.io.request.iomanager.AddBlockAccessNoReadRequest;
import com.neocoretechs.bigsack.io.request.iomanager.DirectBufferWriteRequest;
import com.neocoretechs.bigsack.io.request.iomanager.FindOrAddBlockAccessRequest;
import com.neocoretechs.bigsack.io.request.iomanager.ForceBufferClearRequest;
import com.neocoretechs.bigsack.io.request.iomanager.GetUsedBlockRequest;
/**
* Handles the aggregation of the IO worker threads of which there is one for each tablespace.
* Requests are queued to the IO worker assigned to the tablespace desired and can operate in parallel
* with granularity at the tablespace/randomaccessfile level. This is asynchronous IO on random access files
* either memory mapped or filesystem.
* When we need to cast a global operation which requires all tablespaces to coordinate a response we use
* the CyclicBarrier class to set up the rendezvous with each IOworker and its particular request to the
* set of all IO workers.
* Copyright (C) NeoCoreTechs 2014,2015
* @author jg
*
*/
public class MultithreadedIOManager implements IoManagerInterface {
private static final boolean DEBUG = false;
private static final boolean DEBUG2 = false;
private static final boolean DEBUGWRITE = false; // view blocks written to log and store
public ObjectDBIO globalIO;
// barrier synch for specific functions, cyclic (reusable)
protected final CyclicBarrier forceBarrierSynch = new CyclicBarrier(DBPhysicalConstants.DTABLESPACES);
protected final CyclicBarrier nextBlocksBarrierSynch = new CyclicBarrier(DBPhysicalConstants.DTABLESPACES);
protected final CyclicBarrier commitBarrierSynch = new CyclicBarrier(DBPhysicalConstants.DTABLESPACES);
protected final CyclicBarrier directWriteBarrierSynch = new CyclicBarrier(DBPhysicalConstants.DTABLESPACES);
protected IOWorkerInterface ioWorker[];
protected int L3cache = 0;
protected long[] nextFree = new long[DBPhysicalConstants.DTABLESPACES];
protected MappedBlockBuffer[] blockBuffer; // block number to Datablock
protected RecoveryLogManager[] ulog;
protected BlockStream[] lbai = new BlockStream[DBPhysicalConstants.DTABLESPACES];
public MultithreadedIOManager(ObjectDBIO globalIO) throws IOException {
this.globalIO = globalIO;
assignIoWorker();
blockBuffer = new MappedBlockBuffer[DBPhysicalConstants.DTABLESPACES];
ulog = new RecoveryLogManager[DBPhysicalConstants.DTABLESPACES];
// Initialize the thread pool group NAMES to spin new threads in controllable batches
ThreadPoolManager.init(new String[]{"BLOCKPOOL","IOWORKER"}, false);
setNextFreeBlocks();
}
protected void assignIoWorker() {
ioWorker = new IOWorker[DBPhysicalConstants.DTABLESPACES];
}
/**
* Return the MappedBlockBuffer for the tablespace
*/
public MappedBlockBuffer getBlockBuffer(int tblsp) { return blockBuffer[tblsp]; }
/**
* Return the block access index and db buffered stream for this tablespace
* @param tblsp
* @return
*/
public BlockStream getBlockStream(int tblsp) { return lbai[tblsp]; }
public RecoveryLogManager getUlog(int tablespace) {
return ulog[tablespace];
}
public void setUlog(int tablespace, RecoveryLogManager ulog) {
this.ulog[tablespace] = ulog;
}
/**
* Find or add the block to in-mem list. First deallocate the currently
* used block, get the new block, then allocate it
* @param tbn The virtual block
* @exception IOException If low-level access fails
*/
public int findOrAddBlock(long tbn) throws IOException {
int tblsp = GlobalDBIO.getTablespace(tbn);
if( DEBUG )
System.out.println("MultithreadedIoManager.findOrAddBlock tablespace "+tblsp+" pos:"+GlobalDBIO.valueOf(tbn)+" current:"+lbai[tblsp]);
// If the current entry is the one we are looking for, set byteindex to 0 and return
// if not, call 'dealloc' and find our target
lbai[tblsp].setLbai(blockBuffer[tblsp].findOrAddBlock(tbn));
return tblsp;
}
public int deleten(Optr adr, int osize) throws IOException {
int tblsp = objseek(adr);
blockBuffer[tblsp].deleten(lbai[tblsp].getLbai(), osize);
return tblsp;
}
/**
* objseek - seek to offset within block
* @param adr block/offset to seek to
* @exception IOException If problem seeking block
* @see Optr
*/
public int objseek(Optr adr) throws IOException {
if (adr.getBlock() == -1L)
throw new IOException("Sentinel block seek error");
int tblsp = findOrAddBlock(adr.getBlock());
lbai[tblsp].getLbai().setByteindex(adr.getOffset());
return tblsp;
}
/**
* objseek - seek to offset within block
* @param adr long block to seek to
* @return the tablespace extracted from passed pointer
* @exception IOException If problem seeking block
* @see Optr
*/
public int objseek(long adr) throws IOException {
assert(adr != -1L) : "MultithreadedIOManager objseek Sentinel block seek error";
int tblsp = findOrAddBlock(adr);
lbai[tblsp].getLbai().setByteindex((short) 0);
return tblsp;
}
/**
* Get the new node position for clustered entries. If we have values associated with keys we store
* the values in alternate blocks from the BTree page. This method delivers the block to pack
* For sets vs maps, we store only the serialized keys clustered on the page
* determine location of new node, store in new_node_pos.
* Attempts to cluster entries in used blocks near insertion point
* @return The Optr pointing to the new node position
* @exception IOException If we cannot get block for new node
*/
public synchronized Optr getNewNodePosition(int tblsp) throws IOException {
if( DEBUG2 )
System.out.println("MultithreadedIOManager.getNewNodePosition "+tblsp+" "+lbai[tblsp]);
return blockBuffer[tblsp].getNewNodePosition(lbai[tblsp].getLbai());
}
public synchronized void setNewNodePosition(long newPos) {
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#getNextFreeBlock(int)
*/
@Override
public synchronized long getNextFreeBlock(int tblsp) throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.getNextFreeBlock "+tblsp);
CountDownLatch barrierCount = new CountDownLatch(1);
IoRequestInterface iori = new GetNextFreeBlockRequest(barrierCount, nextFree[tblsp]);
ioWorker[tblsp].queueRequest(iori);
try {
barrierCount.await();
} catch (InterruptedException e) {}
nextFree[tblsp] = iori.getLongReturn();
return nextFree[tblsp];
}
/**
* Return the reverse scan of the first free block of each tablespace
* queue the request to the proper ioworker, they wait at barrier synch,
* then activate countdown latch to signal main. Result in placed in class level nextFree
* @exception IOException if IO problem
*/
private void getNextFreeBlocks() throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.getNextFreeBlocks ");
CountDownLatch barrierCount = new CountDownLatch(DBPhysicalConstants.DTABLESPACES);
IoRequestInterface[] iori = new IoRequestInterface[DBPhysicalConstants.DTABLESPACES];
// queue to each tablespace
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
iori[i] = new GetNextFreeBlocksRequest(nextBlocksBarrierSynch, barrierCount);
ioWorker[i].queueRequest(iori[i]);
}
try {
barrierCount.await();
} catch (InterruptedException e) {}
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
nextFree[i] = iori[i].getLongReturn();
}
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#FseekAndWrite(long, com.neocoretechs.bigsack.io.pooled.Datablock)
*/
@Override
public synchronized void FseekAndWrite(long toffset, Datablock tblk) throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.FseekAndWrite "+toffset);
int tblsp = GlobalDBIO.getTablespace(toffset);
long offset = GlobalDBIO.getBlock(toffset);
CountDownLatch barrierCount = new CountDownLatch(1);
IoRequestInterface iori = new FSeekAndWriteRequest(barrierCount, offset, tblk);
// no need to wait, let the queue handle serialization
ioWorker[tblsp].queueRequest(iori);
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#FseekAndWriteFully(long, com.neocoretechs.bigsack.io.pooled.Datablock)
*/
@Override
public synchronized void FseekAndWriteFully(long toffset, Datablock tblk) throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.FseekAndWriteFully "+toffset);
int tblsp = GlobalDBIO.getTablespace(toffset);
long offset = GlobalDBIO.getBlock(toffset);
CountDownLatch barrierCount = new CountDownLatch(1);
IoRequestInterface iori = new FSeekAndWriteFullyRequest(barrierCount, offset, tblk);
ioWorker[tblsp].queueRequest(iori);
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#FseekAndRead(long, com.neocoretechs.bigsack.io.pooled.Datablock)
*/
@Override
public synchronized void FseekAndRead(long toffset, Datablock tblk) throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.FseekAndRead "+GlobalDBIO.valueOf(toffset));
//if( GlobalDBIO.valueOf(toffset).equals("Tablespace_1_114688"))
// System.out.println("MultithreadedIOManager.FseekAndRead Tablespace_1_114688");
int tblsp = GlobalDBIO.getTablespace(toffset);
long offset = GlobalDBIO.getBlock(toffset);
CountDownLatch barrierCount = new CountDownLatch(1);
IoRequestInterface iori = new FSeekAndReadRequest(barrierCount, offset, tblk);
ioWorker[tblsp].queueRequest(iori);
try {
barrierCount.await();
} catch (InterruptedException e) {}
//if( GlobalDBIO.valueOf(toffset).equals("Tablespace_1_114688"))
// System.out.println("MultithreadedIOManager.FseekAndRead EXIT Tablespace_1_114688 "+tblk+" dump:"+tblk.blockdump());
//assert(tblk.getBytesused() != 0 && tblk.getBytesinuse() != 0) : "MultithreadedIOManager.FseekAndRead returned unusable block from offset "+GlobalDBIO.valueOf(toffset)+" "+tblk.blockdump();
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#FseekAndReadFully(long, com.neocoretechs.bigsack.io.pooled.Datablock)
*/
@Override
public synchronized void FseekAndReadFully(long toffset, Datablock tblk) throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.FseekAndReadFully "+toffset);
int tblsp = GlobalDBIO.getTablespace(toffset);
long offset = GlobalDBIO.getBlock(toffset);
CountDownLatch barrierCount = new CountDownLatch(1);
IoRequestInterface iori = new FSeekAndReadFullyRequest(barrierCount, offset, tblk);
ioWorker[tblsp].queueRequest(iori);
try {
barrierCount.await();
} catch (InterruptedException e) {}
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#setNextFreeBlocks()
*/
@Override
public synchronized void setNextFreeBlocks() {
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++)
if (i == 0)
nextFree[i] = ((long) DBPhysicalConstants.DBLOCKSIZ);
else
nextFree[i] = 0L;
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#firstTableSpace()
*/
@Override
public long firstTableSpace() throws IOException {
return 0L;
}
/**
* Use the parallel getNextFreeBlocks to return the free array, then find
* the smallest element in the array. utility method since we use simple random numbers to
* tablespaces for new blocks
* @see com.neocoretechs.bigsack.io.IoManagerInterface#findSmallestTablespace()
*/
@Override
public synchronized int findSmallestTablespace() throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.findSmallestTablespace ");
// always make sure we have primary
long primarySize = Fsize(0);
int smallestTablespace = 0; // default main
long smallestSize = primarySize;
getNextFreeBlocks();
for (int i = 0; i < nextFree.length; i++) {
if(nextFree[i] != -1 && GlobalDBIO.getBlock(nextFree[i]) < smallestSize) {
smallestSize = GlobalDBIO.getBlock(nextFree[i]);
smallestTablespace = i;
}
}
return smallestTablespace;
}
/**
* Invoke each tablespace open request by creating buffers and spinning workers.
* @see com.neocoretechs.bigsack.io.IoManagerInterface#Fopen(java.lang.String, int, boolean)
*/
@Override
public synchronized boolean Fopen(String fname, int L3cache, boolean create) throws IOException {
this.L3cache = L3cache;
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
ioWorker[i] = new IOWorker(translateDb(fname,i), i, L3cache);
blockBuffer[i] = new MappedBlockBuffer(this, i);
lbai[i] = new BlockStream(i, blockBuffer[i]);
ulog[i] = new RecoveryLogManager(globalIO,i);
ThreadPoolManager.getInstance().spin((Runnable)ioWorker[i],"IOWORKER");
ThreadPoolManager.getInstance().spin(blockBuffer[i], "BLOCKPOOL");
// attempt recovery if needed
ulog[i].getLogToFile().recover();
}
// fill in the next free block indicators and set the smallest tablespace
findSmallestTablespace();
return true;
}
/** (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#Fopen(java.lang.String, int, boolean)
*
* This is where the recovery logs are initialized because the logs operate at the block (database page) level.
* When this module is instantiated the RecoveryLogManager is assigned to 'ulog' and a roll forward recovery
* is started. If there are any records in the log file they will scanned for low water marks and
* checkpoints etc and the determination is made based on the type of log record encountered.
* Our log granularity is the page level. We store DB blocks and their original mirrors to use in
* recovery. At the end of recovery we restore the logs to their initial state, as we do on a commit.
* There is a simple paradigm at work here, we carry a single block access index in another class and use it
* to cursor through the blocks as we access them. The BlockStream class has the BlockAccessIndex and DBStream
* for each tablespace. The cursor window block and read and written from seep store and buffer pool.
*/
@Override
public synchronized boolean Fopen(String fname, String remote, int L3cache, boolean create) throws IOException {
this.L3cache = L3cache;
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
if( remote == null )
ioWorker[i] = new IOWorker(translateDb(fname,i), i, L3cache);
else
ioWorker[i] = new IOWorker(translateDb(fname,i), translateDb(remote,i), i, L3cache);
blockBuffer[i] = new MappedBlockBuffer(this, i);
lbai[i] = new BlockStream(i, blockBuffer[i]);
ulog[i] = new RecoveryLogManager(globalIO,i);
ThreadPoolManager.getInstance().spin((Runnable)ioWorker[i], "IOWORKER");
ThreadPoolManager.getInstance().spin(blockBuffer[i], "BLOCKPOOL");
// attempt recovery if needed
ulog[i].getLogToFile().recover();
}
// fill in the next free block indicators and set the smallest tablespace
findSmallestTablespace();
return true;
}
/**
* Deallocate the outstanding block and call commit on the recovery log
* @throws IOException
*/
public synchronized void deallocOutstandingCommit() throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.deallocOutstandingCommit invoked.");
commitBufferFlush(); // calls iomanager
deallocOutstanding();
}
/**
* Deallocate the outstanding block and call rollback on the recovery log
* @throws IOException
*/
public void deallocOutstandingRollback() throws IOException {
synchronized( lbai ) {
for(int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
if( lbai[i] != null & lbai[i].getLbai() != null ) {
lbai[i].getLbai().decrementAccesses();
forceBufferClear();
ulog[i].rollBack();
ulog[i].stop();
((IoInterface)ioWorker[i]).Fclose();
}
}
}
}
/**
* dealloc outstanding blocks. if not null, do a dealloc and set null
* @throws IOException
*/
public void deallocOutstanding() throws IOException {
synchronized(lbai) {
for(int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
if( lbai[i] != null ) {
if( lbai[i].getLbai() != null )
lbai[i].getLbai().decrementAccesses();
}
}
}
}
/**
* Deallocate the outstanding BlockAccesIndex from the virtual block number. First
* check the outstanding buffers per tablespace, then consult the block buffer failing that.
* If we find nothing in the buffers, there is obviously nothing to unlatch.
* @param pos The virtual block number to deallocate.
* @throws IOException
*/
public void deallocOutstanding(long pos) throws IOException {
int tablespace = GlobalDBIO.getTablespace(pos);
if( lbai[tablespace].getLbai().getBlockNum() == pos ) {
if( lbai[tablespace].getLbai().getBlk().isIncore() ) {
//deallocOutstandingWriteLog(tablespace, lbai[tablespace].getLbai());
} else
lbai[tablespace].getLbai().decrementAccesses();
if( DEBUG )
System.out.println("MultithreadedIOManager.deallocOutstanding current "+GlobalDBIO.valueOf(pos));
} else {
BlockAccessIndex bai = blockBuffer[tablespace].get(pos);
if( bai != null) {
if( bai.getBlk().isIncore() ) {
//deallocOutstandingWriteLog(tablespace, bai);
} else
bai.decrementAccesses();
} else {
//System.out.println("MultithreadedIOManager WARNING!! FAILED TO DEALLOCATE "+GlobalDBIO.valueOf(pos));
//new Throwable().printStackTrace();
}
}
}
/**
* Deallocate the outstanding block and write it to the log. To be eligible for write it must be incore, have
* accesses = 1 (latched) and and NOT yet in log.
*/
public void deallocOutstandingWriteLog(int tablespace, BlockAccessIndex lbai) throws IOException {
if( lbai.getAccesses() == 1 && lbai.getBlk().isIncore() && !lbai.getBlk().isInlog()) {
// will set incore, inlog, and push to raw store via applyChange of Loggable
ulog[tablespace].writeLog(lbai);
lbai.decrementAccesses();
} else {
System.out.println("MultithreadedIOManager.deallocOutstandingWriteLog failed to dealloc intended target tablespace:"+tablespace+" "+lbai);
}
}
private String translateDb(String dbname, int tablespace) {
String db;
// replace any marker of $ with tablespace number
if( dbname.indexOf('$') != -1) {
db = dbname.replace('$', String.valueOf(tablespace).charAt(0));
} else
db = dbname;
db = (new File(db)).toPath().getParent().toString() + File.separator +
"tablespace"+String.valueOf(tablespace) + File.separator +
(new File(dbname).getName());
return db;
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#Fopen()
*/
@Override
public void Fopen() throws IOException {
synchronized(ioWorker) {
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++)
if (ioWorker[i] != null && !((IoInterface)ioWorker[i]).isopen())
((IoInterface)ioWorker[i]).Fopen();
}
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#Fclose()
*/
@Override
public void Fclose() throws IOException {
synchronized(ioWorker) {
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++)
if (ioWorker[i] != null && ((IoInterface)ioWorker[i]).isopen()) {
if( ioWorker[i].getRequestQueueLength() == 0 )
((IoInterface)ioWorker[i]).Fclose();
else
throw new IOException("Attempt to close tablespace with outstanding requests");
}
}
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#Fforce()
*/
@Override
public void Fforce() throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.Fforce ");
synchronized(ioWorker) {
CountDownLatch barrierCount = new CountDownLatch(DBPhysicalConstants.DTABLESPACES);
IoRequestInterface[] iori = new IoRequestInterface[DBPhysicalConstants.DTABLESPACES];
// queue to each tablespace
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
iori[i] = new FSyncRequest(forceBarrierSynch, barrierCount);
ioWorker[i].queueRequest(iori[i]);
}
try {
barrierCount.await();
} catch (InterruptedException e) {}
}
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#isNew()
*/
@Override
public boolean isNew() {
synchronized(ioWorker) {
return ((IoInterface)ioWorker[0]).isnew();
}
}
/* (non-Javadoc)
* @see com.neocoretechs.bigsack.io.IoManagerInterface#getIOWorker(int)
*/
@Override
public IOWorkerInterface getIOWorker(int tblsp) {
return ioWorker[tblsp];
}
@Override
public void forceBufferClear() {
//for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
// blockBuffer[i].forceBufferClear();
//}
synchronized(blockBuffer) {
CountDownLatch cdl = new CountDownLatch(DBPhysicalConstants.DTABLESPACES);
for(int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
ForceBufferClearRequest fbcr = new ForceBufferClearRequest(blockBuffer[i], cdl, forceBarrierSynch);
blockBuffer[i].queueRequest(fbcr);
//blockBuffer[i].forceBufferClear();
}
try {
cdl.await();// wait for completion
} catch (InterruptedException e) {
// executor requested thread shutdown
return;
}
}
}
/**
* Load up a block from the freelist with the assumption that it will be filled in later. Do not
* check for whether it should be logged,etc. As part of the 'acquireblock' process, this takes place. Latch it
* as soon as possible though. Queue a request to the MappedBlockBuffer IoManager to do this. Await the countdownlatch to continue.
*/
@Override
public BlockAccessIndex addBlockAccessNoRead(Long Lbn) throws IOException {
int tblsp = GlobalDBIO.getTablespace(Lbn);
//return blockBuffer[tblsp].addBlockAccessNoRead(Lbn);
CountDownLatch cdl = new CountDownLatch(1);
AddBlockAccessNoReadRequest abanrr = new AddBlockAccessNoReadRequest(blockBuffer[tblsp], cdl, Lbn);
blockBuffer[tblsp].queueRequest(abanrr);
try {
cdl.await();
return (BlockAccessIndex) abanrr.getObjectReturn();
} catch (InterruptedException e) {
// shutdown waiting for return
return null;
}
}
@Override
public BlockAccessIndex findOrAddBlockAccess(long bn) throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.findOrAddBlockAccess "+GlobalDBIO.valueOf(bn));
//int tblsp = GlobalDBIO.getTablespace(bn);
//return blockBuffer[tblsp].findOrAddBlockAccess(bn);
int tblsp = GlobalDBIO.getTablespace(bn);
CountDownLatch cdl = new CountDownLatch(1);
FindOrAddBlockAccessRequest abanrr = new FindOrAddBlockAccessRequest(blockBuffer[tblsp], cdl, bn);
blockBuffer[tblsp].queueRequest(abanrr);
try {
cdl.await();
if( DEBUG )
System.out.println("MultithreadedIOManager.findOrAddBlockAccess "+(BlockAccessIndex) abanrr.getObjectReturn());
lbai[tblsp].setLbai(((BlockAccessIndex) abanrr.getObjectReturn()));
return (BlockAccessIndex) abanrr.getObjectReturn();
} catch (InterruptedException e) {
// shutdown waiting for return
return null;
}
}
@Override
public BlockAccessIndex getUsedBlock(long loc) {
if( DEBUG )
System.out.println("MultithreadedIOManager.getUsedBlock "+GlobalDBIO.valueOf(loc));
//int tblsp = GlobalDBIO.getTablespace(loc);
//return blockBuffer[tblsp].getUsedBlock(loc);
int tblsp = GlobalDBIO.getTablespace(loc);
CountDownLatch cdl = new CountDownLatch(1);
GetUsedBlockRequest abanrr = new GetUsedBlockRequest(blockBuffer[tblsp], cdl, loc);
blockBuffer[tblsp].queueRequest(abanrr);
try {
cdl.await();
return (BlockAccessIndex) abanrr.getObjectReturn();
} catch (InterruptedException e) {
// shutdown waiting for return
return null;
}
}
/**
* Commit the outstanding blocks, wait until the IO requests have finished first
*/
@Override
public void commitBufferFlush() throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.commitBufferFlush invoked.");
CountDownLatch barrierCount = new CountDownLatch(DBPhysicalConstants.DTABLESPACES);
// queue to each tablespace
synchronized(ioWorker) {
for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
IoRequestInterface iori = new CommitRequest(blockBuffer[i], ulog[i], commitBarrierSynch, barrierCount);
ioWorker[i].queueRequest(iori);
}
try {
barrierCount.await();
} catch (InterruptedException e) {}
}
}
@Override
public void directBufferWrite() throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.directBufferWrite invoked.");
//for (int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
// blockBuffer[i].directBufferWrite();
//}
CountDownLatch cdl = new CountDownLatch( DBPhysicalConstants.DTABLESPACES);
synchronized(blockBuffer) {
for(int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) {
//blockBuffer[i].directBufferWrite();
DirectBufferWriteRequest dbwr = new DirectBufferWriteRequest(blockBuffer[i], cdl, directWriteBarrierSynch);
blockBuffer[i].queueRequest(dbwr);
}
try {
cdl.await();
} catch (InterruptedException e) {
return;
}
}
}
/**
* seek_fwd - long seek forward from current spot
* @param offset offset from current
* @exception IOException If we cannot acquire next block
*/
public boolean seek_fwd(int tblsp, long offset) throws IOException {
return blockBuffer[tblsp].seek_fwd(lbai[tblsp].getLbai(), offset);
}
@Override
public long Fsize(int tblsp) throws IOException {
if( DEBUG )
System.out.println("MultithreadedIOManager.fsize "+tblsp);
CountDownLatch cdl = new CountDownLatch(1);
FsizeRequest abanrr = new FsizeRequest(cdl);
ioWorker[tblsp].queueRequest(abanrr);
try {
cdl.await();
return abanrr.getLongReturn();
} catch (InterruptedException e) {
// shutdown waiting for return
return -1L;
}
}
@Override
public ObjectDBIO getIO() {
return globalIO;
}
@Override
public void writen(int tblsp, byte[] o, int osize) throws IOException {
blockBuffer[tblsp].writen(lbai[tblsp].getLbai(), o, osize);
}
@Override
public void deallocOutstandingWriteLog(int tblsp) throws IOException {
deallocOutstandingWriteLog(tblsp, lbai[tblsp].getLbai());
if( DEBUGWRITE ) {
System.out.println("MultithreadedIOManager.deallocOutstandingWriteLog:"+lbai[tblsp].getLbai());
}
}
public void writeDirect(int tblsp, long blkn, Datablock blkV2) throws IOException {
synchronized(ioWorker[tblsp]) {
((IOWorker) ioWorker[tblsp]).Fseek(blkn);
blkV2.write((IoInterface) ioWorker[tblsp]);
}
}
public void readDirect(int tblsp, long blkn, Datablock blkV2) throws IOException {
synchronized(ioWorker[tblsp]) {
((IOWorker) ioWorker[tblsp]).Fseek(blkn);
blkV2.read((IoInterface) ioWorker[tblsp]);
}
}
}