public long freeMemory() { long memoryFreed = 0; for (MemoryBlock block : allocatedPages) { memoryManager.freePage(block); shuffleMemoryManager.release(block.size()); memoryFreed += block.size(); } allocatedPages.clear(); currentPage = null; currentPagePosition = -1; freeSpaceInCurrentPage = 0; return memoryFreed; }
/** * Allocates more memory in order to insert an additional record. This will request additional * memory from the {@link ShuffleMemoryManager} and spill if the requested memory can not be * obtained. * * @param requiredSpace the required space in the data page, in bytes, including space for storing * the record size. */ private void allocateSpaceForRecord(int requiredSpace) throws IOException { // TODO: merge these steps to first calculate total memory requirements for this insert, // then try to acquire; no point in acquiring sort buffer only to spill due to no space in the // data page. if (!sorter.hasSpaceForAnotherRecord()) { logger.debug("Attempting to expand sort pointer array"); final long oldPointerArrayMemoryUsage = sorter.getMemoryUsage(); final long memoryToGrowPointerArray = oldPointerArrayMemoryUsage * 2; final long memoryAcquired = shuffleMemoryManager.tryToAcquire(memoryToGrowPointerArray); if (memoryAcquired < memoryToGrowPointerArray) { shuffleMemoryManager.release(memoryAcquired); spill(); } else { sorter.expandPointerArray(); shuffleMemoryManager.release(oldPointerArrayMemoryUsage); } } if (requiredSpace > freeSpaceInCurrentPage) { logger.trace( "Required space {} is less than free space in current page ({})", requiredSpace, freeSpaceInCurrentPage); // TODO: we should track metrics on the amount of space wasted when we roll over to a new page // without using the free space at the end of the current page. We should also do this for // BytesToBytesMap. if (requiredSpace > PAGE_SIZE) { throw new IOException( "Required space " + requiredSpace + " is greater than page size (" + PAGE_SIZE + ")"); } else { final long memoryAcquired = shuffleMemoryManager.tryToAcquire(PAGE_SIZE); if (memoryAcquired < PAGE_SIZE) { shuffleMemoryManager.release(memoryAcquired); spill(); final long memoryAcquiredAfterSpilling = shuffleMemoryManager.tryToAcquire(PAGE_SIZE); if (memoryAcquiredAfterSpilling != PAGE_SIZE) { shuffleMemoryManager.release(memoryAcquiredAfterSpilling); throw new IOException("Unable to acquire " + PAGE_SIZE + " bytes of memory"); } } currentPage = memoryManager.allocatePage(PAGE_SIZE); currentPagePosition = currentPage.getBaseOffset(); freeSpaceInCurrentPage = PAGE_SIZE; allocatedPages.add(currentPage); } } }
/** Write a record to the sorter. */ public void insertRecord( Object recordBaseObject, long recordBaseOffset, int lengthInBytes, long prefix) throws IOException { // Need 4 bytes to store the record length. final int totalSpaceRequired = lengthInBytes + 4; if (!haveSpaceForRecord(totalSpaceRequired)) { allocateSpaceForRecord(totalSpaceRequired); } final long recordAddress = memoryManager.encodePageNumberAndOffset(currentPage, currentPagePosition); final Object dataPageBaseObject = currentPage.getBaseObject(); PlatformDependent.UNSAFE.putInt(dataPageBaseObject, currentPagePosition, lengthInBytes); currentPagePosition += 4; PlatformDependent.copyMemory( recordBaseObject, recordBaseOffset, dataPageBaseObject, currentPagePosition, lengthInBytes); currentPagePosition += lengthInBytes; freeSpaceInCurrentPage -= totalSpaceRequired; sorter.insertRecord(recordAddress, prefix); }