Search in sources :

Example 21 with StorageDirView

use of alluxio.worker.block.meta.StorageDirView in project alluxio by Alluxio.

the class TieredBlockStore method freeSpace.

/**
 * Free space is the entry for immediate block deletion in order to open up space for
 * new or ongoing blocks.
 *
 * - New blocks creations will not try to free space until all tiers are out of space.
 * - Ongoing blocks could end up freeing space oftenly, when the file's origin location is
 * low on space.
 *
 * This method is synchronized in order to prevent race in its only client, allocations.
 * If not synchronized, new allocations could steal space reserved by ongoing ones.
 * Removing synchronized requires implementing retries to this call along with an optimal
 * locking strategy for fairness.
 *
 * TODO(ggezer): Remove synchronized.
 *
 * @param sessionId the session id
 * @param minContiguousBytes the minimum amount of contigious free space in bytes
 * @param minAvailableBytes the minimum amount of free space in bytes
 * @param location the location to free space
 * @throws WorkerOutOfSpaceException if there is not enough space to fulfill minimum requirement
 */
@VisibleForTesting
public synchronized void freeSpace(long sessionId, long minContiguousBytes, long minAvailableBytes, BlockStoreLocation location) throws WorkerOutOfSpaceException, IOException {
    LOG.debug("freeSpace: sessionId={}, minContiguousBytes={}, minAvailableBytes={}, location={}", sessionId, minAvailableBytes, minAvailableBytes, location);
    // TODO(ggezer): Too much memory pressure when pinned-inodes list is large.
    BlockMetadataEvictorView evictorView = getUpdatedView();
    boolean contiguousSpaceFound = false;
    boolean availableBytesFound = false;
    int blocksIterated = 0;
    int blocksRemoved = 0;
    int spaceFreed = 0;
    // List of all dirs that belong to the given location.
    List<StorageDirView> dirViews = evictorView.getDirs(location);
    Iterator<Long> evictionCandidates = mBlockIterator.getIterator(location, BlockOrder.NATURAL);
    while (true) {
        // Check if minContiguousBytes is satisfied.
        if (!contiguousSpaceFound) {
            for (StorageDirView dirView : dirViews) {
                if (dirView.getAvailableBytes() >= minContiguousBytes) {
                    contiguousSpaceFound = true;
                    break;
                }
            }
        }
        // Check minAvailableBytes is satisfied.
        if (!availableBytesFound) {
            if (evictorView.getAvailableBytes(location) >= minAvailableBytes) {
                availableBytesFound = true;
            }
        }
        if (contiguousSpaceFound && availableBytesFound) {
            break;
        }
        if (!evictionCandidates.hasNext()) {
            break;
        }
        long blockToDelete = evictionCandidates.next();
        blocksIterated++;
        if (evictorView.isBlockEvictable(blockToDelete)) {
            try {
                BlockMeta blockMeta = mMetaManager.getBlockMeta(blockToDelete);
                removeBlockFileAndMeta(blockMeta);
                blocksRemoved++;
                for (BlockStoreEventListener listener : mBlockStoreEventListeners) {
                    synchronized (listener) {
                        listener.onRemoveBlockByWorker(sessionId, blockMeta.getBlockId());
                        listener.onRemoveBlock(sessionId, blockMeta.getBlockId(), blockMeta.getBlockLocation());
                    }
                }
                spaceFreed += blockMeta.getBlockSize();
            } catch (BlockDoesNotExistException e) {
                LOG.warn("Failed to evict blockId {}, it could be already deleted", blockToDelete);
                continue;
            }
        }
    }
    if (!contiguousSpaceFound || !availableBytesFound) {
        throw new WorkerOutOfSpaceException(String.format("Failed to free %d bytes space at location %s. " + "Min contiguous requested: %d, Min available requested: %d, " + "Blocks iterated: %d, Blocks removed: %d, Space freed: %d", minAvailableBytes, location.tierAlias(), minContiguousBytes, minAvailableBytes, blocksIterated, blocksRemoved, spaceFreed));
    }
}
Also used : StorageDirView(alluxio.worker.block.meta.StorageDirView) BlockMeta(alluxio.worker.block.meta.BlockMeta) TempBlockMeta(alluxio.worker.block.meta.TempBlockMeta) BlockDoesNotExistException(alluxio.exception.BlockDoesNotExistException) WorkerOutOfSpaceException(alluxio.exception.WorkerOutOfSpaceException) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 22 with StorageDirView

use of alluxio.worker.block.meta.StorageDirView in project alluxio by Alluxio.

the class TieredBlockStore method createBlockMetaInternal.

