Skip to content

Commit b25b28e

Browse files
authored
HDFS-17380. FsImageValidation: remove inaccessible nodes. (apache#6549). Contributed by Tsz-wo Sze.
Signed-off-by: He Xiaoqiao <[email protected]>
1 parent 4d88f98 commit b25b28e

File tree

2 files changed

+63
-14
lines changed

2 files changed

+63
-14
lines changed

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java

+9
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.FileNotFoundException;
2525
import java.io.IOException;
2626
import java.net.URI;
27+
import java.nio.file.Files;
2728
import java.util.ArrayList;
2829
import java.util.Collection;
2930
import java.util.Collections;
@@ -1213,6 +1214,14 @@ public void removeFromCheckpointing(long txid) {
12131214
currentlyCheckpointing.remove(txid);
12141215
}
12151216

1217+
void save(FSNamesystem src, File dst) throws IOException {
1218+
final SaveNamespaceContext context = new SaveNamespaceContext(src,
1219+
getCorrectLastAppliedOrWrittenTxId(), new Canceler());
1220+
final Storage.StorageDirectory storageDirectory = new Storage.StorageDirectory(dst);
1221+
Files.createDirectories(storageDirectory.getCurrentDir().toPath());
1222+
new FSImageSaver(context, storageDirectory, NameNodeFile.IMAGE).run();
1223+
}
1224+
12161225
private synchronized void saveFSImageInAllDirs(FSNamesystem source,
12171226
NameNodeFile nnf, long txid, Canceler canceler) throws IOException {
12181227
StartupProgress prog = NameNode.getStartupProgress();

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FsImageValidation.java

+54-14
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import java.io.File;
4444
import java.io.FilenameFilter;
4545
import java.io.IOException;
46+
import java.nio.file.Files;
47+
import java.nio.file.Path;
4648
import java.util.Arrays;
4749
import java.util.Collections;
4850
import java.util.Iterator;
@@ -77,6 +79,35 @@ public class FsImageValidation {
7779

7880
static final String FS_IMAGE = "FS_IMAGE";
7981

82+
/**
83+
* Use an environment variable "PRINT_ERROR" to enable/disable printing error messages.
84+
* The default is true
85+
*/
86+
static final boolean PRINT_ERROR;
87+
88+
static {
89+
PRINT_ERROR = getEnvBoolean("PRINT_ERROR", true);
90+
}
91+
92+
/**
93+
* @return the boolean value of an environment property.
94+
* If the environment property is not set or cannot be parsed as a boolean,
95+
* return the default value.
96+
*/
97+
static boolean getEnvBoolean(String property, boolean defaultValue) {
98+
final String env = System.getenv().get(property);
99+
final boolean setToNonDefault = ("" + !defaultValue).equalsIgnoreCase(env);
100+
// default | setToNonDefault | value
101+
// ---------------------------------
102+
// true | true | false
103+
// true | false | true
104+
// false | true | true
105+
// false | false | false
106+
final boolean value = defaultValue != setToNonDefault;
107+
LOG.info("ENV: {} = {} (\"{}\")", property, value, env);
108+
return value;
109+
}
110+
80111
static String getEnv(String property) {
81112
final String value = System.getenv().get(property);
82113
LOG.info("ENV: {} = {}", property, value);
@@ -186,13 +217,19 @@ int run(Configuration conf, AtomicInteger errorCount) throws Exception {
186217
final FSNamesystem namesystem = checkINodeReference(conf, errorCount);
187218

188219
// check INodeMap
189-
INodeMapValidation.run(namesystem.getFSDirectory(), errorCount);
220+
final boolean changed = INodeMapValidation.run(namesystem.getFSDirectory(), errorCount);
190221
LOG.info(Util.memoryInfo());
191222

192223
final int d = errorCount.get() - initCount;
193224
if (d > 0) {
194225
Cli.println("Found %d error(s) in %s", d, fsImageFile.getAbsolutePath());
195226
}
227+
if (changed) {
228+
final File dir = fsImageFile.isDirectory()? fsImageFile: fsImageFile.getParentFile();
229+
final Path temp = Files.createTempDirectory(dir.toPath(), "newFsImage");
230+
Cli.println("INodeMap changed, save a new FSImage to %s", temp);
231+
namesystem.getFSImage().save(namesystem, temp.toFile());
232+
}
196233
return d;
197234
}
198235

@@ -261,27 +298,26 @@ FSNamesystem checkINodeReference(Configuration conf,
261298
}
262299

263300
static class INodeMapValidation {
264-
static Iterable<INodeWithAdditionalFields> iterate(INodeMap map) {
265-
return new Iterable<INodeWithAdditionalFields>() {
266-
@Override
267-
public Iterator<INodeWithAdditionalFields> iterator() {
268-
return map.getMapIterator();
269-
}
270-
};
271-
}
272-
273-
static void run(FSDirectory fsdir, AtomicInteger errorCount) {
301+
static boolean run(FSDirectory fsdir, AtomicInteger errorCount) {
302+
final String name = INodeMapValidation.class.getSimpleName();
274303
final int initErrorCount = errorCount.get();
275304
final Counts counts = INodeCountVisitor.countTree(fsdir.getRoot());
276-
for (INodeWithAdditionalFields i : iterate(fsdir.getINodeMap())) {
305+
final INodeMap map = fsdir.getINodeMap();
306+
final int oldSize = map.size();
307+
println("%s INodeMap old size: %d", name, oldSize);
308+
for (final Iterator<INodeWithAdditionalFields> j = map.getMapIterator(); j.hasNext();) {
309+
final INodeWithAdditionalFields i = j.next();
277310
if (counts.getCount(i) == 0) {
311+
j.remove();
278312
Cli.printError(errorCount, "%s (%d) is inaccessible (%s)",
279313
i, i.getId(), i.getFullPathName());
280314
}
281315
}
282-
println("%s ended successfully: %d error(s) found.",
283-
INodeMapValidation.class.getSimpleName(),
316+
final int newSize = map.size();
317+
println("%s INodeMap new size: %d", name, newSize);
318+
println("%s ended successfully: %d error(s) found.", name,
284319
errorCount.get() - initErrorCount);
320+
return newSize != oldSize;
285321
}
286322
}
287323

@@ -343,6 +379,10 @@ static synchronized void printError(String message, Throwable t) {
343379
static synchronized void printError(AtomicInteger errorCount,
344380
String format, Object... args) {
345381
final int count = errorCount.incrementAndGet();
382+
if (!PRINT_ERROR) {
383+
return;
384+
}
385+
346386
final String s = "FSIMAGE_ERROR " + count + ": "
347387
+ String.format(format, args);
348388
System.out.println(s);

0 commit comments

Comments
 (0)