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));
}
}
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;
}
}
use of alluxio.worker.block.meta.StorageDirView in project alluxio by Alluxio.
the class SwapRestoreTask method getSwapRestorePlan.
/**
* @return the pair of <blocks-to-remove, blocks-to-transfer> 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);
}
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;
}
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()));
}
Aggregations