|
43 | 43 | import java.io.File;
|
44 | 44 | import java.io.FilenameFilter;
|
45 | 45 | import java.io.IOException;
|
| 46 | +import java.nio.file.Files; |
| 47 | +import java.nio.file.Path; |
46 | 48 | import java.util.Arrays;
|
47 | 49 | import java.util.Collections;
|
48 | 50 | import java.util.Iterator;
|
@@ -77,6 +79,35 @@ public class FsImageValidation {
|
77 | 79 |
|
78 | 80 | static final String FS_IMAGE = "FS_IMAGE";
|
79 | 81 |
|
| 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 | + |
80 | 111 | static String getEnv(String property) {
|
81 | 112 | final String value = System.getenv().get(property);
|
82 | 113 | LOG.info("ENV: {} = {}", property, value);
|
@@ -186,13 +217,19 @@ int run(Configuration conf, AtomicInteger errorCount) throws Exception {
|
186 | 217 | final FSNamesystem namesystem = checkINodeReference(conf, errorCount);
|
187 | 218 |
|
188 | 219 | // check INodeMap
|
189 |
| - INodeMapValidation.run(namesystem.getFSDirectory(), errorCount); |
| 220 | + final boolean changed = INodeMapValidation.run(namesystem.getFSDirectory(), errorCount); |
190 | 221 | LOG.info(Util.memoryInfo());
|
191 | 222 |
|
192 | 223 | final int d = errorCount.get() - initCount;
|
193 | 224 | if (d > 0) {
|
194 | 225 | Cli.println("Found %d error(s) in %s", d, fsImageFile.getAbsolutePath());
|
195 | 226 | }
|
| 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 | + } |
196 | 233 | return d;
|
197 | 234 | }
|
198 | 235 |
|
@@ -261,27 +298,26 @@ FSNamesystem checkINodeReference(Configuration conf,
|
261 | 298 | }
|
262 | 299 |
|
263 | 300 | 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(); |
274 | 303 | final int initErrorCount = errorCount.get();
|
275 | 304 | 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(); |
277 | 310 | if (counts.getCount(i) == 0) {
|
| 311 | + j.remove(); |
278 | 312 | Cli.printError(errorCount, "%s (%d) is inaccessible (%s)",
|
279 | 313 | i, i.getId(), i.getFullPathName());
|
280 | 314 | }
|
281 | 315 | }
|
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, |
284 | 319 | errorCount.get() - initErrorCount);
|
| 320 | + return newSize != oldSize; |
285 | 321 | }
|
286 | 322 | }
|
287 | 323 |
|
@@ -343,6 +379,10 @@ static synchronized void printError(String message, Throwable t) {
|
343 | 379 | static synchronized void printError(AtomicInteger errorCount,
|
344 | 380 | String format, Object... args) {
|
345 | 381 | final int count = errorCount.incrementAndGet();
|
| 382 | + if (!PRINT_ERROR) { |
| 383 | + return; |
| 384 | + } |
| 385 | + |
346 | 386 | final String s = "FSIMAGE_ERROR " + count + ": "
|
347 | 387 | + String.format(format, args);
|
348 | 388 | System.out.println(s);
|
|
0 commit comments