Subversion Repositories Code-Repo

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

import java.nio.ByteBuffer;

// Memory manager that operates on the memory pool
public class MemManager {

        private byte[] memoryPool;      // Byte array representing the memory pool
        private DoubleLinkedList emptyBlockList;        // List of free blocks

        // Constructor
        public MemManager(int poolsize) {
                // Initialize memory pool and list of free blocks
                memoryPool = new byte[poolsize];
                emptyBlockList = new DoubleLinkedList();

                // Create the first empty block of the pool size
                LinkedListEntry newEntry = new LinkedListEntry(0, poolsize - 1, poolsize);
                emptyBlockList.insert(newEntry);
        }

        // Insert a record and return its position handle.
        // space contains the record to be inserted, of length size.
        public Handle insert(byte[] space, int size) {
                LinkedListEntry start = emptyBlockList.getFirstEntry();
                if (start == null) {
                        // There are no free blocks
                        return null;
                }
                if ((size + 1) > start.getSize()) {
                        // Size to insert is greater than size of largest free block
                        return null;
                }
                while (start != null) {
                        if (start.getNextBlock() == null) {
                                // Current block is last block in list, insert into current block
                                Handle newHandle = insertDataIntoMemPool(start, space, size);
                                return newHandle;
                        } else if ((size + 1) > start.getNextBlock().getSize()) {
                                // Best fit block found, insert into current block
                                Handle newHandle = insertDataIntoMemPool(start, space, size);
                                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.getAddress());
                
                // Needs to create a new empty block at the specified address
                LinkedListEntry newEntry = new LinkedListEntry(handle.getAddress(), handle.getAddress() + size, size + 1);
                emptyBlockList.insert(newEntry);
        }

        // Return the record with handle posHandle, up to size bytes.
        // Data to be returned is copied to space.
        public void get(byte[] space, Handle handle, int size) {
                short shSize = getDataBlockSize(handle.getAddress());
                
                // Find max number of bytes to copy to byte array
                int toRead;
                if (size < shSize) {
                        toRead = size;
                } else {
                        toRead = shSize;
                }
                
                // Copy bytes from memory pool to byte array
                ByteBuffer memPool = ByteBuffer.wrap(memoryPool, handle.getAddress() + 1, toRead);
                ByteBuffer dest = ByteBuffer.wrap(space);
                dest.put(memPool);
        }

        // Dump a printout of the freeblock list
        public void dump() {
                LinkedListEntry head = emptyBlockList.getFirstEntry();
                while (head != null) {
                        System.out.printf("Empty block at address %d of size %d\n", head.getStartAddress(), head.getSize());
                        head = head.getNextBlock();
                }
        }
        
        // Returns the value of the first byte for the data entry (size)
        private short getDataBlockSize(int address) {
                byte[] shortArr = new byte[2];
                ByteBuffer shortBuffer = ByteBuffer.wrap(shortArr, 1, 1);
                shortBuffer.put(memoryPool[address]);
                shortBuffer = ByteBuffer.wrap(shortArr);
                short size = shortBuffer.getShort();
                return size;
        }
        
        // Copies the passed byte array into a free block in the memory pool
        private Handle insertDataIntoMemPool(LinkedListEntry entry, byte[] space, int size) {
                // Insert the data at the address of the given free block
                ByteBuffer memBuffer = ByteBuffer.wrap(memoryPool, entry.getStartAddress(), size + 1);
                memBuffer.put((byte)size);
                memBuffer.put(space);
                
                // Create a new free block with remaining free space
                if (entry.getSize() - (size + 1) != 0) {
                        int startAddress = entry.getStartAddress() + size + 1;
                        int newSize = entry.getSize() - (size + 1);
                        int endAddress = startAddress + newSize - 1;
                        LinkedListEntry newEntry = new LinkedListEntry(startAddress, endAddress, newSize);
                        emptyBlockList.remove(entry.getStartAddress());
                        emptyBlockList.insert(newEntry);
                } else {
                        emptyBlockList.remove(entry.getStartAddress());
                }
                
                Handle newHandle = new Handle(entry.getStartAddress());
                return newHandle;
        }
}