Blame | Last modification | View Log | RSS feed
import java.nio.ByteBuffer;
// Memory manager that operates on the buffer pool
public class MemManager {
private LRUBuffer buffer; // Buffer pool interfacing to disk
private int blockSize = 0; // Size of each block
private long fileLength = 0; // Current length of the file
private DoubleLinkedList emptyBlockList; // List of free blocks
// Constructor
public MemManager(LRUBuffer buffer, int blockSize) {
// Initialize buffer pool and list of free blocks
this.buffer = buffer;
emptyBlockList = new DoubleLinkedList();
this.blockSize = blockSize;
}
// Insert a record and return its position handle.
public Handle insert(byte[] data, int length) {
// There are no free blocks
if (emptyBlockList.getFirstEntry() == null) {
// Create a new free block of size blockSize
LinkedListBlock newEntry = new LinkedListBlock(0, blockSize - 1, blockSize);
emptyBlockList.insert(newEntry);
fileLength = blockSize;
}
// Size to insert is greater than size of largest free block
if ((length + 1) > emptyBlockList.getFirstEntry().getSize()) {
// Calculate how many new free blocks needs to be created to hold the byte array
int blocks = length / blockSize;
if (length % blockSize != 0) {
blocks++;
}
for (int i = 0; i < blocks; i++) {
// Create a new free block and insert it into the list of empty block
LinkedListBlock newEntry = new LinkedListBlock(fileLength, fileLength + blockSize - 1, blockSize);
emptyBlockList.insert(newEntry);
fileLength += blockSize;
}
}
// Find the first free block that can hold the byte array
LinkedListBlock start = emptyBlockList.getFirstEntry();
while (start != null) {
// Current block is last block in list, insert into current block
if (start.getNextBlock() == null) {
Handle newHandle = insertDataIntoMemPool(start, data, length);
return newHandle;
// Best fit block found, insert into current block
} else if ((length + 1) > start.getNextBlock().getSize()) {
Handle newHandle = insertDataIntoMemPool(start, data, length);
return newHandle;
}
// Otherwise keep searching for best fit block
start = start.getNextBlock();
}
return null;
}
// Free a block at address. Merge adjacent blocks if appropriate.
public void remove(Handle handle) {
short size = getDataBlockSize(handle);
// Needs to create a new empty block at the specified address
LinkedListBlock newEntry = new LinkedListBlock(handle.getAddress(), handle.getAddress() + size, size + 1);
emptyBlockList.insert(newEntry);
}
// Return the record with handle posHandle, up to size bytes.
public void get(byte[] data, Handle handle) {
// Get bytes from buffer
buffer.getBytes(data, 0, handle.getAddress() + 1, getDataBlockSize(handle));
}
// Returns the value of the first byte for the data entry (size)
public short getDataBlockSize(Handle handle) {
byte[] shortArr = new byte[2];
// Get the first byte at the address
buffer.getBytes(shortArr, 1, handle.getAddress(), 1);
ByteBuffer shortBuffer = ByteBuffer.wrap(shortArr);
short size = shortBuffer.getShort();
return size;
}
// Copies the passed byte array into the buffer
private Handle insertDataIntoMemPool(LinkedListBlock entry, byte[] data, int length) {
// Insert the size of the array into the first byte
byte[] size = new byte[1];
ByteBuffer buff = ByteBuffer.wrap(size);
buff.put((byte)length);
buffer.putBytes(size, 0, entry.getStartAddress(), 1);
// Insert the array
buffer.putBytes(data, 0, entry.getStartAddress() + 1, length);
// Create a new free block with remaining free space
if (entry.getSize() - (length + 1) != 0) {
long startAddress = entry.getStartAddress() + length + 1;
long newSize = entry.getSize() - (length + 1);
long endAddress = startAddress + newSize - 1;
LinkedListBlock newEntry = new LinkedListBlock(startAddress, endAddress, newSize);
emptyBlockList.remove(entry.getStartAddress());
emptyBlockList.insert(newEntry);
} else {
emptyBlockList.remove(entry.getStartAddress());
LinkedListBlock newEntry = new LinkedListBlock(fileLength, fileLength + blockSize - 1, blockSize);
emptyBlockList.insert(newEntry);
fileLength += blockSize;
}
Handle newHandle = new Handle(entry.getStartAddress());
return newHandle;
}
// Dump a printout of the freeblock list
public void dump() {
LinkedListBlock head = emptyBlockList.getFirstEntry();
while (head != null) {
System.out.printf("Empty block at address %d to %d\n", head.getStartAddress(), head.getStartAddress() + head.getSize() - 1);
head = head.getNextBlock();
}
}
public void printBuffer() {
buffer.printBlockIDs();
}
public void clear() {
LinkedListBlock head = emptyBlockList.getFirstEntry();
while (head != null) {
emptyBlockList.remove(head.getStartAddress());
head = head.getNextBlock();
}
LinkedListBlock newEntry = new LinkedListBlock(0, fileLength-1, fileLength);
emptyBlockList.insert(newEntry);
}
}