package iitb.con.indexing.isam;
import iitb.con.ds.Node;
import iitb.con.indexing.IndexTree;
import iitb.con.io.BufferedFileAdapter;
import iitb.con.io.IOAdapter;
import iitb.con.util.KeyList;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ISAMTree<K extends Comparable<K>> implements IndexTree<K> {
private static final int BLOCK_SIZE = 4096;
private IOAdapter nonLeafNodesFile;
private IOAdapter leafNodesFile;
private ByteBuffer nonLeafBuffer;
private ByteBuffer leafBuffer;
private KeyList<K,Short> nonLeafNodeKeys;
private short nidxBlockCount = 1;
private short lidxBlockCount = 1;
public ISAMTree(String fileName, String mode)
throws FileNotFoundException, IOException
{
if(mode.equals("r")) {
}else if(mode.equals("rw")) {
nonLeafBuffer = ByteBuffer.allocate(BLOCK_SIZE);
leafBuffer = ByteBuffer.allocate(BLOCK_SIZE);
}else{
throw new IOException("Invalid opening mode");
}
File file = new File(fileName + NON_LEAF_EXT);
int length = (int)file.length();
nonLeafNodesFile = new BufferedFileAdapter(fileName + NON_LEAF_EXT, mode);
leafNodesFile = new BufferedFileAdapter(fileName + LEAF_EXT, mode);
}
public void create(List<Node<K>> nodes)
throws IOException {
Collections.sort(nodes);
initializeBuffer(nonLeafBuffer);
initializeBuffer(leafBuffer);
LeafNode<K> leafNode = new LeafNode<K>();
ArrayList<Integer> tempList = new ArrayList<Integer>();
if(nodes.size() > 0) {
leafNode.key = nodes.get(0).key;
writeIntoBuffer(new NonLeafNode(leafNode.key,lidxBlockCount));
}
for(int i=0 ; i < nodes.size(); i++) {
if((i!= nodes.size() - 1) && nodes.get(i).compareTo(nodes.get(i+1)) == 0) {
tempList.add(nodes.get(i).value);
}else {
leafNode.key = nodes.get(i).key;
tempList.add(nodes.get(i).value);
int[] a = new int[tempList.size()]; int j = 0;
for(Integer n : tempList) {
a[j++] = n;
if(n <= 0) System.out.println(leafNode.key + " - " + n);
}
leafNode.instanceId = a;
tempList.clear();
writeIntoBuffer(leafNode);
}
}
commitBuffers();
}
public int[] getValues(K key) throws IOException {
if(nonLeafNodeKeys == null)
nonLeafNodeKeys = getMetaIndex(key);
Short blockId = nonLeafNodeKeys.getPrev(key);
if(blockId != null) {
byte[] b = leafNodesFile.read(getLocation(blockId), BLOCK_SIZE);
LeafNode<K> leafNode = new LeafNode<K>(key);
ByteBuffer buf = ByteBuffer.wrap(b);
int blockSize = buf.getInt();
buf.limit(blockSize);
while(buf.hasRemaining()) {
if(leafNode.attributeDeSerialize(buf, key) != null)
return leafNode.instanceId;
}
}
return null;
}
public KeyList<K,Short> getMetaIndex(K key) throws IOException {
KeyList<K,Short> nonLeafNodesTable = new KeyList<K,Short>();
ByteBuffer[] buffers = nonLeafNodesFile.readFileAsBlocks();
for(int i=0; i < buffers.length; i++) {
int blockSize = buffers[i].getInt();
buffers[i].limit(blockSize);
while(buffers[i].hasRemaining()) {
NonLeafNode nlNode = new NonLeafNode(key);
nlNode.deSerialize(buffers[i]);
nonLeafNodesTable.add((K)nlNode.value, nlNode.BlockId);
}
}
return nonLeafNodesTable;
}
private void writeIntoBuffer(LeafNode<K> leafNode)
throws IOException {
ByteBuffer buf = leafNode.serialize(leafNode);
if((leafBuffer.position() + buf.capacity()) < BLOCK_SIZE) {
leafBuffer.put(buf);
}else {
leafBuffer.putInt(0, leafBuffer.position());
leafBuffer.rewind();
leafNodesFile.write(leafBuffer, getLocation(lidxBlockCount));
initializeBuffer(leafBuffer);
lidxBlockCount++;
leafBuffer.put(buf);
writeIntoBuffer(new NonLeafNode(leafNode.key, lidxBlockCount));
}
}
private void writeIntoBuffer(NonLeafNode nonLeafNode)
throws IOException {
ByteBuffer buf = nonLeafNode.serialize(nonLeafNode);
if((nonLeafBuffer.position() + buf.capacity()) < BLOCK_SIZE) {
nonLeafBuffer.put(buf);
}else {
nonLeafBuffer.putInt(0, nonLeafBuffer.position());
nonLeafBuffer.rewind();
nonLeafNodesFile.write(nonLeafBuffer, getLocation(nidxBlockCount));
nidxBlockCount++;
initializeBuffer(nonLeafBuffer);
nonLeafBuffer.put(buf);
}
}
private void initializeBuffer(ByteBuffer buffer) {
buffer.clear();
buffer.putInt(BLOCK_SIZE); }
private void commitBuffers() throws IOException {
leafBuffer.putInt(0, leafBuffer.position());
leafBuffer.flip();
leafNodesFile.write(leafBuffer, getLocation(lidxBlockCount));
nonLeafBuffer.putInt(0, nonLeafBuffer.position());
nonLeafBuffer.flip();
nonLeafNodesFile.write(nonLeafBuffer, getLocation(nidxBlockCount));
}
public void close() throws IOException {
if(nonLeafNodesFile != null)
nonLeafNodesFile.close();
if(leafNodesFile != null)
leafNodesFile.close();
}
private long getLocation(int blockId) {
return ((blockId * BLOCK_SIZE) - BLOCK_SIZE);
}
}