); long nrBlocks = metarootFile.getNrBlocks(); if (nrBlocks != NR_METAROOTS) { if (nrBlocks > 0) { if (nrBlocks < NR_METAROOTS) { clear = true; metarootFile.clear(); metarootFile.setNrBlocks(NR_METAROOTS); metarootBlocks[0] = metarootFile.readBlock(writerObjectPool, 0); metarootBlocks[1] = metarootFile.readBlock(writerObjectPool, 1); metarootBlocks[1].putInt(IDX_VALID, 0); metarootBlocks[1].write(); metarootFile.force();
freeList != null && currentPhase != null ) { blockFile.setNrBlocks(freeList.getNextItem()); blockFile.delete(); } else { blockFile.close();
/** * Nullifies references to MappedByteBuffers. */ public void unmap() { if (blockFile != null) { blockFile.unmap(); } if (freeList != null) { freeList.unmap(); } }
/** * 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; }
/** * 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(); }
/** * Allocates a ByteBuffer which is filled with the contents of the * specified block. If the buffer is modified then the method {@link * #writeBlock} should be called to write the buffer back to the file 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. * @param blockId the block to read into the ByteBuffer. * @return The read block. * @throws IOException if an I/O error occurs. */ public Block readBlock(ObjectPool objectPool, long blockId) throws IOException { Block block = blockFile.readBlock(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); } }
blockFile.setNrBlocks(nextBlockId); allocateHeadBlock(newHeadBlockId); headBlock.putInt(IDX_NEXT, nextHeadBlockId); nextHeadBlock = blockFile.readBlock(objectPool, nextHeadBlockId);
/** * 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); }
/** * Closes the file. * * @throws IOException if an I/O error occurs. */ public synchronized void close() throws IOException { try { unmap(); if (objectPool != null) { objectPool.release(); objectPool = null; } } finally { try { if (itemToPhaseSeqMap != null) { itemToPhaseSeqMap.delete(); } } finally { itemToPhaseSeqMap = null; blockFile.close(); } } }
/** * 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); } }
/** * 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(); } } }
/** * Gets the current length of the BlockFile in blocks. An implementation * may allow the actual disk file to be larger or smaller than this size * while it is open but will set the file to this size when it is closed. * * @return the current length of the BlockFile in blocks. */ public long getNrBlocks() { return blockFile.getNrBlocks(); }
/** * Truncates the file to zero length. * * @throws IOException if an I/O error occurs. */ public void clear() throws IOException { blockFile.clear(); freeList.clear(); }
/** * Allocates a buffer from blockFile to hold the head block. If the current * head buffer already holds the head block then nothing is done. If the head * buffer contains a different block then it is released first (writing the * head block to the file). This method uses a previous version of the * block, unless no block with that ID exists yet, in which case a new block * is read in, or allocated if it does not exist in the file either. If the * block existed in the file, then its contents will be ignored. Contrast * this to {@link #readHeadBlock} where the contents of the block on the disk * are always read. * * @param blockId The block number of the head block. * @throws IOException if an I/O error occurs. */ private void allocateHeadBlock(int blockId) throws IOException { if (headBlock != null) { if (blockId == (int) headBlock.getBlockId()) { headBlockDirty = false; return; } releaseHeadBlock(); } headBlock = findBlock(blockId); if (headBlock == null) { headBlock = blockFile.allocateBlock(objectPool, blockId); } headBlockDirty = false; }
/** * Ensures that all data associated with the free list has been written to * persistent storage. * * @throws IOException if an I/O error occurs. */ public void force() throws IOException { writeHeadBlock(); writeReallocateBlock(); blockFile.force(); itemToPhaseSeqMap.force(); }
/** * Reads the tail block from blockFile. If the current tail buffer already * holds the tail block then nothing is done. If the tail buffer contains a * different block then it is freed first. * * @param blockId The block number to use as the tail buffer. * @throws IOException if an I/O error occurs. */ private void readTailBlock(int blockId) throws IOException { if (tailBlock != null) { if (blockId == (int) tailBlock.getBlockId()) { return; } releaseTailBlock(); } tailBlock = findBlock(blockId); if (tailBlock == null) { tailBlock = blockFile.readBlock(objectPool, blockId); } }
/** * 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); } }
metarootFile.close();