/**
 * Creates a temp block meta only if allocator finds available space. This method will not trigger
 * any eviction.
 *
 * @param sessionId session id
 * @param blockId block id
 * @param newBlock true if this temp block is created for a new block
 * @param options block allocation options
 * @return a temp block created if successful, or null if allocation failed (instead of throwing
 *         {@link WorkerOutOfSpaceException} because allocation failure could be an expected case)
 * @throws BlockAlreadyExistsException if there is already a block with the same block id
 */
private TempBlockMeta createBlockMetaInternal(long sessionId, long blockId, boolean newBlock, AllocateOptions options) throws BlockAlreadyExistsException, WorkerOutOfSpaceException, IOException {
    try (LockResource r = new LockResource(mMetadataWriteLock)) {
        // unnecessary to acquire block lock here since no sharing.
        if (newBlock) {
            checkTempBlockIdAvailable(blockId);
        }
        // Allocate space.
        StorageDirView dirView = allocateSpace(sessionId, options);
        // TODO(carson): Add tempBlock to corresponding storageDir and remove the use of
        // StorageDirView.createTempBlockMeta.
        TempBlockMeta tempBlock = dirView.createTempBlockMeta(sessionId, blockId, options.getSize());
        try {
            // Add allocated temp block to metadata manager. This should never fail if allocator
            // correctly assigns a StorageDir.
            mMetaManager.addTempBlockMeta(tempBlock);
        } catch (WorkerOutOfSpaceException | BlockAlreadyExistsException e) {
            // If we reach here, allocator is not working properly
            LOG.error("Unexpected failure: {} bytes allocated at {} by allocator, " + "but addTempBlockMeta failed", options.getSize(), options.getLocation());
            throw Throwables.propagate(e);
        }
        return tempBlock;
    }
}
Also used : BlockAlreadyExistsException(alluxio.exception.BlockAlreadyExistsException) LockResource(alluxio.resource.LockResource) StorageDirView(alluxio.worker.block.meta.StorageDirView) TempBlockMeta(alluxio.worker.block.meta.TempBlockMeta) WorkerOutOfSpaceException(alluxio.exception.WorkerOutOfSpaceException)

Example 23 with StorageDirView

use of alluxio.worker.block.meta.StorageDirView in project alluxio by Alluxio.

the class SwapRestoreTask method getSwapRestorePlan.

/**
 * @return the pair of &lt;blocks-to-remove, blocks-to-transfer&gt; for swap-restore plan
 */
private Pair<List<Long>, List<BlockTransferInfo>> getSwapRestorePlan() {
    StorageTierAssoc storageTierAssoc = mMetadataManager.getStorageTierAssoc();
    List<Long> blocksToRemove = new LinkedList<>();
    List<BlockTransferInfo> blocksToTransfer = new LinkedList<>();
    long cascadingFromAbove = 0;
    for (StorageTierView tierView : mEvictorView.getTierViews()) {
        int currentTierOrdinal = tierView.getTierViewOrdinal();
        String tierAlias = storageTierAssoc.getAlias(currentTierOrdinal);
        BlockStoreLocation destLocation = BlockStoreLocation.anyDirInTier(tierAlias);
        if (currentTierOrdinal < storageTierAssoc.size() - 1) {
            destLocation = BlockStoreLocation.anyDirInTier(storageTierAssoc.getAlias(currentTierOrdinal + 1));
        }
        boolean lastTier = currentTierOrdinal == storageTierAssoc.size() - 1;
        long tierReservedBytes = 0;
        long tierCapacityBytes = 0;
        long tierCommittedBytes = 0;
        for (StorageDirView dirView : tierView.getDirViews()) {
            tierReservedBytes += dirView.getReservedBytes();
            tierCapacityBytes += dirView.getCapacityBytes();
            tierCommittedBytes += dirView.getCommittedBytes();
        }
        long bytesBeyondReserve = (tierCommittedBytes + cascadingFromAbove) - (tierCapacityBytes - tierReservedBytes);
        long moveOutBytes = Math.max(0, bytesBeyondReserve);
        // Store for the next tier.
        cascadingFromAbove = moveOutBytes;
        Iterator<Long> tierIterator = mMetadataManager.getBlockIterator().getIterator(BlockStoreLocation.anyDirInTier(tierAlias), BlockOrder.NATURAL);
        while (tierIterator.hasNext() && moveOutBytes > 0) {
            long blockId = tierIterator.next();
            try {
                BlockMeta nextBlockFromTier = mEvictorView.getBlockMeta(blockId);
                if (nextBlockFromTier == null) {
                    LOG.debug("Block:{} exist but not available for moving.", blockId);
                    continue;
                }
                moveOutBytes -= nextBlockFromTier.getBlockSize();
                if (lastTier) {
                    blocksToRemove.add(nextBlockFromTier.getBlockId());
                } else {
                    blocksToTransfer.add(BlockTransferInfo.createMove(nextBlockFromTier.getBlockLocation(), nextBlockFromTier.getBlockId(), destLocation));
                }
            } catch (BlockDoesNotExistException e) {
                LOG.warn("Failed to find block:{} during cascading calculation.", blockId);
            }
        }
    }
    if (LOG.isDebugEnabled()) {
        LOG.debug("Generated swap-restore plan with {} deletions and {} transfers.\n" + "Block deletions:\n ->{}\nBlock transfers:\n ->{}", blocksToRemove.size(), blocksToTransfer.size(), blocksToRemove.stream().map(Object::toString).collect(Collectors.joining(",\n ->")), blocksToTransfer.stream().map(Object::toString).collect(Collectors.joining(",\n ->")));
    }
    return new Pair<>(blocksToRemove, blocksToTransfer);
}
Also used : BlockTransferInfo(alluxio.worker.block.evictor.BlockTransferInfo) StorageTierAssoc(alluxio.StorageTierAssoc) StorageDirView(alluxio.worker.block.meta.StorageDirView) LinkedList(java.util.LinkedList) StorageTierView(alluxio.worker.block.meta.StorageTierView) BlockStoreLocation(alluxio.worker.block.BlockStoreLocation) BlockMeta(alluxio.worker.block.meta.BlockMeta) BlockDoesNotExistException(alluxio.exception.BlockDoesNotExistException) Pair(alluxio.collections.Pair)

