/** * Aborts a temp block. * * @param sessionId the id of session * @param blockId the id of block * @throws BlockDoesNotExistException if block id can not be found in temporary blocks * @throws BlockAlreadyExistsException if block id already exists in committed blocks * @throws InvalidWorkerStateException if block id is not owned by session id * @throws IOException if I/O errors occur when deleting the block file */ private void abortBlockInternal(long sessionId, long blockId) throws BlockDoesNotExistException, BlockAlreadyExistsException, InvalidWorkerStateException, IOException { long lockId = mLockManager.lockBlock(sessionId, blockId, BlockLockType.WRITE); try { String path; TempBlockMeta tempBlockMeta; mMetadataReadLock.lock(); try { checkTempBlockOwnedBySession(sessionId, blockId); tempBlockMeta = mMetaManager.getTempBlockMeta(blockId); path = tempBlockMeta.getPath(); } finally { mMetadataReadLock.unlock(); } // Heavy IO is guarded by block lock but not metadata lock. This may throw IOException. Files.delete(Paths.get(path)); mMetadataWriteLock.lock(); try { mMetaManager.abortTempBlockMeta(tempBlockMeta); } catch (BlockDoesNotExistException e) { throw Throwables.propagate(e); // We shall never reach here } finally { mMetadataWriteLock.unlock(); } } finally { mLockManager.unlockBlock(lockId); } }
/** * Checks if block id is a temporary block and owned by session id. This method must be enclosed * by {@link #mMetadataLock}. * * @param sessionId the id of session * @param blockId the id of block * @throws BlockDoesNotExistException if block id can not be found in temporary blocks * @throws BlockAlreadyExistsException if block id already exists in committed blocks * @throws InvalidWorkerStateException if block id is not owned by session id */ private void checkTempBlockOwnedBySession(long sessionId, long blockId) throws BlockDoesNotExistException, BlockAlreadyExistsException, InvalidWorkerStateException { if (mMetaManager.hasBlockMeta(blockId)) { throw new BlockAlreadyExistsException(ExceptionMessage.TEMP_BLOCK_ID_COMMITTED, blockId); } TempBlockMeta tempBlockMeta = mMetaManager.getTempBlockMeta(blockId); long ownerSessionId = tempBlockMeta.getSessionId(); if (ownerSessionId != sessionId) { throw new InvalidWorkerStateException( ExceptionMessage.BLOCK_ID_FOR_DIFFERENT_SESSION, blockId, ownerSessionId, sessionId); } }
@Override public BlockWriter getBlockWriter(long sessionId, long blockId) throws BlockDoesNotExistException, IOException { // NOTE: a temp block is supposed to only be visible by its own writer, unnecessary to acquire // block lock here since no sharing // TODO(bin): Handle the case where multiple writers compete for the same block. mMetadataReadLock.lock(); try { TempBlockMeta tempBlockMeta = mMetaManager.getTempBlockMeta(blockId); return new LocalFileBlockWriter(tempBlockMeta.getPath()); } finally { mMetadataReadLock.unlock(); } }
/** * Commits a temp block. * * @param sessionId the id of session * @param blockId the id of block * @return destination location to move the block * @throws BlockDoesNotExistException if block id can not be found in temporary blocks * @throws BlockAlreadyExistsException if block id already exists in committed blocks * @throws InvalidWorkerStateException if block id is not owned by session id * @throws IOException if I/O errors occur when deleting the block file */ private BlockStoreLocation commitBlockInternal(long sessionId, long blockId) throws BlockAlreadyExistsException, InvalidWorkerStateException, BlockDoesNotExistException, IOException { long lockId = mLockManager.lockBlock(sessionId, blockId, BlockLockType.WRITE); try { // When committing TempBlockMeta, the final BlockMeta calculates the block size according to // the actual file size of this TempBlockMeta. Therefore, commitTempBlockMeta must happen // after moving actual block file to its committed path. BlockStoreLocation loc; String srcPath; String dstPath; TempBlockMeta tempBlockMeta; mMetadataReadLock.lock(); try { checkTempBlockOwnedBySession(sessionId, blockId); tempBlockMeta = mMetaManager.getTempBlockMeta(blockId); srcPath = tempBlockMeta.getPath(); dstPath = tempBlockMeta.getCommitPath(); loc = tempBlockMeta.getBlockLocation(); } finally { mMetadataReadLock.unlock(); } // Heavy IO is guarded by block lock but not metadata lock. This may throw IOException. FileUtils.move(srcPath, dstPath); mMetadataWriteLock.lock(); try { mMetaManager.commitTempBlockMeta(tempBlockMeta); } catch (BlockAlreadyExistsException e) { throw Throwables.propagate(e); // we shall never reach here } catch (BlockDoesNotExistException e) { throw Throwables.propagate(e); // we shall never reach here } catch (WorkerOutOfSpaceException e) { throw Throwables.propagate(e); // we shall never reach here } finally { mMetadataWriteLock.unlock(); } return loc; } finally { mLockManager.unlockBlock(lockId); } }
/** * Increases the temp block size only if this temp block's parent dir has enough available space. * * @param blockId block Id * @param additionalBytes additional bytes to request for this block * @return a pair of boolean and {@link BlockStoreLocation}. The boolean indicates if the * operation succeeds and the {@link BlockStoreLocation} denotes where to free more space if * it fails. * @throws BlockDoesNotExistException if this block is not found */ private Pair<Boolean, BlockStoreLocation> requestSpaceInternal(long blockId, long additionalBytes) throws BlockDoesNotExistException { // NOTE: a temp block is supposed to be visible for its own writer, unnecessary to acquire // block lock here since no sharing mMetadataWriteLock.lock(); try { TempBlockMeta tempBlockMeta = mMetaManager.getTempBlockMeta(blockId); if (tempBlockMeta.getParentDir().getAvailableBytes() < additionalBytes) { return new Pair<Boolean, BlockStoreLocation>(false, tempBlockMeta.getBlockLocation()); } // Increase the size of this temp block try { mMetaManager.resizeTempBlockMeta( tempBlockMeta, tempBlockMeta.getBlockSize() + additionalBytes); } catch (InvalidWorkerStateException e) { throw Throwables.propagate(e); // we shall never reach here } return new Pair<Boolean, BlockStoreLocation>(true, null); } finally { mMetadataWriteLock.unlock(); } }