package com.neocoretechs.bigsack.io.request;
import java.io.IOException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import com.neocoretechs.bigsack.DBPhysicalConstants;
import com.neocoretechs.bigsack.io.IoInterface;
import com.neocoretechs.bigsack.io.pooled.Datablock;
import com.neocoretechs.bigsack.io.pooled.GlobalDBIO;
/**
* This is an intent parallel computation component of a tablespace wide request.
* We are using a CyclicBarrier set up with the number of tablepsaces and after each thread
* computes the size of the tablespace it will await the barrier synch.
* Once released from barrier synch a countdown latch is decreased which activates the multi
* threading IO manager countdown latch waiter when count reaches 0, thereby releasing the thread
* to accumulate the results from each worker.
* The barrier synch is present to achieve a consistent state upon the invocation of the
* final tally.
* Copyright (C) NeoCoreTechs 2014
* @author jg
*
*/
public final class GetNextFreeBlocksRequest implements IoRequestInterface {
private final static boolean DEBUG = false;
private long nextFreeBlock = -1L;
private IoInterface ioUnit;
private Datablock d = new Datablock(DBPhysicalConstants.DATASIZE);
private CyclicBarrier barrierSynch;
private int tablespace;
private CountDownLatch barrierCount;
public GetNextFreeBlocksRequest(CyclicBarrier barrierSynch, CountDownLatch barrierCount) {
this.barrierSynch = barrierSynch;
this.barrierCount = barrierCount;
}
@Override
public void process() throws IOException {
long stime = System.currentTimeMillis();
if( DEBUG ) {
System.out.println("GetNextFreeBlocksRequest "+this+" start. ioUnit:"+ioUnit);
}
getNextFreeBlocks();
if( DEBUG ) {
System.out.println("GetNextFreeBlocksRequest "+this+" end in "+(System.currentTimeMillis()-stime)+" ms.");
}
barrierCount.countDown();
}
/**
* Set the next free block position from reverse scan of blocks
* next free will be set to -1 if there are no free blocks
* @exception IOException if seek or size fails
*/
private void getNextFreeBlocks() throws IOException {
synchronized(ioUnit) {
long endBlock = 0L;
long endBl = ioUnit.Fsize();
nextFreeBlock = 0L; // assume there are none and if we fall through get block 0
while (endBl > endBlock) {
ioUnit.Fseek(endBl - (long) DBPhysicalConstants.DBLOCKSIZ);
d.read(ioUnit);
if (d.getPrevblk() == -1L
&& d.getNextblk() == -1L
&& d.getBytesinuse() == 0) {
endBl -= (long) DBPhysicalConstants.DBLOCKSIZ;
continue;
} else {
// this is it
break;
}
}
if( endBl == ioUnit.Fsize()) {
nextFreeBlock = -1L;
} else {
nextFreeBlock = GlobalDBIO.makeVblock(tablespace, endBl);
}
}
// wait at the barrier until all other tablespaces arrive at their result
try {
barrierSynch.await();
} catch (InterruptedException | BrokenBarrierException e) {
throw new IOException(e);
}
}
@Override
public long getLongReturn() {
return nextFreeBlock;
}
@Override
public Object getObjectReturn() {
return new Long(nextFreeBlock);
}
/**
* This method is called by queueRequest to set the proper tablespace from IOManager
* It is the default way to set the active IO unit
*/
@Override
public void setIoInterface(IoInterface ioi) {
this.ioUnit = ioi;
}
/**
* This method also set by queueRequest
*/
@Override
public void setTablespace(int tablespace) {
this.tablespace = tablespace;
}
public String toString() {
return "GetNextFreeBlocksRequest for tablespace "+tablespace+" "+barrierSynch+" "+barrierCount+" next free block "+GlobalDBIO.valueOf(nextFreeBlock);
}
}