Example 24 with StorageDirView

use of alluxio.worker.block.meta.StorageDirView in project alluxio by Alluxio.

the class SwapRestoreTask method getBalancingTransfersList.

/**
 * @return the list of transfer in order to balance swap-space within tier
 */
private List<BlockTransferInfo> getBalancingTransfersList() {
    List<BlockTransferInfo> transferInfos = new LinkedList<>();
    for (StorageTierView tierView : mEvictorView.getTierViews()) {
        for (StorageDirView dirView : tierView.getDirViews()) {
            Iterator<Long> dirBlockIter = mMetadataManager.getBlockIterator().getIterator(new BlockStoreLocation(tierView.getTierViewAlias(), dirView.getDirViewIndex()), BlockOrder.NATURAL);
            while (dirBlockIter.hasNext() && dirView.getAvailableBytes() < dirView.getReservedBytes()) {
                long blockId = dirBlockIter.next();
                try {
                    BlockMeta movingOutBlock = mEvictorView.getBlockMeta(blockId);
                    if (movingOutBlock == null) {
                        LOG.debug("Block:{} exist but not available for balancing.", blockId);
                        continue;
                    }
                    // Find where to move the block.
                    StorageDirView dstDirView = null;
                    for (StorageDirView candidateDirView : tierView.getDirViews()) {
                        if (candidateDirView.getDirViewIndex() == dirView.getDirViewIndex()) {
                            continue;
                        }
                        if (candidateDirView.getAvailableBytes() - candidateDirView.getReservedBytes() >= movingOutBlock.getBlockSize()) {
                            dstDirView = candidateDirView;
                            break;
                        }
                    }
                    if (dstDirView == null) {
                        LOG.warn("Could not balance swap-restore space for location: {}", dirView.toBlockStoreLocation());
                        break;
                    }
                    // TODO(ggezer): Consider allowing evictions for this move.
                    transferInfos.add(BlockTransferInfo.createMove(movingOutBlock.getBlockLocation(), blockId, dstDirView.toBlockStoreLocation()));
                    // Account for moving-out blocks.
                    ((StorageDirEvictorView) dirView).markBlockMoveOut(blockId, movingOutBlock.getBlockSize());
                    // Account for moving-in blocks.
                    ((StorageDirEvictorView) dstDirView).markBlockMoveIn(blockId, movingOutBlock.getBlockSize());
                } catch (BlockDoesNotExistException e) {
                    LOG.warn("Failed to find metadata for block:{} during swap-restore balancing.", blockId);
                }
            }
        }
    }
    if (LOG.isDebugEnabled()) {
        LOG.debug("Generated {} balance transfers:\n ->{}", transferInfos.size(), transferInfos.stream().map(Object::toString).collect(Collectors.joining(",\n ->")));
    }
    return transferInfos;
}
Also used : BlockTransferInfo(alluxio.worker.block.evictor.BlockTransferInfo) StorageDirEvictorView(alluxio.worker.block.meta.StorageDirEvictorView) StorageDirView(alluxio.worker.block.meta.StorageDirView) LinkedList(java.util.LinkedList) StorageTierView(alluxio.worker.block.meta.StorageTierView) BlockStoreLocation(alluxio.worker.block.BlockStoreLocation) BlockMeta(alluxio.worker.block.meta.BlockMeta) BlockDoesNotExistException(alluxio.exception.BlockDoesNotExistException)

