sstFilenames = new HashSet<>();
try (TarArchiveInputStream tarInput =
new TarArchiveInputStream(Files.newInputStream(tarball.toPath()))) {
TarArchiveEntry entry;
while ((entry = tarInput.getNextTarEntry()) != null) {
- fileNames.add(entry.getName());
+ String name = entry.getName();
+ if (name.toLowerCase().endsWith(".sst")) {
+ sstFilenames.add(entry.getName());
+ }
}
}
- return fileNames;
+ return sstFilenames;
}
// Find the tarball in the dir.
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotProvider.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotProvider.java
index 4d5f1dda1c7..bdf1f7d1dab 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotProvider.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotProvider.java
@@ -124,8 +124,6 @@ public void testDownloadCheckpoint() throws Exception {
private long getDownloadedSnapshotIndex(DBCheckpoint dbCheckpoint)
throws Exception {
- OmSnapshotUtils.createHardLinks(dbCheckpoint.getCheckpointLocation(), true);
-
TransactionInfo trxnInfoFromCheckpoint =
OzoneManagerRatisUtils.getTrxnInfoFromCheckpoint(conf,
dbCheckpoint.getCheckpointLocation());
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMDBCheckpointServletInodeBasedXfer.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMDBCheckpointServletInodeBasedXfer.java
deleted file mode 100644
index 28769f75409..00000000000
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMDBCheckpointServletInodeBasedXfer.java
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.ozone.om;
-
-import static org.apache.hadoop.hdds.utils.Archiver.includeFile;
-import static org.apache.hadoop.hdds.utils.Archiver.linkAndIncludeFile;
-import static org.apache.hadoop.hdds.utils.Archiver.tar;
-import static org.apache.hadoop.hdds.utils.HddsServerUtil.includeRatisSnapshotCompleteFlag;
-import static org.apache.hadoop.ozone.OzoneConsts.OM_CHECKPOINT_DIR;
-import static org.apache.hadoop.ozone.OzoneConsts.OM_DB_NAME;
-import static org.apache.hadoop.ozone.OzoneConsts.OZONE_DB_CHECKPOINT_REQUEST_TO_EXCLUDE_SST;
-import static org.apache.hadoop.ozone.OzoneConsts.ROCKSDB_SST_SUFFIX;
-import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RATIS_SNAPSHOT_MAX_TOTAL_SST_SIZE_DEFAULT;
-import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RATIS_SNAPSHOT_MAX_TOTAL_SST_SIZE_KEY;
-import static org.apache.hadoop.ozone.om.lock.FlatResource.SNAPSHOT_DB_LOCK;
-import static org.apache.hadoop.ozone.om.snapshot.OMDBCheckpointUtils.includeSnapshotData;
-import static org.apache.hadoop.ozone.om.snapshot.OMDBCheckpointUtils.logEstimatedTarballSize;
-import static org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils.DATA_PREFIX;
-import static org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils.DATA_SUFFIX;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Stream;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.compress.archivers.ArchiveOutputStream;
-import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
-import org.apache.commons.io.FileUtils;
-import org.apache.hadoop.hdds.conf.OzoneConfiguration;
-import org.apache.hadoop.hdds.recon.ReconConfig;
-import org.apache.hadoop.hdds.utils.DBCheckpointServlet;
-import org.apache.hadoop.hdds.utils.db.DBCheckpoint;
-import org.apache.hadoop.ozone.OzoneConsts;
-import org.apache.hadoop.ozone.lock.BootstrapStateHandler;
-import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
-import org.apache.hadoop.ozone.om.snapshot.OmSnapshotLocalDataManager;
-import org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils;
-import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.hadoop.util.Time;
-import org.apache.ozone.rocksdiff.RocksDBCheckpointDiffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Specialized OMDBCheckpointServlet implementation that transfers Ozone Manager
- * database checkpoints using inode-based deduplication.
- *
- * This servlet constructs checkpoint archives by examining file inodes,
- * ensuring that files with the same inode (i.e., hardlinks or duplicates)
- * are only transferred once. It maintains mappings from inode IDs to file
- * paths, manages hardlink information, and enforces snapshot and SST file
- * size constraints as needed.
- *
- * This approach optimizes checkpoint streaming by reducing redundant data
- * transfer, especially in environments where RocksDB and snapshotting result
- * in multiple hardlinks to the same physical data.
- */
-public class OMDBCheckpointServletInodeBasedXfer extends DBCheckpointServlet {
-
- protected static final Logger LOG =
- LoggerFactory.getLogger(OMDBCheckpointServletInodeBasedXfer.class);
- private static final long serialVersionUID = 1L;
- private transient BootstrapStateHandler.Lock lock;
-
- @Override
- public void init() throws ServletException {
- OzoneManager om = (OzoneManager) getServletContext()
- .getAttribute(OzoneConsts.OM_CONTEXT_ATTRIBUTE);
-
- if (om == null) {
- LOG.error("Unable to initialize OMDBCheckpointServlet. OM is null");
- return;
- }
-
- OzoneConfiguration conf = getConf();
- // Only Ozone Admins and Recon are allowed
- Collection allowedUsers =
- new LinkedHashSet<>(om.getOmAdminUsernames());
- Collection allowedGroups = om.getOmAdminGroups();
- ReconConfig reconConfig = conf.getObject(ReconConfig.class);
- String reconPrincipal = reconConfig.getKerberosPrincipal();
- if (!reconPrincipal.isEmpty()) {
- UserGroupInformation ugi =
- UserGroupInformation.createRemoteUser(reconPrincipal);
- allowedUsers.add(ugi.getShortUserName());
- }
-
- initialize(om.getMetadataManager().getStore(),
- om.getMetrics().getDBCheckpointMetrics(),
- om.getAclsEnabled(),
- allowedUsers,
- allowedGroups,
- om.isSpnegoEnabled());
- lock = new OMDBCheckpointServlet.Lock(om);
- }
-
- @Override
- public BootstrapStateHandler.Lock getBootstrapStateLock() {
- return lock;
- }
-
- @Override
- public void processMetadataSnapshotRequest(HttpServletRequest request, HttpServletResponse response,
- boolean isFormData, boolean flush) {
- String[] sstParam = isFormData ?
- parseFormDataParameters(request) : request.getParameterValues(
- OZONE_DB_CHECKPOINT_REQUEST_TO_EXCLUDE_SST);
- Set receivedSstFiles = extractFilesToExclude(sstParam);
- Path tmpdir = null;
- try (BootstrapStateHandler.Lock lock = getBootstrapStateLock().lock()) {
- tmpdir = Files.createTempDirectory(getBootstrapTempData().toPath(),
- "bootstrap-data-");
- if (tmpdir == null) {
- throw new IOException("tmp dir is null");
- }
- String tarName = "om.data-" + System.currentTimeMillis() + ".tar";
- response.setContentType("application/x-tar");
- response.setHeader("Content-Disposition", "attachment; filename=\"" + tarName + "\"");
- Instant start = Instant.now();
- writeDbDataToStream(request, response.getOutputStream(), receivedSstFiles, tmpdir);
- Instant end = Instant.now();
- long duration = Duration.between(start, end).toMillis();
- LOG.info("Time taken to write the checkpoint to response output " +
- "stream: {} milliseconds", duration);
- logSstFileList(receivedSstFiles,
- "Excluded {} SST files from the latest checkpoint{}: {}", 5);
- } catch (Exception e) {
- LOG.error(
- "Unable to process metadata snapshot request. ", e);
- response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- } finally {
- try {
- if (tmpdir != null) {
- FileUtils.deleteDirectory(tmpdir.toFile());
- }
- } catch (IOException e) {
- LOG.error("unable to delete: " + tmpdir, e.toString());
- }
- }
- }
-
- Path getSstBackupDir() {
- RocksDBCheckpointDiffer differ = getDbStore().getRocksDBCheckpointDiffer();
- return new File(differ.getSSTBackupDir()).toPath();
- }
-
- Path getCompactionLogDir() {
- RocksDBCheckpointDiffer differ = getDbStore().getRocksDBCheckpointDiffer();
- return new File(differ.getCompactionLogDir()).toPath();
- }
-
- /**
- * Streams the Ozone Manager database checkpoint and (optionally) snapshot-related data
- * as a tar archive to the provided output stream. This method handles deduplication
- * based on file inodes to avoid transferring duplicate files (such as hardlinks),
- * supports excluding specific SST files, enforces maximum total SST file size limits,
- * and manages temporary directories for processing.
- *
- * The method processes snapshot directories and backup/compaction logs (if requested),
- * then finally the active OM database. It also writes a hardlink mapping file
- * and includes a completion flag for Ratis snapshot streaming.
- *
- * @param request The HTTP servlet request containing parameters for the snapshot.
- * @param destination The output stream to which the tar archive is written.
- * @param sstFilesToExclude Set of SST file identifiers to exclude from the archive.
- * @param tmpdir Temporary directory for staging files during archiving.
- * @throws IOException if an I/O error occurs during processing or streaming.
- */
-
- public void writeDbDataToStream(HttpServletRequest request, OutputStream destination,
- Set sstFilesToExclude, Path tmpdir) throws IOException {
- DBCheckpoint checkpoint = null;
- OzoneManager om = (OzoneManager) getServletContext().getAttribute(OzoneConsts.OM_CONTEXT_ATTRIBUTE);
- OMMetadataManager omMetadataManager = om.getMetadataManager();
- boolean includeSnapshotData = includeSnapshotData(request);
- AtomicLong maxTotalSstSize = new AtomicLong(getConf().getLong(OZONE_OM_RATIS_SNAPSHOT_MAX_TOTAL_SST_SIZE_KEY,
- OZONE_OM_RATIS_SNAPSHOT_MAX_TOTAL_SST_SIZE_DEFAULT));
-
- Set snapshotPaths = Collections.emptySet();
-
- if (!includeSnapshotData) {
- maxTotalSstSize.set(Long.MAX_VALUE);
- } else {
- snapshotPaths = getSnapshotDirs(omMetadataManager);
- }
-
- if (sstFilesToExclude.isEmpty()) {
- logEstimatedTarballSize(getDbStore().getDbLocation().toPath(), snapshotPaths);
- }
-
- boolean shouldContinue = true;
-
- Map hardLinkFileMap = new HashMap<>();
- try (ArchiveOutputStream archiveOutputStream = tar(destination)) {
- if (includeSnapshotData) {
- // Process each snapshot db path and write it to archive
- for (Path snapshotDbPath : snapshotPaths) {
- if (!shouldContinue) {
- break;
- }
- shouldContinue = writeDBToArchive(sstFilesToExclude, snapshotDbPath,
- maxTotalSstSize, archiveOutputStream, tmpdir, hardLinkFileMap, true);
- }
-
-
- if (shouldContinue) {
- shouldContinue = writeDBToArchive(sstFilesToExclude, getSstBackupDir(),
- maxTotalSstSize, archiveOutputStream, tmpdir, hardLinkFileMap, true);
- }
-
- if (shouldContinue) {
- shouldContinue = writeDBToArchive(sstFilesToExclude, getCompactionLogDir(),
- maxTotalSstSize, archiveOutputStream, tmpdir, hardLinkFileMap, true);
- }
- }
-
- if (shouldContinue) {
- // we finished transferring files from snapshot DB's by now and
- // this is the last step where we transfer the active om.db contents
- checkpoint = createAndPrepareCheckpoint(tmpdir, true);
- // unlimited files as we want the Active DB contents to be transferred in a single batch
- maxTotalSstSize.set(Long.MAX_VALUE);
- Path checkpointDir = checkpoint.getCheckpointLocation();
- writeDBToArchive(sstFilesToExclude, checkpointDir,
- maxTotalSstSize, archiveOutputStream, tmpdir, hardLinkFileMap, false);
- if (includeSnapshotData) {
- Path tmpCompactionLogDir = tmpdir.resolve(getCompactionLogDir().getFileName());
- Path tmpSstBackupDir = tmpdir.resolve(getSstBackupDir().getFileName());
- writeDBToArchive(sstFilesToExclude, tmpCompactionLogDir, maxTotalSstSize, archiveOutputStream, tmpdir,
- hardLinkFileMap, getCompactionLogDir(), false);
- writeDBToArchive(sstFilesToExclude, tmpSstBackupDir, maxTotalSstSize, archiveOutputStream, tmpdir,
- hardLinkFileMap, getSstBackupDir(), false);
- // This is done to ensure all data to be copied correctly is flushed in the snapshot DB
- transferSnapshotData(sstFilesToExclude, tmpdir, snapshotPaths, maxTotalSstSize,
- archiveOutputStream, hardLinkFileMap);
- }
- writeHardlinkFile(getConf(), hardLinkFileMap, archiveOutputStream);
- includeRatisSnapshotCompleteFlag(archiveOutputStream);
- }
-
- } catch (IOException ioe) {
- LOG.error("got exception writing to archive " + ioe);
- throw ioe;
- } finally {
- cleanupCheckpoint(checkpoint);
- }
- }
-
- /**
- * Transfers the snapshot data from the specified snapshot directories into the archive output stream,
- * handling deduplication and managing resource locking.
- *
- * @param sstFilesToExclude Set of SST file identifiers to exclude from the archive.
- * @param tmpdir Temporary directory for intermediate processing.
- * @param snapshotPaths Set of paths to snapshot directories to be processed.
- * @param maxTotalSstSize AtomicLong to track the cumulative size of SST files included.
- * @param archiveOutputStream Archive output stream to write the snapshot data.
- * @param hardLinkFileMap Map of hardlink file paths to their unique identifiers for deduplication.
- * @throws IOException if an I/O error occurs during processing.
- */
- private void transferSnapshotData(Set sstFilesToExclude, Path tmpdir, Set snapshotPaths,
- AtomicLong maxTotalSstSize, ArchiveOutputStream archiveOutputStream,
- Map hardLinkFileMap) throws IOException {
- OzoneManager om = (OzoneManager) getServletContext().getAttribute(OzoneConsts.OM_CONTEXT_ATTRIBUTE);
- OMMetadataManager omMetadataManager = om.getMetadataManager();
- for (Path snapshotDir : snapshotPaths) {
- String snapshotId = OmSnapshotManager.extractSnapshotIDFromCheckpointDirName(snapshotDir.toString());
- omMetadataManager.getLock().acquireReadLock(SNAPSHOT_DB_LOCK, snapshotId);
- try {
- // invalidate closes the snapshot DB
- om.getOmSnapshotManager().invalidateCacheEntry(UUID.fromString(snapshotId));
- writeDBToArchive(sstFilesToExclude, snapshotDir, maxTotalSstSize, archiveOutputStream, tmpdir,
- hardLinkFileMap, false);
- Path snapshotLocalPropertyYaml = Paths.get(
- OmSnapshotLocalDataManager.getSnapshotLocalPropertyYamlPath(snapshotDir));
- if (Files.exists(snapshotLocalPropertyYaml)) {
- File yamlFile = snapshotLocalPropertyYaml.toFile();
- hardLinkFileMap.put(yamlFile.getAbsolutePath(), yamlFile.getName());
- linkAndIncludeFile(yamlFile, yamlFile.getName(), archiveOutputStream, tmpdir);
- }
- } finally {
- omMetadataManager.getLock().releaseReadLock(SNAPSHOT_DB_LOCK, snapshotId);
- }
- }
- }
-
- @VisibleForTesting
- boolean writeDBToArchive(Set sstFilesToExclude, Path dir,
- AtomicLong maxTotalSstSize, ArchiveOutputStream archiveOutputStream,
- Path tmpdir, Map hardLinkFileMap, boolean onlySstFile) throws IOException {
- return writeDBToArchive(sstFilesToExclude, dir, maxTotalSstSize,
- archiveOutputStream, tmpdir, hardLinkFileMap, null, onlySstFile);
- }
-
- private static void cleanupCheckpoint(DBCheckpoint checkpoint) {
- if (checkpoint != null) {
- try {
- checkpoint.cleanupCheckpoint();
- } catch (IOException e) {
- LOG.error("Error trying to clean checkpoint at {} .",
- checkpoint.getCheckpointLocation().toString());
- }
- }
- }
-
- /**
- * Writes a hardlink mapping file to the archive, which maps file IDs to their
- * relative paths. This method generates the mapping file based on the provided
- * hardlink metadata and adds it to the archive output stream.
- *
- * @param conf Ozone configuration for the OM instance.
- * @param hardlinkFileMap A map where the key is the absolute file path
- * and the value is its corresponding file ID.
- * @param archiveOutputStream The archive output stream to which the hardlink
- * file should be written.
- * @throws IOException If an I/O error occurs while creating or writing the
- * hardlink file.
- */
- private static void writeHardlinkFile(OzoneConfiguration conf, Map hardlinkFileMap,
- ArchiveOutputStream archiveOutputStream) throws IOException {
- Path data = Files.createTempFile(DATA_PREFIX, DATA_SUFFIX);
- Path metaDirPath = OMStorage.getOmDbDir(conf).toPath();
- StringBuilder sb = new StringBuilder();
-
- for (Map.Entry entry : hardlinkFileMap.entrySet()) {
- Path p = Paths.get(entry.getKey());
- String fileId = entry.getValue();
- Path relativePath = metaDirPath.relativize(p);
- // if the file is in "om.db" directory, strip off the 'o
- // m.db' name from the path
- // and only keep the file name as this would be created in the current dir of the untarred dir
- // on the follower.
- if (relativePath.startsWith(OM_DB_NAME)) {
- relativePath = relativePath.getFileName();
- }
- sb.append(relativePath).append('\t').append(fileId).append('\n');
- }
- Files.write(data, sb.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.TRUNCATE_EXISTING);
- includeFile(data.toFile(), OmSnapshotManager.OM_HARDLINK_FILE, archiveOutputStream);
- }
-
- /**
- * Gets the configuration from the OzoneManager context.
- *
- * @return OzoneConfiguration instance
- */
- private OzoneConfiguration getConf() {
- return ((OzoneManager) getServletContext()
- .getAttribute(OzoneConsts.OM_CONTEXT_ATTRIBUTE))
- .getConfiguration();
- }
-
- /**
- * Collects paths to all snapshot databases.
- *
- * @param omMetadataManager OMMetadataManager instance
- * @return Set of paths to snapshot databases
- * @throws IOException if an I/O error occurs
- */
- Set getSnapshotDirs(OMMetadataManager omMetadataManager) throws IOException {
- Set snapshotPaths = new HashSet<>();
- SnapshotChainManager snapshotChainManager = new SnapshotChainManager(omMetadataManager);
- for (SnapshotChainInfo snapInfo : snapshotChainManager.getGlobalSnapshotChain().values()) {
- String snapshotDir =
- OmSnapshotManager.getSnapshotPath(getConf(), SnapshotInfo.getCheckpointDirName(snapInfo.getSnapshotId()));
- Path path = Paths.get(snapshotDir);
- snapshotPaths.add(path);
- }
- return snapshotPaths;
- }
-
- /**
- * Writes database files to the archive, handling deduplication based on inode IDs.
- * Here the dbDir could either be a snapshot db directory, the active om.db,
- * compaction log dir, sst backup dir.
- *
- * @param sstFilesToExclude Set of SST file IDs to exclude from the archive
- * @param dbDir Directory containing database files to archive
- * @param maxTotalSstSize Maximum total size of SST files to include
- * @param archiveOutputStream Archive output stream
- * @param tmpDir Temporary directory for processing
- * @param hardLinkFileMap Map of hardlink file paths to their unique identifiers for deduplication
- * @param destDir Destination directory for the archived files. If null,
- * the archived files are not moved to this directory.
- * @param onlySstFile If true, only SST files are processed. If false, all files are processed.
- *
- * This parameter is typically set to {@code true} for initial iterations to
- * prioritize SST file transfer, and then set to {@code false} only for the
- * final iteration to ensure all remaining file types are transferred.
- * @return true if processing should continue, false if size limit reached
- * @throws IOException if an I/O error occurs
- */
- @SuppressWarnings("checkstyle:ParameterNumber")
- private boolean writeDBToArchive(Set sstFilesToExclude, Path dbDir, AtomicLong maxTotalSstSize,
- ArchiveOutputStream archiveOutputStream, Path tmpDir,
- Map hardLinkFileMap, Path destDir, boolean onlySstFile) throws IOException {
- if (!Files.exists(dbDir)) {
- LOG.warn("DB directory {} does not exist. Skipping.", dbDir);
- return true;
- }
- long bytesWritten = 0L;
- int filesWritten = 0;
- long lastLoggedTime = Time.monotonicNow();
- try (Stream files = Files.list(dbDir)) {
- Iterable iterable = files::iterator;
- for (Path dbFile : iterable) {
- if (!Files.isDirectory(dbFile)) {
- if (onlySstFile && !dbFile.toString().endsWith(ROCKSDB_SST_SUFFIX)) {
- continue;
- }
- String fileId = OmSnapshotUtils.getFileInodeAndLastModifiedTimeString(dbFile);
- String path = dbFile.toFile().getAbsolutePath();
- if (destDir != null) {
- path = destDir.resolve(dbFile.getFileName()).toString();
- }
- // if the file is in the om checkpoint dir, then we need to change the path to point to the OM DB.
- if (path.contains(OM_CHECKPOINT_DIR)) {
- path = getDbStore().getDbLocation().toPath().resolve(dbFile.getFileName()).toAbsolutePath().toString();
- }
- hardLinkFileMap.put(path, fileId);
- if (!sstFilesToExclude.contains(fileId)) {
- long fileSize = Files.size(dbFile);
- if (maxTotalSstSize.get() - fileSize <= 0) {
- return false;
- }
- bytesWritten += linkAndIncludeFile(dbFile.toFile(), fileId, archiveOutputStream, tmpDir);
- filesWritten++;
- maxTotalSstSize.addAndGet(-fileSize);
- sstFilesToExclude.add(fileId);
- if (Time.monotonicNow() - lastLoggedTime >= 30000) {
- LOG.info("Transferred {} KB, #files {} to checkpoint tarball stream...",
- bytesWritten / (1024), filesWritten);
- lastLoggedTime = Time.monotonicNow();
- }
- }
- }
- }
- }
- return true;
- }
-
- /**
- * Creates a database checkpoint and copies compaction log and SST backup files
- * into the given temporary directory.
- * The copy to the temporary directory for compaction log and SST backup files
- * is done to maintain a consistent view of the files in these directories.
- *
- * @param tmpdir Temporary directory for storing checkpoint-related files.
- * @param flush If true, flushes in-memory data to disk before checkpointing.
- * @return The created database checkpoint.
- * @throws IOException If an error occurs during checkpoint creation or file copying.
- */
- private DBCheckpoint createAndPrepareCheckpoint(Path tmpdir, boolean flush) throws IOException {
- // make tmp directories to contain the copies
- Path tmpCompactionLogDir = tmpdir.resolve(getCompactionLogDir().getFileName());
- Path tmpSstBackupDir = tmpdir.resolve(getSstBackupDir().getFileName());
-
- // Create checkpoint and then copy the files so that it has all the compaction entries and files.
- DBCheckpoint dbCheckpoint = getDbStore().getCheckpoint(flush);
- FileUtils.copyDirectory(getCompactionLogDir().toFile(), tmpCompactionLogDir.toFile());
- OmSnapshotUtils.linkFiles(getSstBackupDir().toFile(), tmpSstBackupDir.toFile());
-
- return dbCheckpoint;
- }
-}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
index 7b9beb80cf6..eae4dd6b224 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
@@ -26,7 +26,6 @@
import static org.apache.hadoop.ozone.OzoneConsts.OM_SNAPSHOT_CHECKPOINT_DIR;
import static org.apache.hadoop.ozone.OzoneConsts.OM_SNAPSHOT_DIFF_DB_NAME;
import static org.apache.hadoop.ozone.OzoneConsts.OM_SNAPSHOT_INDICATOR;
-import static org.apache.hadoop.ozone.OzoneConsts.OM_SNAPSHOT_SEPARATOR;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_FS_SNAPSHOT_MAX_LIMIT;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_FS_SNAPSHOT_MAX_LIMIT_DEFAULT;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_SNAPSHOT_CACHE_CLEANUP_SERVICE_RUN_INTERVAL;
@@ -811,24 +810,10 @@ public static Path getSnapshotPath(OMMetadataManager omMetadataManager, UUID sna
}
public static String getSnapshotPath(OzoneConfiguration conf,
- SnapshotInfo snapshotInfo) {
- return getSnapshotPath(conf, snapshotInfo.getCheckpointDirName());
- }
-
- public static String getSnapshotPath(OzoneConfiguration conf,
- String checkpointDirName) {
+ SnapshotInfo snapshotInfo) {
return OMStorage.getOmDbDir(conf) +
OM_KEY_PREFIX + OM_SNAPSHOT_CHECKPOINT_DIR + OM_KEY_PREFIX +
- OM_DB_NAME + checkpointDirName;
- }
-
- public static String extractSnapshotIDFromCheckpointDirName(String snapshotPath) {
- // Find "om.db-" in the path and return whatever comes after
- int index = snapshotPath.lastIndexOf(OM_DB_NAME);
- if (index == -1 || index + OM_DB_NAME.length() + OM_SNAPSHOT_SEPARATOR.length() >= snapshotPath.length()) {
- throw new IllegalArgumentException("Invalid snapshot path " + snapshotPath);
- }
- return snapshotPath.substring(index + OM_DB_NAME.length() + OM_SNAPSHOT_SEPARATOR.length());
+ OM_DB_NAME + snapshotInfo.getCheckpointDirName();
}
public static boolean isSnapshotKey(String[] keyParts) {
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 56e51cf4026..a4e384890de 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -3988,7 +3988,7 @@ public synchronized TermIndex installSnapshotFromLeader(String leaderId) {
TermIndex termIndex = null;
try {
// Install hard links.
- OmSnapshotUtils.createHardLinks(omDBCheckpoint.getCheckpointLocation(), false);
+ OmSnapshotUtils.createHardLinks(omDBCheckpoint.getCheckpointLocation());
termIndex = installCheckpoint(leaderId, omDBCheckpoint);
} catch (Exception ex) {
LOG.error("Failed to install snapshot from Leader OM.", ex);
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerHttpServer.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerHttpServer.java
index 9c2688de812..355d6249806 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerHttpServer.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerHttpServer.java
@@ -18,7 +18,6 @@
package org.apache.hadoop.ozone.om;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_DB_CHECKPOINT_HTTP_ENDPOINT;
-import static org.apache.hadoop.ozone.OzoneConsts.OZONE_DB_CHECKPOINT_HTTP_ENDPOINT_V2;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_OM_SERVICE_LIST_HTTP_ENDPOINT;
import java.io.IOException;
@@ -38,8 +37,6 @@ public OzoneManagerHttpServer(MutableConfigurationSource conf,
ServiceListJSONServlet.class);
addServlet("dbCheckpoint", OZONE_DB_CHECKPOINT_HTTP_ENDPOINT,
OMDBCheckpointServlet.class);
- addServlet("dbCheckpointv2", OZONE_DB_CHECKPOINT_HTTP_ENDPOINT_V2,
- OMDBCheckpointServletInodeBasedXfer.class);
getWebAppContext().setAttribute(OzoneConsts.OM_CONTEXT_ATTRIBUTE, om);
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java
index 9894e8f5d6b..6d053e1e5e0 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java
@@ -17,8 +17,6 @@
package org.apache.hadoop.ozone.om.codec;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import org.apache.hadoop.hdds.utils.TransactionInfo;
import org.apache.hadoop.hdds.utils.db.DBColumnFamilyDefinition;
@@ -360,13 +358,5 @@ public String getName() {
public String getLocationConfigKey() {
return OMConfigKeys.OZONE_OM_DB_DIRS;
}
-
- public static List getAllColumnFamilies() {
- List columnFamilies = new ArrayList<>();
- COLUMN_FAMILIES.values().forEach(cf -> {
- columnFamilies.add(cf.getName());
- });
- return columnFamilies;
- }
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis_snapshot/OmRatisSnapshotProvider.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis_snapshot/OmRatisSnapshotProvider.java
index ef0a46548a4..a343232c39e 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis_snapshot/OmRatisSnapshotProvider.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis_snapshot/OmRatisSnapshotProvider.java
@@ -153,7 +153,7 @@ public void downloadSnapshot(String leaderNodeID, File targetFile)
connection.setRequestProperty("Content-Type", contentTypeValue);
connection.setDoOutput(true);
writeFormData(connection,
- HAUtils.getExistingFiles(getCandidateDir()));
+ HAUtils.getExistingSstFiles(getCandidateDir()));
connection.connect();
int errorCode = connection.getResponseCode();
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/OmSnapshotUtils.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/OmSnapshotUtils.java
index 497c7a064b8..f5805044b7f 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/OmSnapshotUtils.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/OmSnapshotUtils.java
@@ -27,15 +27,11 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.attribute.FileTime;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.hadoop.ozone.om.OmSnapshotManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Ozone Manager Snapshot Utilities.
@@ -44,8 +40,6 @@ public final class OmSnapshotUtils {
public static final String DATA_PREFIX = "data";
public static final String DATA_SUFFIX = "txt";
- private static final Logger LOG =
- LoggerFactory.getLogger(OmSnapshotUtils.class);
private OmSnapshotUtils() { }
@@ -71,26 +65,6 @@ public static Object getINode(Path file) throws IOException {
return Files.readAttributes(file, BasicFileAttributes.class).fileKey();
}
- /**
- * Returns a string combining the inode (fileKey) and the last modification time (mtime) of the given file.
- *
- * The returned string is formatted as "{inode}-{mtime}", where:
- *
- * - {@code inode} is the unique file key obtained from the file system, typically representing
- * the inode on POSIX systems
- * - {@code mtime} is the last modified time of the file in milliseconds since the epoch
- *
- *
- * @param file the {@link Path} to the file whose inode and modification time are to be retrieved
- * @return a string in the format "{inode}-{mtime}"
- * @throws IOException if an I/O error occurs
- */
- public static String getFileInodeAndLastModifiedTimeString(Path file) throws IOException {
- Object inode = Files.readAttributes(file, BasicFileAttributes.class).fileKey();
- FileTime mTime = Files.getLastModifiedTime(file);
- return String.format("%s-%s", inode, mTime.toMillis());
- }
-
/**
* Create file of links to add to tarball.
* Format of entries are either:
@@ -129,12 +103,10 @@ public static Path createHardLinkList(int truncateLength,
* Create hard links listed in OM_HARDLINK_FILE.
*
* @param dbPath Path to db to have links created.
- * @param deleteSourceFiles - Whether to delete the source files after creating the links.
*/
- public static void createHardLinks(Path dbPath, boolean deleteSourceFiles) throws IOException {
+ public static void createHardLinks(Path dbPath) throws IOException {
File hardLinkFile =
new File(dbPath.toString(), OmSnapshotManager.OM_HARDLINK_FILE);
- List filesToDelete = new ArrayList<>();
if (hardLinkFile.exists()) {
// Read file.
try (Stream s = Files.lines(hardLinkFile.toPath())) {
@@ -142,15 +114,9 @@ public static void createHardLinks(Path dbPath, boolean deleteSourceFiles) throw
// Create a link for each line.
for (String l : lines) {
- String[] parts = l.split("\t");
- if (parts.length != 2) {
- LOG.warn("Skipping malformed line in hardlink file: {}", l);
- continue;
- }
- String from = parts[1];
- String to = parts[0];
+ String from = l.split("\t")[1];
+ String to = l.split("\t")[0];
Path fullFromPath = Paths.get(dbPath.toString(), from);
- filesToDelete.add(fullFromPath);
Path fullToPath = Paths.get(dbPath.toString(), to);
// Make parent dir if it doesn't exist.
Path parent = fullToPath.getParent();
@@ -167,15 +133,6 @@ public static void createHardLinks(Path dbPath, boolean deleteSourceFiles) throw
}
}
}
- if (deleteSourceFiles) {
- for (Path fileToDelete : filesToDelete) {
- try {
- Files.deleteIfExists(fileToDelete);
- } catch (IOException e) {
- LOG.warn("Couldn't delete source file {} while unpacking the DB", fileToDelete, e);
- }
- }
- }
}
/**
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotCache.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotCache.java
index 6867f819b9c..81c9dc46554 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotCache.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotCache.java
@@ -151,7 +151,6 @@ public void invalidate(UUID key) {
LOG.debug("SnapshotId: '{}' does not exist in snapshot cache.", k);
} else {
try {
- v.get().getMetadataManager().getStore().flushDB();
v.get().close();
} catch (IOException e) {
throw new IllegalStateException("Failed to close snapshotId: " + key, e);
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
index 7f808df3f97..03c3b4e4ef1 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
@@ -19,7 +19,7 @@
import static org.apache.commons.io.file.PathUtils.copyDirectory;
import static org.apache.hadoop.hdds.StringUtils.string2Bytes;
-import static org.apache.hadoop.hdds.utils.HAUtils.getExistingFiles;
+import static org.apache.hadoop.hdds.utils.HAUtils.getExistingSstFiles;
import static org.apache.hadoop.ozone.OzoneConsts.OM_CHECKPOINT_DIR;
import static org.apache.hadoop.ozone.OzoneConsts.OM_DB_NAME;
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
@@ -35,6 +35,7 @@
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.KEY_TABLE;
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.VOLUME_TABLE;
import static org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils.getINode;
+import static org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils.truncateFileName;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -456,7 +457,7 @@ public void testHardLinkCreation() throws IOException {
File s1FileLink = new File(followerSnapDir2, "s1.sst");
// Create links on the follower from list.
- OmSnapshotUtils.createHardLinks(candidateDir.toPath(), false);
+ OmSnapshotUtils.createHardLinks(candidateDir.toPath());
// Confirm expected follower links.
assertTrue(s1FileLink.exists());
@@ -499,16 +500,44 @@ public void testGetSnapshotInfo() throws IOException {
@Test
public void testExcludeUtilities() throws IOException {
File noLinkFile = new File(followerSnapDir2, "noLink.sst");
- File nonSstFile = new File(followerSnapDir2, "nonSstFile");
+
// Confirm that the list of existing sst files is as expected.
- List existingSstList = getExistingFiles(candidateDir);
+ List existingSstList = getExistingSstFiles(candidateDir);
Set existingSstFiles = new HashSet<>(existingSstList);
- Set expectedSstFileNames = new HashSet<>(Arrays.asList(
- s1File.getName(),
- noLinkFile.getName(),
- f1File.getName(),
- nonSstFile.getName()));
- assertEquals(expectedSstFileNames, existingSstFiles);
+ int truncateLength = candidateDir.toString().length() + 1;
+ Set expectedSstFiles = new HashSet<>(Arrays.asList(
+ s1File.toString().substring(truncateLength),
+ noLinkFile.toString().substring(truncateLength),
+ f1File.toString().substring(truncateLength)));
+ assertEquals(expectedSstFiles, existingSstFiles);
+
+ // Confirm that the excluded list is normalized as expected.
+ // (Normalizing means matches the layout on the leader.)
+ File leaderSstBackupDir = new File(leaderDir.toString(), "sstBackup");
+ assertTrue(leaderSstBackupDir.mkdirs());
+ File leaderTmpDir = new File(leaderDir.toString(), "tmp");
+ assertTrue(leaderTmpDir.mkdirs());
+ OMDBCheckpointServlet.DirectoryData sstBackupDir =
+ new OMDBCheckpointServlet.DirectoryData(leaderTmpDir.toPath(),
+ leaderSstBackupDir.toString());
+ Path srcSstBackup = Paths.get(sstBackupDir.getTmpDir().toString(),
+ "backup.sst");
+ Path destSstBackup = Paths.get(sstBackupDir.getOriginalDir().toString(),
+ "backup.sst");
+ truncateLength = leaderDir.toString().length() + 1;
+ existingSstList.add(truncateFileName(truncateLength, destSstBackup));
+ Map> normalizedMap =
+ OMDBCheckpointServlet.normalizeExcludeList(existingSstList,
+ leaderCheckpointDir.toPath(), sstBackupDir);
+ Map> expectedMap = new TreeMap<>();
+ Path s1 = Paths.get(leaderSnapDir1.toString(), "s1.sst");
+ Path noLink = Paths.get(leaderSnapDir2.toString(), "noLink.sst");
+ Path f1 = Paths.get(leaderCheckpointDir.toString(), "f1.sst");
+ expectedMap.put("s1.sst", ImmutableMap.of(s1, s1));
+ expectedMap.put("noLink.sst", ImmutableMap.of(noLink, noLink));
+ expectedMap.put("f1.sst", ImmutableMap.of(f1, f1));
+ expectedMap.put("backup.sst", ImmutableMap.of(srcSstBackup, destSstBackup));
+ assertEquals(expectedMap, new TreeMap<>(normalizedMap));
}
/*
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/OzoneManagerServiceProviderImpl.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/OzoneManagerServiceProviderImpl.java
index 3cd785e53a5..b4b96ff4d88 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/OzoneManagerServiceProviderImpl.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/OzoneManagerServiceProviderImpl.java
@@ -18,7 +18,7 @@
package org.apache.hadoop.ozone.recon.spi.impl;
import static org.apache.hadoop.hdds.recon.ReconConfigKeys.OZONE_RECON_DB_DIRS_PERMISSIONS_DEFAULT;
-import static org.apache.hadoop.ozone.OzoneConsts.OZONE_DB_CHECKPOINT_HTTP_ENDPOINT_V2;
+import static org.apache.hadoop.ozone.OzoneConsts.OZONE_DB_CHECKPOINT_HTTP_ENDPOINT;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_DB_CHECKPOINT_REQUEST_FLUSH;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_HTTP_AUTH_TYPE;
import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_OM_SNAPSHOT_DB;
@@ -84,7 +84,6 @@
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.helpers.DBUpdates;
import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
-import org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DBUpdatesRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServicePort.Type;
import org.apache.hadoop.ozone.recon.ReconContext;
@@ -197,11 +196,11 @@ public OzoneManagerServiceProviderImpl(
HttpConfig.Policy policy = HttpConfig.getHttpPolicy(configuration);
omDBSnapshotUrl = "http://" + ozoneManagerHttpAddress +
- OZONE_DB_CHECKPOINT_HTTP_ENDPOINT_V2;
+ OZONE_DB_CHECKPOINT_HTTP_ENDPOINT;
if (policy.isHttpsEnabled()) {
omDBSnapshotUrl = "https://" + ozoneManagerHttpsAddress +
- OZONE_DB_CHECKPOINT_HTTP_ENDPOINT_V2;
+ OZONE_DB_CHECKPOINT_HTTP_ENDPOINT;
}
boolean flushParam = configuration.getBoolean(
@@ -414,7 +413,7 @@ public String getOzoneManagerSnapshotUrl() throws IOException {
omLeaderUrl = (policy.isHttpsEnabled() ?
"https://" + info.getServiceAddress(Type.HTTPS) :
"http://" + info.getServiceAddress(Type.HTTP)) +
- OZONE_DB_CHECKPOINT_HTTP_ENDPOINT_V2;
+ OZONE_DB_CHECKPOINT_HTTP_ENDPOINT;
}
}
}
@@ -471,7 +470,6 @@ public DBCheckpoint getOzoneManagerDBSnapshot() {
try (InputStream inputStream = reconUtils.makeHttpCall(
connectionFactory, getOzoneManagerSnapshotUrl(), isOmSpnegoEnabled()).getInputStream()) {
tarExtractor.extractTar(inputStream, untarredDbDir);
- OmSnapshotUtils.createHardLinks(untarredDbDir, true);
} catch (IOException | InterruptedException e) {
reconContext.updateHealthStatus(new AtomicBoolean(false));
reconContext.updateErrors(ReconContext.ErrorCode.GET_OM_DB_SNAPSHOT_FAILED);