package com.neocoretechs.bigsack.io.request;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
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;
/**
* Deal with virtual blocks and extract block. Pass the previous free block from each
* respective tablespace in the request constructor
* @author jg
*
*/
public final class GetNextFreeBlockRequest implements IoRequestInterface {
private static boolean DEBUG = false;
private IoInterface ioUnit;
Datablock d = new Datablock(DBPhysicalConstants.DATASIZE);
private int tablespace;
private long nextFreeBlock = -1L;
private CountDownLatch barrierCount;
public GetNextFreeBlockRequest(CountDownLatch barrierCount, long prevFreeBlk) {
this.barrierCount = barrierCount;
nextFreeBlock = prevFreeBlk;
}
@Override
public void process() throws IOException {
getNextFreeBlock();
barrierCount.countDown();
}
/**
* Return the first available block that can be acquired for write. Use the previous free block as guide unless
* its not initialized, ie, not -1. Take the next physical block after the previous one, if that one is eligible
* @param tblsp The tablespace
* @return The block available as a real, not virtual, block in this tablespace
* @exception IOException if IO problem
*/
private void getNextFreeBlock() throws IOException {
synchronized(ioUnit) {
if( DEBUG )
System.out.println("GetNextFreeBlockRequest CURRENT block:"+this);
if( nextFreeBlock != -1L) {
long tblock = GlobalDBIO.getBlock(nextFreeBlock) + (long) DBPhysicalConstants.DBLOCKSIZ;
nextFreeBlock = GlobalDBIO.makeVblock(tablespace, tblock);
long tsize = ioUnit.Fsize();
if( DEBUG )
System.out.println("GetNextFreeBlockRequest FOUND:"+this+" size:"+tsize);
if (GlobalDBIO.getBlock(nextFreeBlock) >= tsize) {
// extend tablespace in pool-size increments
long newLen = tsize + (long) (DBPhysicalConstants.DBLOCKSIZ * DBPhysicalConstants.DBUCKETS);
if( DEBUG )
System.out.println("GetNextFreeBlockRequest FOUND EXTEND:"+this+" size:"+tsize+" setting to "+newLen);
ioUnit.Fset_length(newLen);
while (tsize < newLen) {
ioUnit.Fseek(tsize);
d.write(ioUnit);
tsize += (long) DBPhysicalConstants.DBLOCKSIZ;
}
ioUnit.Fforce(); // flush on block creation
}
} else {
// no next free, extend tablespace and set next free to prev end
long tsize = ioUnit.Fsize();
nextFreeBlock = GlobalDBIO.makeVblock(tablespace,tsize);
// extend tablespace in pool-size increments
long newLen = tsize + (long) (DBPhysicalConstants.DBLOCKSIZ * DBPhysicalConstants.DBUCKETS);
if( DEBUG )
System.out.println("GetNextFreeBlockRequest NO FREE, EXTEND:"+this+" size:"+tsize+" setting to "+newLen);
ioUnit.Fset_length(newLen);
while(tsize < newLen) {
ioUnit.Fseek(tsize);
d.write(ioUnit);
tsize += (long) DBPhysicalConstants.DBLOCKSIZ;
}
ioUnit.Fforce(); // flush on block creation
}
}
}
@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;
}
@Override
public void setTablespace(int tablespace) {
this.tablespace = tablespace;
}
public String toString() {
return "GetNextFreeBlockRequest for "+ioUnit.Fname()+" tablespace "+tablespace+" next free block "+(nextFreeBlock == -1 ? "Empty" : GlobalDBIO.valueOf(nextFreeBlock));
}
}