|
@@ -18,13 +18,19 @@
|
|
|
|
|
|
package org.apache.hadoop.hdfs.server.datanode;
|
|
|
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import com.google.common.util.concurrent.Futures;
|
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.fs.FileSystem;
|
|
|
-import org.apache.hadoop.fs.*;
|
|
|
+import org.apache.hadoop.fs.FileUtil;
|
|
|
+import org.apache.hadoop.fs.HardLink;
|
|
|
+import org.apache.hadoop.fs.LocalFileSystem;
|
|
|
+import org.apache.hadoop.fs.Path;
|
|
|
import org.apache.hadoop.fs.permission.FsPermission;
|
|
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
|
|
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
|
|
+import org.apache.hadoop.hdfs.protocol.Block;
|
|
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
|
|
import org.apache.hadoop.hdfs.protocol.LayoutVersion;
|
|
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NodeType;
|
|
@@ -35,13 +41,30 @@ import org.apache.hadoop.hdfs.server.common.StorageInfo;
|
|
|
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorage;
|
|
|
import org.apache.hadoop.hdfs.server.protocol.NamespaceInfo;
|
|
|
import org.apache.hadoop.io.IOUtils;
|
|
|
+import org.apache.hadoop.io.nativeio.NativeIO;
|
|
|
import org.apache.hadoop.util.Daemon;
|
|
|
import org.apache.hadoop.util.DiskChecker;
|
|
|
|
|
|
-import java.io.*;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.FileOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.RandomAccessFile;
|
|
|
import java.nio.channels.FileLock;
|
|
|
-import java.util.*;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Properties;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.concurrent.Callable;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
+import java.util.concurrent.Future;
|
|
|
|
|
|
/**
|
|
|
* Data storage information file.
|
|
@@ -261,6 +284,7 @@ public class DataStorage extends Storage {
|
|
|
STORAGE_DIR_CURRENT));
|
|
|
bpDataDirs.add(bpRoot);
|
|
|
}
|
|
|
+
|
|
|
// mkdir for the list of BlockPoolStorage
|
|
|
makeBlockPoolDataDir(bpDataDirs, null);
|
|
|
BlockPoolSliceStorage bpStorage = new BlockPoolSliceStorage(
|
|
@@ -488,7 +512,7 @@ public class DataStorage extends Storage {
|
|
|
|
|
|
// do upgrade
|
|
|
if (this.layoutVersion > HdfsConstants.DATANODE_LAYOUT_VERSION) {
|
|
|
- doUpgrade(sd, nsInfo); // upgrade
|
|
|
+ doUpgrade(datanode, sd, nsInfo); // upgrade
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -523,7 +547,8 @@ public class DataStorage extends Storage {
|
|
|
* @param sd storage directory
|
|
|
* @throws IOException on error
|
|
|
*/
|
|
|
- void doUpgrade(StorageDirectory sd, NamespaceInfo nsInfo) throws IOException {
|
|
|
+ void doUpgrade(DataNode datanode, StorageDirectory sd, NamespaceInfo nsInfo)
|
|
|
+ throws IOException {
|
|
|
// If the existing on-disk layout version supportes federation, simply
|
|
|
// update its layout version.
|
|
|
if (DataNodeLayoutVersion.supports(
|
|
@@ -568,7 +593,8 @@ public class DataStorage extends Storage {
|
|
|
BlockPoolSliceStorage bpStorage = new BlockPoolSliceStorage(nsInfo.getNamespaceID(),
|
|
|
nsInfo.getBlockPoolID(), nsInfo.getCTime(), nsInfo.getClusterID());
|
|
|
bpStorage.format(curDir, nsInfo);
|
|
|
- linkAllBlocks(tmpDir, bbwDir, new File(curBpDir, STORAGE_DIR_CURRENT));
|
|
|
+ linkAllBlocks(datanode, tmpDir, bbwDir, new File(curBpDir,
|
|
|
+ STORAGE_DIR_CURRENT));
|
|
|
|
|
|
// 4. Write version file under <SD>/current
|
|
|
layoutVersion = HdfsConstants.DATANODE_LAYOUT_VERSION;
|
|
@@ -746,22 +772,22 @@ public class DataStorage extends Storage {
|
|
|
*
|
|
|
* @throws IOException If error occurs during hardlink
|
|
|
*/
|
|
|
- private void linkAllBlocks(File fromDir, File fromBbwDir, File toDir)
|
|
|
- throws IOException {
|
|
|
+ private void linkAllBlocks(DataNode datanode, File fromDir, File fromBbwDir,
|
|
|
+ File toDir) throws IOException {
|
|
|
HardLink hardLink = new HardLink();
|
|
|
// do the link
|
|
|
int diskLayoutVersion = this.getLayoutVersion();
|
|
|
if (DataNodeLayoutVersion.supports(
|
|
|
LayoutVersion.Feature.APPEND_RBW_DIR, diskLayoutVersion)) {
|
|
|
// hardlink finalized blocks in tmpDir/finalized
|
|
|
- linkBlocks(new File(fromDir, STORAGE_DIR_FINALIZED),
|
|
|
+ linkBlocks(datanode, new File(fromDir, STORAGE_DIR_FINALIZED),
|
|
|
new File(toDir, STORAGE_DIR_FINALIZED), diskLayoutVersion, hardLink);
|
|
|
// hardlink rbw blocks in tmpDir/rbw
|
|
|
- linkBlocks(new File(fromDir, STORAGE_DIR_RBW),
|
|
|
+ linkBlocks(datanode, new File(fromDir, STORAGE_DIR_RBW),
|
|
|
new File(toDir, STORAGE_DIR_RBW), diskLayoutVersion, hardLink);
|
|
|
} else { // pre-RBW version
|
|
|
// hardlink finalized blocks in tmpDir
|
|
|
- linkBlocks(fromDir, new File(toDir, STORAGE_DIR_FINALIZED),
|
|
|
+ linkBlocks(datanode, fromDir, new File(toDir, STORAGE_DIR_FINALIZED),
|
|
|
diskLayoutVersion, hardLink);
|
|
|
if (fromBbwDir.exists()) {
|
|
|
/*
|
|
@@ -770,15 +796,67 @@ public class DataStorage extends Storage {
|
|
|
* NOT underneath the 'current' directory in those releases. See
|
|
|
* HDFS-3731 for details.
|
|
|
*/
|
|
|
- linkBlocks(fromBbwDir,
|
|
|
+ linkBlocks(datanode, fromBbwDir,
|
|
|
new File(toDir, STORAGE_DIR_RBW), diskLayoutVersion, hardLink);
|
|
|
}
|
|
|
}
|
|
|
LOG.info( hardLink.linkStats.report() );
|
|
|
}
|
|
|
+
|
|
|
+ private static class LinkArgs {
|
|
|
+ public File src;
|
|
|
+ public File dst;
|
|
|
+
|
|
|
+ public LinkArgs(File src, File dst) {
|
|
|
+ this.src = src;
|
|
|
+ this.dst = dst;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void linkBlocks(DataNode datanode, File from, File to, int oldLV,
|
|
|
+ HardLink hl) throws IOException {
|
|
|
+ boolean upgradeToIdBasedLayout = false;
|
|
|
+ // If we are upgrading from a version older than the one where we introduced
|
|
|
+ // block ID-based layout AND we're working with the finalized directory,
|
|
|
+ // we'll need to upgrade from the old flat layout to the block ID-based one
|
|
|
+ if (oldLV > DataNodeLayoutVersion.Feature.BLOCKID_BASED_LAYOUT.getInfo().
|
|
|
+ getLayoutVersion() && to.getName().equals(STORAGE_DIR_FINALIZED)) {
|
|
|
+ upgradeToIdBasedLayout = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ final List<LinkArgs> idBasedLayoutSingleLinks = Lists.newArrayList();
|
|
|
+ linkBlocksHelper(from, to, oldLV, hl, upgradeToIdBasedLayout, to,
|
|
|
+ idBasedLayoutSingleLinks);
|
|
|
+ int numLinkWorkers = datanode.getConf().getInt(
|
|
|
+ DFSConfigKeys.DFS_DATANODE_BLOCK_ID_LAYOUT_UPGRADE_THREADS_KEY,
|
|
|
+ DFSConfigKeys.DFS_DATANODE_BLOCK_ID_LAYOUT_UPGRADE_THREADS);
|
|
|
+ ExecutorService linkWorkers = Executors.newFixedThreadPool(numLinkWorkers);
|
|
|
+ final int step = idBasedLayoutSingleLinks.size() / numLinkWorkers + 1;
|
|
|
+ List<Future<Void>> futures = Lists.newArrayList();
|
|
|
+ for (int i = 0; i < idBasedLayoutSingleLinks.size(); i += step) {
|
|
|
+ final int iCopy = i;
|
|
|
+ futures.add(linkWorkers.submit(new Callable<Void>() {
|
|
|
+ @Override
|
|
|
+ public Void call() throws IOException {
|
|
|
+ int upperBound = Math.min(iCopy + step,
|
|
|
+ idBasedLayoutSingleLinks.size());
|
|
|
+ for (int j = iCopy; j < upperBound; j++) {
|
|
|
+ LinkArgs cur = idBasedLayoutSingleLinks.get(j);
|
|
|
+ NativeIO.link(cur.src, cur.dst);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ linkWorkers.shutdown();
|
|
|
+ for (Future<Void> f : futures) {
|
|
|
+ Futures.get(f, IOException.class);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- static void linkBlocks(File from, File to, int oldLV, HardLink hl)
|
|
|
- throws IOException {
|
|
|
+ static void linkBlocksHelper(File from, File to, int oldLV, HardLink hl,
|
|
|
+ boolean upgradeToIdBasedLayout, File blockRoot,
|
|
|
+ List<LinkArgs> idBasedLayoutSingleLinks) throws IOException {
|
|
|
if (!from.exists()) {
|
|
|
return;
|
|
|
}
|
|
@@ -805,9 +883,6 @@ public class DataStorage extends Storage {
|
|
|
// from is a directory
|
|
|
hl.linkStats.countDirs++;
|
|
|
|
|
|
- if (!to.mkdirs())
|
|
|
- throw new IOException("Cannot create directory " + to);
|
|
|
-
|
|
|
String[] blockNames = from.list(new java.io.FilenameFilter() {
|
|
|
@Override
|
|
|
public boolean accept(File dir, String name) {
|
|
@@ -815,12 +890,36 @@ public class DataStorage extends Storage {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+ // If we are upgrading to block ID-based layout, we don't want to recreate
|
|
|
+ // any subdirs from the source that contain blocks, since we have a new
|
|
|
+ // directory structure
|
|
|
+ if (!upgradeToIdBasedLayout || !to.getName().startsWith(
|
|
|
+ BLOCK_SUBDIR_PREFIX)) {
|
|
|
+ if (!to.mkdirs())
|
|
|
+ throw new IOException("Cannot create directory " + to);
|
|
|
+ }
|
|
|
+
|
|
|
// Block files just need hard links with the same file names
|
|
|
// but a different directory
|
|
|
if (blockNames.length > 0) {
|
|
|
- HardLink.createHardLinkMult(from, blockNames, to);
|
|
|
- hl.linkStats.countMultLinks++;
|
|
|
- hl.linkStats.countFilesMultLinks += blockNames.length;
|
|
|
+ if (upgradeToIdBasedLayout) {
|
|
|
+ for (String blockName : blockNames) {
|
|
|
+ long blockId = Block.getBlockId(blockName);
|
|
|
+ File blockLocation = DatanodeUtil.idToBlockDir(blockRoot, blockId);
|
|
|
+ if (!blockLocation.exists()) {
|
|
|
+ if (!blockLocation.mkdirs()) {
|
|
|
+ throw new IOException("Failed to mkdirs " + blockLocation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ idBasedLayoutSingleLinks.add(new LinkArgs(new File(from, blockName),
|
|
|
+ new File(blockLocation, blockName)));
|
|
|
+ hl.linkStats.countSingleLinks++;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ HardLink.createHardLinkMult(from, blockNames, to);
|
|
|
+ hl.linkStats.countMultLinks++;
|
|
|
+ hl.linkStats.countFilesMultLinks += blockNames.length;
|
|
|
+ }
|
|
|
} else {
|
|
|
hl.linkStats.countEmptyDirs++;
|
|
|
}
|
|
@@ -834,8 +933,9 @@ public class DataStorage extends Storage {
|
|
|
}
|
|
|
});
|
|
|
for(int i = 0; i < otherNames.length; i++)
|
|
|
- linkBlocks(new File(from, otherNames[i]),
|
|
|
- new File(to, otherNames[i]), oldLV, hl);
|
|
|
+ linkBlocksHelper(new File(from, otherNames[i]),
|
|
|
+ new File(to, otherNames[i]), oldLV, hl, upgradeToIdBasedLayout,
|
|
|
+ blockRoot, idBasedLayoutSingleLinks);
|
|
|
}
|
|
|
|
|
|
/**
|