private void processSnapshotDeepClean()

in hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyDeletingService.java [254:464]


    private void processSnapshotDeepClean(int delCount)
        throws IOException {
      OmSnapshotManager omSnapshotManager =
          getOzoneManager().getOmSnapshotManager();
      OmMetadataManagerImpl metadataManager = (OmMetadataManagerImpl)
          getOzoneManager().getMetadataManager();
      SnapshotChainManager snapChainManager = metadataManager
          .getSnapshotChainManager();
      Table<String, SnapshotInfo> snapshotInfoTable =
          getOzoneManager().getMetadataManager().getSnapshotInfoTable();
      List<String> deepCleanedSnapshots = new ArrayList<>();
      try (TableIterator<String, ? extends Table.KeyValue
          <String, SnapshotInfo>> iterator = snapshotInfoTable.iterator()) {

        while (delCount < keyLimitPerTask && iterator.hasNext()) {
          List<BlockGroup> keysToPurge = new ArrayList<>();
          HashMap<String, RepeatedOmKeyInfo> keysToModify = new HashMap<>();
          SnapshotInfo currSnapInfo = snapshotInfoTable.get(iterator.next().getKey());
          // Deep clean only on active snapshot. Deleted Snapshots will be
          // cleaned up by SnapshotDeletingService.
          if (currSnapInfo == null || currSnapInfo.getSnapshotStatus() != SNAPSHOT_ACTIVE ||
              currSnapInfo.getDeepClean()) {
            continue;
          }

          SnapshotInfo prevSnapInfo = SnapshotUtils.getPreviousSnapshot(getOzoneManager(), snapChainManager,
              currSnapInfo);
          if (prevSnapInfo != null &&
              (prevSnapInfo.getSnapshotStatus() != SnapshotInfo.SnapshotStatus.SNAPSHOT_ACTIVE ||
                  !OmSnapshotManager.areSnapshotChangesFlushedToDB(getOzoneManager().getMetadataManager(),
                      prevSnapInfo))) {
            continue;
          }

          try (ReferenceCounted<OmSnapshot>
              rcCurrOmSnapshot = omSnapshotManager.getSnapshot(
                  currSnapInfo.getVolumeName(),
                  currSnapInfo.getBucketName(),
                  currSnapInfo.getName())) {
            OmSnapshot currOmSnapshot = rcCurrOmSnapshot.get();

            Table<String, RepeatedOmKeyInfo> snapDeletedTable =
                currOmSnapshot.getMetadataManager().getDeletedTable();
            Table<String, String> snapRenamedTable =
                currOmSnapshot.getMetadataManager().getSnapshotRenamedTable();

            long volumeId = metadataManager.getVolumeId(
                currSnapInfo.getVolumeName());
            // Get bucketInfo for the snapshot bucket to get bucket layout.
            String dbBucketKey = metadataManager.getBucketKey(
                currSnapInfo.getVolumeName(), currSnapInfo.getBucketName());
            OmBucketInfo bucketInfo = metadataManager.getBucketTable()
                .get(dbBucketKey);

            if (bucketInfo == null) {
              throw new IllegalStateException("Bucket " + "/" + currSnapInfo
                  .getVolumeName() + "/" + currSnapInfo.getBucketName() +
                  " is not found. BucketInfo should not be null for" +
                  " snapshotted bucket. The OM is in unexpected state.");
            }

            String snapshotBucketKey = dbBucketKey + OzoneConsts.OM_KEY_PREFIX;
            SnapshotInfo previousSnapshot = SnapshotUtils.getPreviousSnapshot(getOzoneManager(), snapChainManager,
                currSnapInfo);
            SnapshotInfo previousToPrevSnapshot = null;

            if (previousSnapshot != null) {
              previousToPrevSnapshot = SnapshotUtils.getPreviousSnapshot(getOzoneManager(), snapChainManager,
                  previousSnapshot);
            }

            Table<String, OmKeyInfo> previousKeyTable = null;
            Table<String, String> prevRenamedTable = null;
            ReferenceCounted<OmSnapshot> rcPrevOmSnapshot = null;

            // Split RepeatedOmKeyInfo and update current snapshot
            // deletedKeyTable and next snapshot deletedKeyTable.
            if (previousSnapshot != null) {
              rcPrevOmSnapshot = omSnapshotManager.getSnapshot(
                  previousSnapshot.getVolumeName(),
                  previousSnapshot.getBucketName(),
                  previousSnapshot.getName());
              OmSnapshot omPreviousSnapshot = rcPrevOmSnapshot.get();

              previousKeyTable = omPreviousSnapshot.getMetadataManager()
                  .getKeyTable(bucketInfo.getBucketLayout());
              prevRenamedTable = omPreviousSnapshot
                  .getMetadataManager().getSnapshotRenamedTable();
            }

            Table<String, OmKeyInfo> previousToPrevKeyTable = null;
            ReferenceCounted<OmSnapshot> rcPrevToPrevOmSnapshot = null;
            if (previousToPrevSnapshot != null) {
              rcPrevToPrevOmSnapshot = omSnapshotManager.getSnapshot(
                  previousToPrevSnapshot.getVolumeName(),
                  previousToPrevSnapshot.getBucketName(),
                  previousToPrevSnapshot.getName());
              OmSnapshot omPreviousToPrevSnapshot = rcPrevToPrevOmSnapshot.get();

              previousToPrevKeyTable = omPreviousToPrevSnapshot
                  .getMetadataManager()
                  .getKeyTable(bucketInfo.getBucketLayout());
            }

            try (TableIterator<String, ? extends Table.KeyValue<String,
                RepeatedOmKeyInfo>> deletedIterator = snapDeletedTable
                .iterator()) {

              String lastKeyInCurrentRun = null;
              String deletedTableSeek = snapshotSeekMap.getOrDefault(
                  currSnapInfo.getTableKey(), snapshotBucketKey);
              deletedIterator.seek(deletedTableSeek);
              // To avoid processing the last key from the previous
              // run again.
              if (!deletedTableSeek.equals(snapshotBucketKey) &&
                  deletedIterator.hasNext()) {
                deletedIterator.next();
              }

              while (deletedIterator.hasNext() && delCount < keyLimitPerTask) {
                Table.KeyValue<String, RepeatedOmKeyInfo>
                    deletedKeyValue = deletedIterator.next();
                String deletedKey = deletedKeyValue.getKey();
                lastKeyInCurrentRun = deletedKey;

                // Exit if it is out of the bucket scope.
                if (!deletedKey.startsWith(snapshotBucketKey)) {
                  break;
                }

                RepeatedOmKeyInfo repeatedOmKeyInfo =
                    deletedKeyValue.getValue();

                List<BlockGroup> blockGroupList = new ArrayList<>();
                RepeatedOmKeyInfo newRepeatedOmKeyInfo =
                    new RepeatedOmKeyInfo();
                for (OmKeyInfo keyInfo : repeatedOmKeyInfo.getOmKeyInfoList()) {
                  if (previousSnapshot != null) {
                    // Calculates the exclusive size for the previous
                    // snapshot. See Java Doc for more info.
                    calculateExclusiveSize(previousSnapshot,
                        previousToPrevSnapshot, keyInfo, bucketInfo, volumeId,
                        snapRenamedTable, previousKeyTable, prevRenamedTable,
                        previousToPrevKeyTable, exclusiveSizeMap,
                        exclusiveReplicatedSizeMap);
                  }

                  if (isKeyReclaimable(previousKeyTable, snapRenamedTable,
                      keyInfo, bucketInfo, volumeId, null)) {
                    List<BlockGroup> blocksForKeyDelete = currOmSnapshot
                        .getMetadataManager()
                        .getBlocksForKeyDelete(deletedKey);
                    if (blocksForKeyDelete != null) {
                      blockGroupList.addAll(blocksForKeyDelete);
                    }
                    delCount++;
                  } else {
                    newRepeatedOmKeyInfo.addOmKeyInfo(keyInfo);
                  }
                }

                if (!newRepeatedOmKeyInfo.getOmKeyInfoList().isEmpty() &&
                    newRepeatedOmKeyInfo.getOmKeyInfoList().size() !=
                        repeatedOmKeyInfo.getOmKeyInfoList().size()) {
                  keysToModify.put(deletedKey, newRepeatedOmKeyInfo);
                }

                if (newRepeatedOmKeyInfo.getOmKeyInfoList().size() !=
                    repeatedOmKeyInfo.getOmKeyInfoList().size()) {
                  keysToPurge.addAll(blockGroupList);
                }
              }

              if (delCount < keyLimitPerTask) {
                // Deep clean is completed, we can update the SnapInfo.
                deepCleanedSnapshots.add(currSnapInfo.getTableKey());
                // exclusiveSizeList contains check is used to prevent
                // case where there is no entry in deletedTable, this
                // will throw NPE when we submit request.
                if (previousSnapshot != null && exclusiveSizeMap
                    .containsKey(previousSnapshot.getTableKey())) {
                  completedExclusiveSizeSet.add(
                      previousSnapshot.getTableKey());
                }

                snapshotSeekMap.remove(currSnapInfo.getTableKey());
              } else {
                // There are keys that still needs processing
                // we can continue from it in the next iteration
                if (lastKeyInCurrentRun != null) {
                  snapshotSeekMap.put(currSnapInfo.getTableKey(),
                      lastKeyInCurrentRun);
                }
              }

              if (!keysToPurge.isEmpty()) {
                processKeyDeletes(keysToPurge, currOmSnapshot.getKeyManager(),
                    keysToModify, currSnapInfo.getTableKey(),
                    Optional.ofNullable(previousSnapshot).map(SnapshotInfo::getSnapshotId).orElse(null));
              }
            } finally {
              IOUtils.closeQuietly(rcPrevOmSnapshot, rcPrevToPrevOmSnapshot);
            }
          }

        }
      }

      updateDeepCleanedSnapshots(deepCleanedSnapshots);
      updateSnapshotExclusiveSize();
    }