Example 25 with StorageDirView

use of alluxio.worker.block.meta.StorageDirView in project alluxio by Alluxio.

the class TieredBlockStore method allocateSpace.

private StorageDirView allocateSpace(long sessionId, AllocateOptions options) throws WorkerOutOfSpaceException, IOException {
    StorageDirView dirView;
    BlockMetadataView allocatorView = new BlockMetadataAllocatorView(mMetaManager, options.canUseReservedSpace());
    // Convenient way to break on failure cases, no intention to loop
    while (true) {
        if (options.isForceLocation()) {
            // Try allocating from given location. Skip the review because the location is forced.
            dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(), options.getLocation(), allocatorView, true);
            if (dirView != null) {
                return dirView;
            }
            if (options.isEvictionAllowed()) {
                LOG.debug("Free space for block expansion: freeing {} bytes on {}. ", options.getSize(), options.getLocation());
                freeSpace(sessionId, options.getSize(), options.getSize(), options.getLocation());
                // Block expansion are forcing the location. We do not want the review's opinion.
                dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(), options.getLocation(), allocatorView.refreshView(), true);
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Allocation after freeing space for block expansion, {}", dirView == null ? "no available dir." : "available bytes in dir: " + dirView.getAvailableBytes());
                }
                if (dirView == null) {
                    LOG.error("Target tier: {} has no evictable space to store {} bytes for session: {}", options.getLocation(), options.getSize(), sessionId);
                    break;
                }
            } else {
                // We are not evicting in the target tier so having no available space just
                // means the tier is currently full.
                LOG.warn("Target tier: {} has no available space to store {} bytes for session: {}", options.getLocation(), options.getSize(), sessionId);
                break;
            }
        } else {
            // Try allocating from given location. This may be rejected by the review logic.
            dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(), options.getLocation(), allocatorView, false);
            if (dirView != null) {
                return dirView;
            }
            LOG.debug("Allocate to anyTier for {} bytes on {}", options.getSize(), options.getLocation());
            dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(), BlockStoreLocation.anyTier(), allocatorView, false);
            if (dirView != null) {
                return dirView;
            }
            if (options.isEvictionAllowed()) {
                // There is no space left on worker.
                // Free more than requested by configured free-ahead size.
                long toFreeBytes = options.getSize() + FREE_AHEAD_BYTETS;
                LOG.debug("Allocation on anyTier failed. Free space for {} bytes on anyTier", toFreeBytes);
                freeSpace(sessionId, options.getSize(), toFreeBytes, BlockStoreLocation.anyTier());
                // Skip the review as we want the allocation to be in the place we just freed
                dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(), BlockStoreLocation.anyTier(), allocatorView.refreshView(), true);
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Allocation after freeing space for block creation, {} ", dirView == null ? "no available dir." : "available bytes in dir: " + dirView.getAvailableBytes());
                }
            }
        }
        if (dirView == null) {
            break;
        }
        return dirView;
    }
    throw new WorkerOutOfSpaceException(String.format("Allocation failure. Options: %s. Error:", options.toString()));
}
Also used : StorageDirView(alluxio.worker.block.meta.StorageDirView) WorkerOutOfSpaceException(alluxio.exception.WorkerOutOfSpaceException)

Aggregations

StorageDirView (alluxio.worker.block.meta.StorageDirView)33 StorageTierView (alluxio.worker.block.meta.StorageTierView)15 BlockStoreLocation (alluxio.worker.block.BlockStoreLocation)6 BlockMeta (alluxio.worker.block.meta.BlockMeta)6 TempBlockMeta (alluxio.worker.block.meta.TempBlockMeta)6 BlockDoesNotExistException (alluxio.exception.BlockDoesNotExistException)5 Pair (alluxio.collections.Pair)4 WorkerOutOfSpaceException (alluxio.exception.WorkerOutOfSpaceException)4 LockResource (alluxio.resource.LockResource)3 StorageDirEvictorView (alluxio.worker.block.meta.StorageDirEvictorView)3 ArrayList (java.util.ArrayList)3 Nullable (javax.annotation.Nullable)3 BlockAlreadyExistsException (alluxio.exception.BlockAlreadyExistsException)2 BlockTransferInfo (alluxio.worker.block.evictor.BlockTransferInfo)2 LinkedList (java.util.LinkedList)2 StorageTierAssoc (alluxio.StorageTierAssoc)1 InvalidWorkerStateException (alluxio.exception.InvalidWorkerStateException)1 DefaultBlockMeta (alluxio.worker.block.meta.DefaultBlockMeta)1 StorageDir (alluxio.worker.block.meta.StorageDir)1 StorageTier (alluxio.worker.block.meta.StorageTier)1