hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/block/BlockManagerImpl.java
@Override
  public void deleteBlocks(List<String> blockIDs) throws IOException {
    if (!nodeManager.isOutOfChillMode()) {
      throw new SCMException("Unable to delete block while in chill mode",
          CHILL_MODE_EXCEPTION);
    }

    lock.lock();
    LOG.info("Deleting blocks {}", String.join(",", blockIDs));
    Map<String, List<String>> containerBlocks = new HashMap<>();
    BatchOperation batch = new BatchOperation();
    BatchOperation rollbackBatch = new BatchOperation();
    // TODO: track the block size info so that we can reclaim the container
    // TODO: used space when the block is deleted.
    try {
      for (String blockKey : blockIDs) {
        byte[] blockKeyBytes = DFSUtil.string2Bytes(blockKey);
        byte[] containerBytes = blockStore.get(blockKeyBytes);
        if (containerBytes == null) {
          throw new SCMException(
              "Specified block key does not exist. key : " + blockKey,
              FAILED_TO_FIND_BLOCK);
        }
        batch.delete(blockKeyBytes);
        rollbackBatch.put(blockKeyBytes, containerBytes);

        // Merge blocks to a container to blocks mapping,
        // prepare to persist this info to the deletedBlocksLog.
        String containerName = DFSUtil.bytes2String(containerBytes);
        if (containerBlocks.containsKey(containerName)) {
          containerBlocks.get(containerName).add(blockKey);
        } else {
          List<String> item = new ArrayList<>();
          item.add(blockKey);
          containerBlocks.put(containerName, item);
        }
      }

      // We update SCM DB first, so if this step fails, we end up here,
      // nothing gets into the delLog so no blocks will be accidentally
      // removed. If we write the log first, once log is written, the
      // async deleting service will start to scan and might be picking
      // up some blocks to do real deletions, that might cause data loss.
      blockStore.writeBatch(batch);
      try {
        deletedBlockLog.addTransactions(containerBlocks);
      } catch (IOException e) {
        try {
          // If delLog update is failed, we need to rollback the changes.
          blockStore.writeBatch(rollbackBatch);
        } catch (IOException rollbackException) {
          // This is a corner case. AddTX fails and rollback also fails,
          // this will leave these blocks in inconsistent state. They were
          // moved to pending deletion state in SCM DB but were not written
          // into delLog so real deletions would not be done. Blocks become
          // to be invisible from namespace but actual data are not removed.
          // We log an error here so admin can manually check and fix such
          // errors.
          LOG.error(
              "Blocks might be in inconsistent state because"
                  + " they were moved to pending deletion state in SCM DB but"
                  + " not written into delLog. Admin can manually add them"
                  + " into delLog for deletions. Inconsistent block list: {}",
              String.join(",", blockIDs),
              e);
          throw rollbackException;
        }
        throw new IOException(
            "Skip writing the deleted blocks info to"
                + " the delLog because addTransaction fails. Batch skipped: "
                + String.join(",", blockIDs),
            e);
      }
      // TODO: Container report handling of the deleted blocks:
      // Remove tombstone and update open container usage.
      // We will revisit this when the closed container replication is done.
    } finally {
      lock.unlock();
    }
  }
/**
   * Deletes a list of blocks in an atomic operation. Internally, SCM writes
   * these blocks into a
   * {@link DeletedBlockLog} and deletes them from SCM DB. If this is
   * successful, given blocks are
   * entering pending deletion state and becomes invisible from SCM namespace.
   *
   * @param blockIDs block IDs. This is often the list of blocks of a
   * particular object key.
   * @throws IOException if exception happens, non of the blocks is deleted.
   */
Deletes a list of blocks in an atomic operation. Internally, SCM writes
these blocks into a
DeletedBlockLog and deletes them from SCM DB. If this is
successful, given blocks are
entering pending deletion state and becomes invisible from SCM namespace.


