package iitb.con.ds;
import iitb.con.caching.SimpleLRUCache;
import iitb.con.core.ConStoreConstants;
import iitb.con.io.BufferedFileAdapter;
import iitb.con.io.IOAdapter;
import iitb.con.util.IntArrayGrid;
import iitb.con.util.Sorted2DIntArray;
import iitb.con.util.Unbound2DIntArray;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
public class RelationTable {
private IOAdapter rTabFile;
private Sorted2DIntArray instanceIndex;
private IOAdapter instanceIndexFile;
private IntArrayGrid grid;
private int currentGridId;
private SimpleLRUCache<Integer, IntArrayGrid> cache;
private static final int COL_NUM = 3;
public RelationTable(String dirName, long cacheSize)
throws FileNotFoundException, IOException
{
String idxFileName = dirName + ConStoreConstants.RELATION_IDX_FILE;
String rtabFileName = dirName + ConStoreConstants.RELATION_TABLE_FILE;
File file = new File(idxFileName);
int length = (int)file.length();
instanceIndexFile = new BufferedFileAdapter(idxFileName , "rw", length);
ByteBuffer buffer = instanceIndexFile.readIntoBuffer(0);
instanceIndex = new Sorted2DIntArray(buffer);
file = new File(rtabFileName);
length = (int)file.length();
int blockId = length / IntArrayGrid.BLOCK_SIZE;
rTabFile = new BufferedFileAdapter(rtabFileName, "rw");
currentGridId = blockId;
cache = new SimpleLRUCache<Integer, IntArrayGrid>((int)(cacheSize / IntArrayGrid.BLOCK_SIZE));
grid = getGridBlock(blockId);
}
public boolean insert(int leftId, int relationId, int rightId) {
int n = grid.add(leftId, relationId, rightId);
if(n < 0) {
newGrid();
grid.add(leftId, relationId, rightId);
}
instanceIndex.add(leftId, grid.id);
instanceIndex.add(relationId, grid.id);
return true;
}
public boolean update(int leftId, int relationId, int rightId) {
IntArrayGrid[] grids = getGrid(leftId);
for(IntArrayGrid grid : grids) {
if(grid.setRow(leftId, relationId, rightId)) {
commitGrid(grid);
return true;
}
}
return false;
}
public boolean removeInstance(int leftId) {
IntArrayGrid[] grids = getGrid(leftId);
if(grids != null) {
for(IntArrayGrid grid : grids) {
if(grid.setRow(leftId, LEFT_ENTITY_IDX, -1)) {
commitGrid(grid);
instanceIndex.remove(leftId);
return true;
}
}
}
return false;
}
public boolean removeRelation(int relationId) {
IntArrayGrid[] grids = getGrid(relationId);
if(grids != null) {
for(IntArrayGrid grid : grids) {
if(grid.setRow(relationId, RELATION_IDX, -1, -1, -1)) {
commitGrid(grid);
instanceIndex.remove(relationId);
return true;
}
}
}
return false;
}
public Unbound2DIntArray getRelationTuplesByEntityId(int leftEntityId) {
IntArrayGrid[] grids = getGrid(leftEntityId);
Unbound2DIntArray result = null;
if(grids != null) {
result = new Unbound2DIntArray(5, COL_NUM); for(int i = 0; i< grids.length ; i++) {
int[][] r = grids[i].getRows(leftEntityId, LEFT_ENTITY_IDX);
if(r != null) {
for(int j = 0; j < r.length ; j++)
result.add(r[j][LEFT_ENTITY_IDX], r[j][RELATION_IDX], r[j][RIGHT_ENTITY_IDX]);
}
}
}
return result;
}
public Unbound2DIntArray getRelationTupleByRelationId(int relationId) {
IntArrayGrid[] grids = getGrid(relationId);
Unbound2DIntArray result = null;
if(grids != null) {
result = new Unbound2DIntArray(5, COL_NUM); for(int i = 0; i< grids.length ; i++) {
int[][] r = grids[i].getRows(relationId, RELATION_IDX);
if(r != null) {
for(int j = 0; j < r.length ; j++)
result.add(r[j][LEFT_ENTITY_IDX], r[j][RELATION_IDX], r[j][RIGHT_ENTITY_IDX]);
}
}
}
return result;
}
public int getLeftEntityId(int relationId) {
Unbound2DIntArray result = getRelationTupleByRelationId(relationId);
if(result != null) {
if(result.length > 0) {
int[] r = result.get(0);
return r[LEFT_ENTITY_IDX];
}
}
return -1;
}
public int getRightEntityId(int relationId) {
Unbound2DIntArray result = getRelationTupleByRelationId(relationId);
if(result != null) {
if(result.length > 0) {
int[] r = result.get(0);
return r[RIGHT_ENTITY_IDX];
}
}
return -1;
}
public int[] getAllRelationIds() {
return grid.getCol(RELATION_IDX);
}
private void newGrid() {
commitGrid(grid);
currentGridId++;
grid = new IntArrayGrid(currentGridId, COL_NUM);
}
private IntArrayGrid[] getGrid(int leftId) {
IntArrayGrid[] grids = null;
int[][] r = instanceIndex.get(leftId);
if(r != null) {
grids = new IntArrayGrid[r.length];
for(int i = 0; i < r.length; i++)
grids[i] = getGridBlock(r[i][1]);
}
return grids;
}
private IntArrayGrid getGridBlock(int blockId) {
IntArrayGrid grid = cache.get(blockId);
if(grid != null) {
cache.put(blockId, grid);
return grid;
}
try {
ByteBuffer buf = rTabFile.readIntoBuffer(IntArrayGrid.BLOCK_SIZE * blockId);
grid = new IntArrayGrid(blockId, COL_NUM, buf);
cache.put(blockId, grid);
return grid;
}catch(IOException ie) {
ie.printStackTrace();
}
return null;
}
private void commitGrid(IntArrayGrid grid) {
try {
rTabFile.write(grid.toBuffer(), IntArrayGrid.BLOCK_SIZE * grid.id);
}catch(IOException ie) {
ie.printStackTrace();
}
}
private void commitInstanceIndex() {
try {
instanceIndexFile.write(instanceIndex.toBuffer(), 0);
}catch(IOException ie) {
ie.printStackTrace();
}
}
public void commit() {
commitGrid(grid);
commitInstanceIndex();
}
public void close() {
try {
rTabFile.close();
instanceIndexFile.close();
}catch(IOException ie) {
ie.printStackTrace();
}
}
public static final int LEFT_ENTITY_IDX = 0;
public static final int RELATION_IDX = 1;
public static final int RIGHT_ENTITY_IDX = 2;
}