/** * Changes the block ID of the specified Block. This method is called * copyBlock because a call to copyBlock() followed by a call to * writeBlock() can be used to copy the contents of a block to a new * location in the block file. * * @param block the Block to be copied. * @param dstBlockId the ID of the block to which the Block will be written * when writeBlock() is called. * @throws IOException if an I/O error occurs. */ public void copyBlock(Block block, long dstBlockId) throws IOException { assert this == currentPhase; assert block.getBlockId() != dstBlockId; if (freeList.isSharedItem(dstBlockId)) { // Choose an alternative destination block since this one is shared // with another phase. freeList.free(dstBlockId); dstBlockId = freeList.allocate(); blockFile.setNrBlocks(freeList.getNextItem()); } blockFile.copyBlock(block, dstBlockId); }
/** * Truncates the file to zero length. * * @throws IOException if an I/O error occurs. */ public void clear() throws IOException { blockFile.clear(); freeList.clear(); }
/** * Ensures that all data for this BlockFile is stored in persistent storage * before returning. * * @throws IOException if an I/O error occurs. */ public void force() throws IOException { blockFile.force(); freeList.force(); }
removeClosedPhases(); readHeadBlock(getBlockId(head)); int offset = getBlockOffset(head++); headBlock.putLong(offset, item); headBlockDirty = true; if (!isSharedItem(item)) { reallocate = head; if (getBlockOffset(head) == 0) { if (nextHeadBlockId == getBlockId(firstTail)) { allocateHeadBlock(newHeadBlockId); headBlock.putInt(IDX_NEXT, nextHeadBlockId); headBlock.putInt(IDX_PREV, (int) prevHeadBlock.getBlockId()); headBlockDirty = true; force(); Block nextHeadBlock = findBlock(nextHeadBlockId);
freeList != null && currentPhase != null ) { blockFile.setNrBlocks(freeList.getNextItem()); if (freeList != null) { if (deleteFiles) { freeList.delete(); } else { freeList.close();
releaseTailBlock(); releaseReallocateBlock(); releaseHeadBlock(); nextBlockId = 2; blockFile.setNrBlocks(nextBlockId); allocateHeadBlock(0); headBlock.putInt(IDX_NEXT, 1); headBlock.putInt(IDX_PREV, 1); headBlockDirty = true; allocateHeadBlock(1); headBlock.putInt(IDX_NEXT, 0); headBlock.putInt(IDX_PREV, 0); headBlockDirty = true; force();
/** * Allocates a ByteBuffer to be used for writing to the specified block. The * contents of the ByteBuffer are undefined. The method {@link #writeBlock} * should be called to write the buffer to the block but, depending on the * BlockFile implementation, changes to the ByteBuffer may take effect even if * {@link #writeBlock} is never called. * * @param objectPool the object pool to attempt to get objects from and * release objects to. * @return a ByteBuffer to be used for writing to the specified block. * @throws IOException if an I/O error occurs. */ public Block allocateBlock(ObjectPool objectPool) throws IOException { assert this == currentPhase; long blockId = freeList.allocate(); blockFile.setNrBlocks(freeList.getNextItem()); Block block = blockFile.allocateBlock(objectPool, blockId); block.setBlockFile(this); return block; }
/** * Initializes a FreeList block file or repairs the back-pointers in * an existing file. This is called from Phase.init(llll). */ private void initFreeListFile(boolean clear) throws IOException { if (clear || blockFile.getNrBlocks() < 2) { // File is too small to be valid. Reset to two blocks. nextBlockId = 2; blockFile.setNrBlocks(nextBlockId); allocateHeadBlock(0); headBlock.putInt(IDX_NEXT, 1); headBlock.putInt(IDX_PREV, 1); headBlockDirty = true; allocateHeadBlock(1); headBlock.putInt(IDX_NEXT, 0); headBlock.putInt(IDX_PREV, 0); headBlockDirty = true; force(); } else { nextBlockId = findMaxBlockId() + 1; blockFile.setNrBlocks(nextBlockId); } }
/** * METHOD TO DO * * @param node PARAMETER TO DO * @throws NodePoolException EXCEPTION TO DO * @throws NoSuchNodeException EXCEPTION TO DO */ public synchronized void releaseNode( long node ) throws NodePoolException, NoSuchNodeException { checkInitialized(); try { if (node < MIN_NODE || node >= freeList.getNextItem()) { throw new NoSuchNodeException(node, "Invalid node ID: " + node); } freeList.free(node); } catch (NullPointerException ex) { throw new NodePoolException("Node pool not open."); } catch (IOException ex) { throw new NodePoolException("Failed to free node.", ex); } catch (IllegalStateException ex) { throw new NodePoolException("Node pool already initialized.", ex); } }
/** * Nullifies references to MappedByteBuffers. */ public void unmap() { if (blockFile != null) { blockFile.unmap(); } if (freeList != null) { freeList.unmap(); } }
/** * Creates a FreeList instance which uses the specified file (if it exists) or * creates a new file (if it doesn't already exist). Uses the default IO file type. * * @param objectPool the ObjectPool to use when allocating Blocks. * @param file the file. * @return The new FreeList instance. * @throws IOException if an I/O error occurs. */ public static FreeList openFreeList( ObjectPool objectPool, File file ) throws IOException { return openFreeList(objectPool, file, DEF_IO_TYPE); }
/** * Release a block ID back into the free list. * * @param blockId The ID of the block to release. * @throws IOException if an I/O error occurs. */ public void freeBlock(long blockId) throws IOException { assert this == currentPhase; freeList.free(blockId); }
/** * Establishes that the structure of the blocks is what it should be. * * @throws Error When the file is shorter than the fields in the file indicate. */ private void check() throws IOException { // Initial phase. // Check that the block file has the correct size. long nrValidBlocks = freeList.getNextItem(); long nrBlocks = getNrBlocks(); if (nrBlocks != nrValidBlocks) { if (nrBlocks < nrValidBlocks) { logger.error("File " + file + " may have been truncated."); throw new Error("File " + file + " may have been truncated."); } if (logger.isDebugEnabled()) { logger.debug("File " + file + " may not have been closed properly on shutdown.\n nrBlocks=" + nrBlocks + " nrValidBlocks=" + nrValidBlocks, new Throwable()); } blockFile.setNrBlocks(nrValidBlocks); } }
/** * METHOD TO DO * * @return RETURNED VALUE TO DO * @throws NodePoolException EXCEPTION TO DO */ public synchronized long newNode() throws NodePoolException { checkInitialized(); try { long node = freeList.allocate(); // Notify all the NewNodeListeners. try { Iterator it = newNodeListeners.iterator(); while (it.hasNext()) { NewNodeListener l = (NewNodeListener) it.next(); l.newNode(node); } } catch (Exception ex) { throw new NodePoolException("Call to NewNodeListener failed.", ex); } return node; } catch (NullPointerException ex) { throw new NodePoolException("Node pool not open."); } catch (IOException ex) { throw new NodePoolException("Failed to allocate new node.", ex); } catch (IllegalStateException ex) { throw new NodePoolException("Node pool already initialized.", ex); } }
/** * Factory method for a FreeList instance which uses the specified file * (if it exists) or creates a new file (if it doesn't already exist). * * @param objectPool the ObjectPool to use when allocating Blocks. * @param file the file. * @param ioType the IOType to use for the BlockFile. * @return The new FreeList instance. * @throws IOException if an I/O error occurs. */ public static FreeList openFreeList( ObjectPool objectPool, File file, BlockFile.IOType ioType ) throws IOException { return new FreeList(objectPool, file, ioType); }
/** * Closes and deletes the file. * * @throws IOException if an I/O error occurs. */ public synchronized void delete() throws IOException { try { unmap(); if (objectPool != null) { objectPool.release(); objectPool = null; } } finally { try { if (itemToPhaseSeqMap != null) { itemToPhaseSeqMap.delete(); } } finally { itemToPhaseSeqMap = null; blockFile.delete(); } } }
/** * Creates a FreeList instance which uses the file with the specified file * name (if the file exists) or creates a new file (if it doesn't already * exist). * * @param objectPool the ObjectPool to use when allocating Blocks. * @param fileName the file name of the file. * @return The new FreeList instance. * @throws IOException if an I/O error occurs. */ public static FreeList openFreeList( ObjectPool objectPool, String fileName ) throws IOException { return openFreeList(objectPool, new File(fileName)); }
/** * Gets a new block from the file to write block data to. * The block data to write is a modified version of an existing block. * * @param block The block to be copied into the new "modified" block. * @throws IOException if an I/O error occurs. */ public void modifyBlock(Block block) throws IOException { assert this == currentPhase; if (freeList.isSharedItem(block.getBlockId())) { // Allocate a new block and copy block to it. long newBlockId = freeList.allocate(); blockFile.setNrBlocks(freeList.getNextItem()); // Although we use block after the block is freed, the block can't // be reused (by a later phase) until the current phase is committed. freeList.free(block.getBlockId()); blockFile.copyBlock(block, newBlockId); } }