HDFS-17573. Allow turn on both FSImage parallelization and compression (#6929). Contributed by Sung Dong Kim.
Signed-off-by: He Xiaoqiao <hexiaoqiao@apache.org>
This commit is contained in:
parent
5745a7dd75
commit
89e38f08ae
@ -790,6 +790,7 @@ void serializeINodeDirectorySection(OutputStream out) throws IOException {
|
|||||||
outputInodes = 0;
|
outputInodes = 0;
|
||||||
parent.commitSubSection(summary,
|
parent.commitSubSection(summary,
|
||||||
FSImageFormatProtobuf.SectionName.INODE_DIR_SUB);
|
FSImageFormatProtobuf.SectionName.INODE_DIR_SUB);
|
||||||
|
out = parent.getSectionOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parent.commitSectionAndSubSection(summary,
|
parent.commitSectionAndSubSection(summary,
|
||||||
@ -817,6 +818,7 @@ void serializeINodeSection(OutputStream out) throws IOException {
|
|||||||
if (i % parent.getInodesPerSubSection() == 0) {
|
if (i % parent.getInodesPerSubSection() == 0) {
|
||||||
parent.commitSubSection(summary,
|
parent.commitSubSection(summary,
|
||||||
FSImageFormatProtobuf.SectionName.INODE_SUB);
|
FSImageFormatProtobuf.SectionName.INODE_SUB);
|
||||||
|
out = parent.getSectionOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parent.commitSectionAndSubSection(summary,
|
parent.commitSectionAndSubSection(summary,
|
||||||
|
@ -584,18 +584,6 @@ private void loadErasureCodingSection(InputStream in)
|
|||||||
|
|
||||||
private static boolean enableParallelSaveAndLoad(Configuration conf) {
|
private static boolean enableParallelSaveAndLoad(Configuration conf) {
|
||||||
boolean loadInParallel = enableParallelLoad;
|
boolean loadInParallel = enableParallelLoad;
|
||||||
boolean compressionEnabled = conf.getBoolean(
|
|
||||||
DFSConfigKeys.DFS_IMAGE_COMPRESS_KEY,
|
|
||||||
DFSConfigKeys.DFS_IMAGE_COMPRESS_DEFAULT);
|
|
||||||
|
|
||||||
if (loadInParallel) {
|
|
||||||
if (compressionEnabled) {
|
|
||||||
LOG.warn("Parallel Image loading and saving is not supported when {}" +
|
|
||||||
" is set to true. Parallel will be disabled.",
|
|
||||||
DFSConfigKeys.DFS_IMAGE_COMPRESS_KEY);
|
|
||||||
loadInParallel = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return loadInParallel;
|
return loadInParallel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,6 +641,10 @@ public int getInodesPerSubSection() {
|
|||||||
return inodesPerSubSection;
|
return inodesPerSubSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OutputStream getSectionOutputStream() {
|
||||||
|
return sectionOutputStream;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit the length and offset of a fsimage section to the summary index,
|
* Commit the length and offset of a fsimage section to the summary index,
|
||||||
* including the sub section, which will be committed before the section is
|
* including the sub section, which will be committed before the section is
|
||||||
@ -664,14 +656,22 @@ public int getInodesPerSubSection() {
|
|||||||
*/
|
*/
|
||||||
public void commitSectionAndSubSection(FileSummary.Builder summary,
|
public void commitSectionAndSubSection(FileSummary.Builder summary,
|
||||||
SectionName name, SectionName subSectionName) throws IOException {
|
SectionName name, SectionName subSectionName) throws IOException {
|
||||||
commitSubSection(summary, subSectionName);
|
commitSubSection(summary, subSectionName, true);
|
||||||
commitSection(summary, name);
|
commitSection(summary, name, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void commitSection(FileSummary.Builder summary, SectionName name)
|
public void commitSection(FileSummary.Builder summary, SectionName name)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
commitSection(summary, name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commitSection(FileSummary.Builder summary, SectionName name,
|
||||||
|
boolean afterSubSectionCommit) throws IOException {
|
||||||
long oldOffset = currentOffset;
|
long oldOffset = currentOffset;
|
||||||
|
boolean subSectionCommitted = afterSubSectionCommit && writeSubSections;
|
||||||
|
if (!subSectionCommitted) {
|
||||||
flushSectionOutputStream();
|
flushSectionOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
if (codec != null) {
|
if (codec != null) {
|
||||||
sectionOutputStream = codec.createOutputStream(underlyingOutputStream);
|
sectionOutputStream = codec.createOutputStream(underlyingOutputStream);
|
||||||
@ -685,14 +685,20 @@ public void commitSection(FileSummary.Builder summary, SectionName name)
|
|||||||
subSectionOffset = currentOffset;
|
subSectionOffset = currentOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void commitSubSection(FileSummary.Builder summary, SectionName name)
|
||||||
|
throws IOException {
|
||||||
|
this.commitSubSection(summary, name, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit the length and offset of a fsimage sub-section to the summary
|
* Commit the length and offset of a fsimage sub-section to the summary
|
||||||
* index.
|
* index.
|
||||||
* @param summary The image summary object
|
* @param summary The image summary object
|
||||||
* @param name The name of the sub-section to commit
|
* @param name The name of the sub-section to commit
|
||||||
|
* @param isLast True if sub-section is the last sub-section of each section
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void commitSubSection(FileSummary.Builder summary, SectionName name)
|
public void commitSubSection(FileSummary.Builder summary, SectionName name, boolean isLast)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (!writeSubSections) {
|
if (!writeSubSections) {
|
||||||
return;
|
return;
|
||||||
@ -701,7 +707,15 @@ public void commitSubSection(FileSummary.Builder summary, SectionName name)
|
|||||||
LOG.debug("Saving a subsection for {}", name.toString());
|
LOG.debug("Saving a subsection for {}", name.toString());
|
||||||
// The output stream must be flushed before the length is obtained
|
// The output stream must be flushed before the length is obtained
|
||||||
// as the flush can move the length forward.
|
// as the flush can move the length forward.
|
||||||
sectionOutputStream.flush();
|
flushSectionOutputStream();
|
||||||
|
|
||||||
|
if (codec == null || isLast) {
|
||||||
|
// To avoid empty sub-section, Do not create CompressionOutputStream
|
||||||
|
// if sub-section is last sub-section of each section
|
||||||
|
sectionOutputStream = underlyingOutputStream;
|
||||||
|
} else {
|
||||||
|
sectionOutputStream = codec.createOutputStream(underlyingOutputStream);
|
||||||
|
}
|
||||||
long length = fileChannel.position() - subSectionOffset;
|
long length = fileChannel.position() - subSectionOffset;
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
LOG.warn("The requested section for {} is empty. It will not be " +
|
LOG.warn("The requested section for {} is empty. It will not be " +
|
||||||
|
@ -530,8 +530,8 @@ public void serializeSnapshotDiffSection(OutputStream out)
|
|||||||
context.checkCancelled();
|
context.checkCancelled();
|
||||||
}
|
}
|
||||||
if (i % parent.getInodesPerSubSection() == 0) {
|
if (i % parent.getInodesPerSubSection() == 0) {
|
||||||
parent.commitSubSection(headers,
|
parent.commitSubSection(headers, FSImageFormatProtobuf.SectionName.SNAPSHOT_DIFF_SUB);
|
||||||
FSImageFormatProtobuf.SectionName.SNAPSHOT_DIFF_SUB);
|
out = parent.getSectionOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parent.commitSectionAndSubSection(headers,
|
parent.commitSectionAndSubSection(headers,
|
||||||
|
@ -1120,7 +1120,7 @@ public void testParallelSaveAndLoad() throws IOException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoParallelSectionsWithCompressionEnabled()
|
public void testParallelSaveAndLoadWithCompression()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Configuration conf = new Configuration();
|
Configuration conf = new Configuration();
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_IMAGE_COMPRESS_KEY, true);
|
conf.setBoolean(DFSConfigKeys.DFS_IMAGE_COMPRESS_KEY, true);
|
||||||
@ -1137,16 +1137,21 @@ public void testNoParallelSectionsWithCompressionEnabled()
|
|||||||
getLatestImageSummary(cluster);
|
getLatestImageSummary(cluster);
|
||||||
ArrayList<Section> sections = Lists.newArrayList(
|
ArrayList<Section> sections = Lists.newArrayList(
|
||||||
summary.getSectionsList());
|
summary.getSectionsList());
|
||||||
|
Section inodeSection =
|
||||||
|
getSubSectionsOfName(sections, SectionName.INODE).get(0);
|
||||||
|
Section dirSection = getSubSectionsOfName(sections,
|
||||||
|
SectionName.INODE_DIR).get(0);
|
||||||
|
|
||||||
ArrayList<Section> inodeSubSections =
|
ArrayList<Section> inodeSubSections =
|
||||||
getSubSectionsOfName(sections, SectionName.INODE_SUB);
|
getSubSectionsOfName(sections, SectionName.INODE_SUB);
|
||||||
ArrayList<Section> dirSubSections =
|
ArrayList<Section> dirSubSections =
|
||||||
getSubSectionsOfName(sections, SectionName.INODE_DIR_SUB);
|
getSubSectionsOfName(sections, SectionName.INODE_DIR_SUB);
|
||||||
|
// Compression and parallel can be enabled at the same time.
|
||||||
|
assertEquals(4, inodeSubSections.size());
|
||||||
|
assertEquals(4, dirSubSections.size());
|
||||||
|
|
||||||
// As compression is enabled, there should be no sub-sections in the
|
ensureSubSectionsAlignWithParent(inodeSubSections, inodeSection);
|
||||||
// image header
|
ensureSubSectionsAlignWithParent(dirSubSections, dirSection);
|
||||||
assertEquals(0, inodeSubSections.size());
|
|
||||||
assertEquals(0, dirSubSections.size());
|
|
||||||
} finally {
|
} finally {
|
||||||
if (cluster != null) {
|
if (cluster != null) {
|
||||||
cluster.shutdown();
|
cluster.shutdown();
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.SafeModeAction;
|
import org.apache.hadoop.fs.SafeModeAction;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
import org.apache.hadoop.hdfs.DFSTestUtil;
|
import org.apache.hadoop.hdfs.DFSTestUtil;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||||
@ -78,16 +79,19 @@ public class TestFSImageWithSnapshot {
|
|||||||
FSNamesystem fsn;
|
FSNamesystem fsn;
|
||||||
DistributedFileSystem hdfs;
|
DistributedFileSystem hdfs;
|
||||||
|
|
||||||
@Before
|
public void createCluster() throws IOException {
|
||||||
public void setUp() throws Exception {
|
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(NUM_DATANODES).build();
|
||||||
conf = new Configuration();
|
|
||||||
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(NUM_DATANODES)
|
|
||||||
.build();
|
|
||||||
cluster.waitActive();
|
cluster.waitActive();
|
||||||
fsn = cluster.getNamesystem();
|
fsn = cluster.getNamesystem();
|
||||||
hdfs = cluster.getFileSystem();
|
hdfs = cluster.getFileSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
conf = new Configuration();
|
||||||
|
createCluster();
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
if (cluster != null) {
|
if (cluster != null) {
|
||||||
@ -512,6 +516,32 @@ public void testSaveLoadImageAfterSnapshotDeletion()
|
|||||||
hdfs = cluster.getFileSystem();
|
hdfs = cluster.getFileSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test parallel compressed fsimage can be loaded serially.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testLoadParallelCompressedImageSerial() throws Exception {
|
||||||
|
int s = 0;
|
||||||
|
cluster.shutdown();
|
||||||
|
|
||||||
|
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(NUM_DATANODES).build();
|
||||||
|
cluster.waitActive();
|
||||||
|
fsn = cluster.getNamesystem();
|
||||||
|
hdfs = cluster.getFileSystem();
|
||||||
|
hdfs.mkdirs(dir);
|
||||||
|
SnapshotTestHelper.createSnapshot(hdfs, dir, "s");
|
||||||
|
|
||||||
|
Path sub1 = new Path(dir, "sub1");
|
||||||
|
Path sub1file1 = new Path(sub1, "sub1file1");
|
||||||
|
Path sub1file2 = new Path(sub1, "sub1file2");
|
||||||
|
DFSTestUtil.createFile(hdfs, sub1file1, BLOCKSIZE, (short) 1, seed);
|
||||||
|
DFSTestUtil.createFile(hdfs, sub1file2, BLOCKSIZE, (short) 1, seed);
|
||||||
|
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_IMAGE_COMPRESS_KEY, false);
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_IMAGE_PARALLEL_LOAD_KEY, false);
|
||||||
|
checkImage(s);
|
||||||
|
}
|
||||||
|
|
||||||
void rename(Path src, Path dst) throws Exception {
|
void rename(Path src, Path dst) throws Exception {
|
||||||
printTree("Before rename " + src + " -> " + dst);
|
printTree("Before rename " + src + " -> " + dst);
|
||||||
hdfs.rename(src, dst);
|
hdfs.rename(src, dst);
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.event.Level;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotTestHelper;
|
||||||
|
import org.apache.hadoop.io.compress.GzipCodec;
|
||||||
|
import org.apache.hadoop.test.GenericTestUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test extends TestFSImageWithSnapshot to test
|
||||||
|
* enable both fsimage load parallel and fsimage compress.
|
||||||
|
*/
|
||||||
|
public class TestFSImageWithSnapshotParallelAndCompress extends TestFSImageWithSnapshot {
|
||||||
|
{
|
||||||
|
SnapshotTestHelper.disableLogs();
|
||||||
|
GenericTestUtils.setLogLevel(INode.LOG, Level.TRACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createCluster() throws IOException {
|
||||||
|
|
||||||
|
// turn on both parallelization and compression
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_IMAGE_COMPRESS_KEY, true);
|
||||||
|
conf.set(DFSConfigKeys.DFS_IMAGE_COMPRESSION_CODEC_KEY, GzipCodec.class.getCanonicalName());
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_IMAGE_PARALLEL_LOAD_KEY, true);
|
||||||
|
conf.setInt(DFSConfigKeys.DFS_IMAGE_PARALLEL_INODE_THRESHOLD_KEY, 2);
|
||||||
|
conf.setInt(DFSConfigKeys.DFS_IMAGE_PARALLEL_TARGET_SECTIONS_KEY, 2);
|
||||||
|
conf.setInt(DFSConfigKeys.DFS_IMAGE_PARALLEL_THREADS_KEY, 2);
|
||||||
|
|
||||||
|
conf = new Configuration();
|
||||||
|
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(NUM_DATANODES).build();
|
||||||
|
cluster.waitActive();
|
||||||
|
fsn = cluster.getNamesystem();
|
||||||
|
hdfs = cluster.getFileSystem();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user