Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,12 @@ public void importContainerData(InputStream input,
//fill in memory stat counter (keycount, byte usage)
KeyValueContainerUtil.parseKVContainerData(containerData, config);

if (!scanMetaData()) {
String message = "Metadata scan of imported container " +
containerData.getContainerID() + " failed. Attempting clean up.";
LOG.error(message);
throw new IOException(message);
}
} catch (Exception ex) {
if (ex instanceof StorageContainerException &&
((StorageContainerException) ex).getResult() ==
Expand Down Expand Up @@ -551,6 +557,15 @@ public void exportContainerData(OutputStream destination,
" is in state " + state);
}

if (!scanMetaData()) {
markContainerUnhealthy();
String message = "Metadata scan failed before exporting " +
"container " + containerData.getContainerID() + ". Container " +
"export aborted and container marked unhealthy.";
LOG.error(message);
throw new IOException(message);
}

try {
compactDB();
// Close DB (and remove from cache) to avoid concurrent modification
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,19 @@ public byte[] unpackContainerData(Container<KeyValueContainerData> container,
if (name.startsWith(DB_DIR_NAME + "/")) {
Path destinationPath = dbRoot
.resolve(name.substring(DB_DIR_NAME.length() + 1));
extractEntry(archiveInput, size, dbRoot, destinationPath);
if (entry.isDirectory()) {
Files.createDirectories(destinationPath);
} else {
extractFileEntry(archiveInput, size, dbRoot, destinationPath);
}
Comment thread
adoroszlai marked this conversation as resolved.
Outdated
} else if (name.startsWith(CHUNKS_DIR_NAME + "/")) {
Path destinationPath = chunksRoot
.resolve(name.substring(CHUNKS_DIR_NAME.length() + 1));
extractEntry(archiveInput, size, chunksRoot, destinationPath);
if (entry.isDirectory()) {
Files.createDirectories(destinationPath);
} else {
extractFileEntry(archiveInput, size, chunksRoot, destinationPath);
}
} else if (CONTAINER_FILE_NAME.equals(name)) {
//Don't do anything. Container file should be unpacked in a
//separated step by unpackContainerDescriptor call.
Expand All @@ -109,8 +117,8 @@ public byte[] unpackContainerData(Container<KeyValueContainerData> container,
}
}

private void extractEntry(InputStream input, long size,
Path ancestor, Path path) throws IOException {
private void extractFileEntry(InputStream input, long size,
Path ancestor, Path path) throws IOException {
HddsUtils.validatePath(path, ancestor);
Path parent = path.getParent();
if (parent != null) {
Expand Down Expand Up @@ -209,6 +217,12 @@ private byte[] readEntry(InputStream input, final long size)
private void includePath(Path dir, String subdir,
ArchiveOutputStream archiveOutput) throws IOException {

// Add a directory entry before adding files, in case the directory is
// empty.
ArchiveEntry entry = archiveOutput.createArchiveEntry(dir.toFile(), subdir);
archiveOutput.putArchiveEntry(entry);

// Add files in the directory.
try (Stream<Path> dirEntries = Files.list(dir)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the error is thrown here, so it still needs the CHUNK file to exist?

Reproduced by adding new File(data.getChunksPath()).delete(); after checking the state of original container.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@symious the error is thrown because the chunk directory does not exist. Not having chunk files in the directory should not be a problem here.

for (Path path : dirEntries.collect(toList())) {
String entryName = subdir + "/" + path.getFileName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
Expand Down Expand Up @@ -254,6 +255,13 @@ public static void parseKVContainerData(KeyValueContainerData kvContainerData,
if (!isBlockMetadataSet) {
initializeUsedBytesAndBlockCount(store, kvContainerData);
}

// If the container is missing a chunks directory, possibly due to the
// bug fixed by HDDS-6235, create it here.
File chunksDir = new File(kvContainerData.getChunksPath());
if (!chunksDir.exists()) {
Comment thread
errose28 marked this conversation as resolved.
Files.createDirectories(chunksDir.toPath());
}
} finally {
if (cachedDB != null) {
// If we get a cached instance, calling close simply decrements the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
Expand All @@ -74,6 +76,7 @@
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DB_PROFILE;
import static org.apache.ratis.util.Preconditions.assertTrue;
Expand Down Expand Up @@ -154,6 +157,36 @@ public void testCreateContainer() throws Exception {
"DB does not exist");
}


@Test
public void testEmptyContainerImportExport() throws Exception {
createContainer();
closeContainer();

KeyValueContainerData data = keyValueContainer.getContainerData();

// Check state of original container.
checkContainerFilesPresent(data, 0);

//destination path
File exportTar = folder.newFile("exported.tar.gz");
TarContainerPacker packer = new TarContainerPacker();
//export the container
try (FileOutputStream fos = new FileOutputStream(exportTar)) {
keyValueContainer.exportContainerData(fos, packer);
}

keyValueContainer.delete();

// import container.
try (FileInputStream fis = new FileInputStream(exportTar)) {
keyValueContainer.importContainerData(fis, packer);
}

// Make sure empty chunks dir was unpacked.
checkContainerFilesPresent(data, 0);
}

@Test
public void testContainerImportExport() throws Exception {
long containerId = keyValueContainer.getContainerData().getContainerID();
Expand Down Expand Up @@ -244,6 +277,18 @@ public void testContainerImportExport() throws Exception {
}
}

private void checkContainerFilesPresent(KeyValueContainerData data,
Comment thread
adoroszlai marked this conversation as resolved.
long expectedNumFilesInChunksDir) throws IOException {
File chunksDir = new File(data.getChunksPath());
Assert.assertTrue(Files.isDirectory(chunksDir.toPath()));
try (Stream<Path> stream = Files.list(chunksDir.toPath())) {
Assert.assertEquals(expectedNumFilesInChunksDir, stream.count());
}
Assert.assertTrue(data.getDbFile().exists());
Assert.assertTrue(KeyValueContainer.getContainerFile(data.getMetadataPath(),
data.getContainerID()).exists());
}

/**
* Create the container on disk.
*/
Expand Down