Deletes a list of blocks in an atomic operation . Internally SCM writes these blocks into a DeletedBlockLog and deletes them from SCM DB . If this is successful given blocks are entering pending deletion state and becomes invisible from SCM namespace .
@Override
  public void deleteBlocks(List<String> blockIDs) throws IOException {
    if (!nodeManager.isOutOfChillMode()) {
      throw new SCMException("Unable to delete block while in chill mode",
          CHILL_MODE_EXCEPTION);
    }
    lock.lock();
    LOG.info("Deleting blocks {}", String.join(",", blockIDs));
    Map<String, List<String>> containerBlocks = new HashMap<>();
    BatchOperation batch = new BatchOperation();
    BatchOperation rollbackBatch = new BatchOperation();
    try {
      for (String blockKey : blockIDs) {
        byte[] blockKeyBytes = DFSUtil.string2Bytes(blockKey);
        byte[] containerBytes = blockStore.get(blockKeyBytes);
        if (containerBytes == null) {
          throw new SCMException(
              "Specified block key does not exist. key : " + blockKey,
              FAILED_TO_FIND_BLOCK);
        }
        batch.delete(blockKeyBytes);
        rollbackBatch.put(blockKeyBytes, containerBytes);
        String containerName = DFSUtil.bytes2String(containerBytes);
        if (containerBlocks.containsKey(containerName)) {
          containerBlocks.get(containerName).add(blockKey);
        } else {
          List<String> item = new ArrayList<>();
          item.add(blockKey);
          containerBlocks.put(containerName, item);
        }
      }
      blockStore.writeBatch(batch);
      try {
        deletedBlockLog.addTransactions(containerBlocks);
      } catch (IOException e) {
        try {
          blockStore.writeBatch(rollbackBatch);
        } catch (IOException rollbackException) {
          LOG.error(
              "Blocks might be in inconsistent state because"
                  + " they were moved to pending deletion state in SCM DB but"
                  + " not written into delLog. Admin can manually add them"
                  + " into delLog for deletions. Inconsistent block list: {}",
              String.join(",", blockIDs),
              e);
          throw rollbackException;
        }
        throw new IOException(
            "Skip writing the deleted blocks info to"
                + " the delLog because addTransaction fails. Batch skipped: "
                + String.join(",", blockIDs),
            e);
      }
    } finally {
      lock.unlock();
    }
  }
@ Override public void deleteBlocks ( List < String > blockIDs ) throws IOException { if ( ! nodeManager . isOutOfChillMode ( ) ) { throw new SCMException ( "Unable to delete block while in chill mode" , CHILL_MODE_EXCEPTION ) ; } lock . lock ( ) ; LOG . info ( "Deleting blocks {}" , String . join ( "," , blockIDs ) ) ; Map < String , List < String > > containerBlocks = new HashMap < > ( ) ; BatchOperation batch = new BatchOperation ( ) ; BatchOperation rollbackBatch = new BatchOperation ( ) ; try { for ( String blockKey : blockIDs ) { byte [ ] blockKeyBytes = DFSUtil . string2Bytes ( blockKey ) ; byte [ ] containerBytes = blockStore . get ( blockKeyBytes ) ; if ( containerBytes == null ) { throw new SCMException ( "Specified block key does not exist. key : " + blockKey , FAILED_TO_FIND_BLOCK ) ; } batch . delete ( blockKeyBytes ) ; rollbackBatch . put ( blockKeyBytes , containerBytes ) ; String containerName = DFSUtil . bytes2String ( containerBytes ) ; if ( containerBlocks . containsKey ( containerName ) ) { containerBlocks . get ( containerName ) . add ( blockKey ) ; } else { List < String > item = new ArrayList < > ( ) ; item . add ( blockKey ) ; containerBlocks . put ( containerName , item ) ; } } blockStore . writeBatch ( batch ) ; try { deletedBlockLog . addTransactions ( containerBlocks ) ; } catch ( IOException e ) { try { blockStore . writeBatch ( rollbackBatch ) ; } catch ( IOException rollbackException ) { LOG . error ( "Blocks might be in inconsistent state because" + " they were moved to pending deletion state in SCM DB but" + " not written into delLog. Admin can manually add them" + " into delLog for deletions. Inconsistent block list: {}" , String . join ( "," , blockIDs ) , e ) ; throw rollbackException ; } throw new IOException ( "Skip writing the deleted blocks info to" + " the delLog because addTransaction fails. Batch skipped: " + String . join ( "," , blockIDs ) , e ) ; } } finally { lock . unlock ( ) ; } }
Deletes a list of blocks in an atomic operation.
Deletes a list of blocks in an atomic operation .
// TODO: track the block size info so that we can reclaim the container // TODO: used space when the block is deleted. // Merge blocks to a container to blocks mapping, // prepare to persist this info to the deletedBlocksLog. // We update SCM DB first, so if this step fails, we end up here, // nothing gets into the delLog so no blocks will be accidentally // removed. If we write the log first, once log is written, the // async deleting service will start to scan and might be picking // up some blocks to do real deletions, that might cause data loss. // If delLog update is failed, we need to rollback the changes. // This is a corner case. AddTX fails and rollback also fails, // this will leave these blocks in inconsistent state. They were // moved to pending deletion state in SCM DB but were not written // into delLog so real deletions would not be done. Blocks become // to be invisible from namespace but actual data are not removed. // We log an error here so admin can manually check and fix such // errors. // TODO: Container report handling of the deleted blocks: // Remove tombstone and update open container usage. // We will revisit this when the closed container replication is done.