0,0 → 1,137 |
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); |
} |
} |