示例#1
0
  @Test
  public void reserveTest() throws Exception {
    // Reserve on top tier
    long blockId = 100;
    BlockStoreLocation tier0 = BlockStoreLocation.anyDirInTier(StorageLevelAlias.MEM.getValue());
    for (int i = 0; i < 3; i++) {
      TieredBlockStoreTestUtils.cache(SESSION_ID, blockId++, BLOCK_SIZE, mBlockStore, tier0);
    }
    CommonUtils.sleepMs(
        WorkerContext.getConf().getLong(Constants.WORKER_SPACE_RESERVER_INTERVAL_MS));
    BlockStoreMeta storeMeta = mBlockStore.getBlockStoreMeta();
    Assert.assertEquals(3 * BLOCK_SIZE, storeMeta.getUsedBytes());
    List<Long> usedBytesOnTiers = storeMeta.getUsedBytesOnTiers();
    Assert.assertEquals(
        2 * BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.MEM.getValue() - 1));
    Assert.assertEquals(
        BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.HDD.getValue() - 1));

    // Reserve on under tier
    for (int i = 0; i < 7; i++) {
      TieredBlockStoreTestUtils.cache(SESSION_ID, blockId++, BLOCK_SIZE, mBlockStore, tier0);
    }
    CommonUtils.sleepMs(
        WorkerContext.getConf().getLong(Constants.WORKER_SPACE_RESERVER_INTERVAL_MS));
    storeMeta = mBlockStore.getBlockStoreMeta();
    Assert.assertEquals(9 * BLOCK_SIZE, storeMeta.getUsedBytes());
    usedBytesOnTiers = storeMeta.getUsedBytesOnTiers();
    Assert.assertEquals(
        2 * BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.MEM.getValue() - 1));
    Assert.assertEquals(
        7 * BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.HDD.getValue() - 1));
  }
 /**
  * Gets the StorageDir given its location in the store.
  *
  * @param location Location of the dir
  * @return the StorageDir object
  * @throws IllegalArgumentException if location is not a specific dir or the location is invalid
  */
 public synchronized StorageDir getDir(BlockStoreLocation location) {
   if (location.equals(BlockStoreLocation.anyTier())
       || location.equals(BlockStoreLocation.anyDirInTier(location.tierAlias()))) {
     throw new IllegalArgumentException(
         "Failed to get block path: " + location + " is not a specific dir.");
   }
   return getTier(location.tierAlias()).getDir(location.dir());
 }
  /**
   * Moves the metadata of an existing block to another location or throws IOExceptions.
   *
   * @param blockMeta the meta data of the block to move
   * @param newLocation new location of the block
   * @return the new block metadata if success, absent otherwise
   * @throws IllegalArgumentException when the newLocation is not in the tiered storage
   * @throws NotFoundException when the block to move is not found
   * @throws AlreadyExistsException when the block to move already exists in the destination
   * @throws OutOfSpaceException when destination have no extra space to hold the block to move
   */
  public synchronized BlockMeta moveBlockMeta(BlockMeta blockMeta, BlockStoreLocation newLocation)
      throws NotFoundException, AlreadyExistsException, OutOfSpaceException {
    // If existing location belongs to the target location, simply return the current block meta.
    BlockStoreLocation oldLocation = blockMeta.getBlockLocation();
    if (oldLocation.belongTo(newLocation)) {
      LOG.info("moveBlockMeta: moving {} to {} is a noop", oldLocation, newLocation);
      return blockMeta;
    }

    long blockSize = blockMeta.getBlockSize();
    int newTierAlias = newLocation.tierAlias();
    StorageTier newTier = getTier(newTierAlias);
    StorageDir newDir = null;
    if (newLocation.equals(BlockStoreLocation.anyDirInTier(newTierAlias))) {
      for (StorageDir dir : newTier.getStorageDirs()) {
        if (dir.getAvailableBytes() >= blockSize) {
          newDir = dir;
          break;
        }
      }
    } else {
      StorageDir dir = newTier.getDir(newLocation.dir());
      if (dir.getAvailableBytes() >= blockSize) {
        newDir = dir;
      }
    }

    if (newDir == null) {
      throw new OutOfSpaceException(
          "Failed to move BlockMeta: newLocation "
              + newLocation
              + " does not have enough space for "
              + blockSize
              + " bytes");
    }
    StorageDir oldDir = blockMeta.getParentDir();
    oldDir.removeBlockMeta(blockMeta);
    BlockMeta newBlockMeta = new BlockMeta(blockMeta.getBlockId(), blockSize, newDir);
    newDir.addBlockMeta(newBlockMeta);
    return newBlockMeta;
  }
  /**
   * Gets the amount of available space of given location in bytes. Master queries the total number
   * of bytes available on each tier of the worker, and Evictor/Allocator often cares about the
   * bytes at a {@link StorageDir}.
   *
   * @param location location the check available bytes
   * @return available bytes
   * @throws IllegalArgumentException when location does not belong to tiered storage
   */
  public synchronized long getAvailableBytes(BlockStoreLocation location) {
    long spaceAvailable = 0;

    if (location.equals(BlockStoreLocation.anyTier())) {
      for (StorageTier tier : mTiers) {
        spaceAvailable += tier.getAvailableBytes();
      }
      return spaceAvailable;
    }

    int tierAlias = location.tierAlias();
    StorageTier tier = getTier(tierAlias);
    // TODO: This should probably be max of the capacity bytes in the dirs?
    if (location.equals(BlockStoreLocation.anyDirInTier(tierAlias))) {
      return tier.getAvailableBytes();
    }

    int dirIndex = location.dir();
    StorageDir dir = tier.getDir(dirIndex);
    return dir.getAvailableBytes();
  }
 /**
  * Moves a block from its current location to a target location, currently only tier level moves
  * are supported
  *
  * @param sessionId The id of the client
  * @param blockId The id of the block to move
  * @param tierAlias The alias of the tier to move the block to
  * @throws IllegalArgumentException if tierAlias is out of range of tiered storage
  * @throws BlockDoesNotExistException if blockId cannot be found
  * @throws BlockAlreadyExistsException if blockId already exists in committed blocks of the
  *     newLocation
  * @throws InvalidWorkerStateException if blockId has not been committed
  * @throws WorkerOutOfSpaceException if newLocation does not have enough extra space to hold the
  *     block
  * @throws IOException if block cannot be moved from current location to newLocation
  */
 public void moveBlock(long sessionId, long blockId, String tierAlias)
     throws BlockDoesNotExistException, BlockAlreadyExistsException, InvalidWorkerStateException,
         WorkerOutOfSpaceException, IOException {
   BlockStoreLocation dst = BlockStoreLocation.anyDirInTier(tierAlias);
   mBlockStore.moveBlock(sessionId, blockId, dst);
 }
 /**
  * Frees space to make a specific amount of bytes available in the tier.
  *
  * @param sessionId the session ID
  * @param availableBytes the amount of free space in bytes
  * @param tierAlias the alias of the tier to free space
  * @throws WorkerOutOfSpaceException if there is not enough space
  * @throws BlockDoesNotExistException if blocks can not be found
  * @throws IOException if blocks fail to be moved or deleted on file system
  * @throws BlockAlreadyExistsException if blocks to move already exists in destination location
  * @throws InvalidWorkerStateException if blocks to move/evict is uncommitted
  */
 public void freeSpace(long sessionId, long availableBytes, String tierAlias)
     throws WorkerOutOfSpaceException, BlockDoesNotExistException, IOException,
         BlockAlreadyExistsException, InvalidWorkerStateException {
   BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias);
   mBlockStore.freeSpace(sessionId, availableBytes, location);
 }
 /**
  * Creates a block. This method is only called from a data server.
  *
  * <p>Call {@link #getTempBlockWriterRemote(long, long)} to get a writer for writing to the block.
  *
  * @param sessionId The id of the client
  * @param blockId The id of the block to be created
  * @param tierAlias The alias of the tier to place the new block in
  * @param initialBytes The initial amount of bytes to be allocated
  * @throws IllegalArgumentException if location does not belong to tiered storage
  * @throws BlockAlreadyExistsException if blockId already exists, either temporary or committed,
  *     or block in eviction plan already exists
  * @throws WorkerOutOfSpaceException if this Store has no more space than the initialBlockSize
  * @throws IOException if blocks in eviction plan fail to be moved or deleted
  */
 public void createBlockRemote(long sessionId, long blockId, String tierAlias, long initialBytes)
     throws BlockAlreadyExistsException, WorkerOutOfSpaceException, IOException {
   BlockStoreLocation loc = BlockStoreLocation.anyDirInTier(tierAlias);
   TempBlockMeta createdBlock = mBlockStore.createBlockMeta(sessionId, blockId, loc, initialBytes);
   FileUtils.createBlockPath(createdBlock.getPath());
 }