Subversion Repositories Code-Repo

Rev

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);
        }
}