package iitb.con.util;
import iitb.con.io.BufferedFileAdapter;
import iitb.con.io.IOAdapter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ArrayFreeSpaceList implements FreeSpaceList{
private List<Entry> locationList;
private List<Long> sizeList;
private IOAdapter freeSpaceListFile;
public ArrayFreeSpaceList(String fileName, String mode)
throws FileNotFoundException, IOException
{
File file = new File(fileName);
int length = (int)file.length();
freeSpaceListFile = new BufferedFileAdapter(fileName, mode, length);
locationList = new ArrayList<Entry>();
sizeList = new ArrayList<Long>();
read(length);
}
private void read(int length) throws IOException{
ByteBuffer buffer = freeSpaceListFile.readIntoBuffer(0);
buffer.rewind();
LongBuffer longBuf = buffer.asLongBuffer();
while (longBuf.hasRemaining()) {
long sloc = longBuf.get();
long eloc = longBuf.get();
Entry e = new Entry(sloc, eloc);
locationList.add(e);
sizeList.add(eloc - sloc + 1);
}
}
public long getFreeBlock(long size){
int index = Collections.binarySearch(sizeList, size);
if(index >= 0) { Entry e = locationList.get(index);
remove(index);
return e.startLocation;
}else {
int nextIndex = - (index + 1);
if(nextIndex < sizeList.size()) {
Entry e = locationList.get(nextIndex);
long loc = e.startLocation;
e.startLocation = e.startLocation + size;
update(nextIndex, e, (e.endLocation - e.startLocation + 1));
return loc;
}else {
}
}
return 0;
}
private void update(int index, Entry e, long size) {
locationList.set(index, e);
sizeList.set(index, size);
}
private void insert(Entry e) {
long size = e.endLocation - e.startLocation + 1;
int index = Collections.binarySearch(sizeList, size); int nextIndex = -1;
if(index < 0)
nextIndex = - (index + 1);
else
nextIndex = index;
locationList.add(nextIndex, e);
sizeList.add(nextIndex, size);
}
private void remove(int index) {
sizeList.remove(index);
locationList.remove(index);
}
public boolean freeTheBlock(long location, long size) {
Entry e = new Entry(location, location + size - 1);
insert(e);
return true;
}
private static class Entry implements Comparable<Entry> {
long startLocation;
long endLocation;
Entry(long startLocation, long endLocation) {
this.startLocation = startLocation;
this.endLocation = endLocation;
}
public int compareTo(Entry e) {
if(this.startLocation > e.startLocation)
return 1;
else if(this.startLocation < e.startLocation)
return -1;
else
return 0;
}
}
public void commit() throws IOException {
coalesceFreeSpace();
ByteBuffer bbuf = ByteBuffer.allocate(locationList.size() * 16);
for(Entry e : locationList) {
bbuf.putLong(e.startLocation);
bbuf.putLong(e.endLocation);
}
freeSpaceListFile.write(bbuf, 0);
}
private void coalesceFreeSpace() {
Collections.sort(locationList);
int length = locationList.size();
int index = 0;
List<Entry> tempLocationList = new ArrayList<Entry>();
List<Long> tempSizeList = new ArrayList<Long>();
if(length > 1) {
Entry first = locationList.get(0);
Entry e = new Entry(first.startLocation, first.endLocation);
long size = sizeList.get(0);
for(int i = 1; i < length; i++) {
Entry next = locationList.get(i);
if(e.endLocation == (next.startLocation - 1)) {
e.endLocation = next.endLocation;
size += (next.endLocation = next.startLocation) + 1;
} else {
tempLocationList.add(index, e);
tempSizeList.add(index, new Long(size));
index++;
e = new Entry(next.startLocation, next.endLocation);
size = sizeList.get(i);
}
}
tempLocationList.add(index, e);
tempSizeList.add(index, new Long(size));
locationList.clear();
sizeList.clear();
locationList = tempLocationList;
sizeList = tempSizeList;
}
}
public void close() throws IOException {
freeSpaceListFile.close();
}
public void dumpFreeSpaceList(){
int i = 0;
for(Entry e : locationList) {
System.out.println(e.startLocation + "-" + e.endLocation + " = " + sizeList.get(i++));
}
}
}