Skip to content

Commit cd68d13

Browse files
committed
Revert " HADOOP-19554. LocalDirAllocator still doesn't always recover from directory deletion (#7651)"
not the final commit This reverts commit 4769feb.
1 parent 4769feb commit cd68d13

File tree

2 files changed

+33
-129
lines changed

2 files changed

+33
-129
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/LocalDirAllocator.java

Lines changed: 24 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,7 @@
6565
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
6666
@InterfaceStability.Unstable
6767
public class LocalDirAllocator {
68-
69-
static final String E_NO_SPACE_AVAILABLE =
70-
"No space available in any of the local directories";
71-
68+
7269
//A Map from the config item names like "mapred.local.dir"
7370
//to the instance of the AllocatorPerContext. This
7471
//is a static object to make sure there exists exactly one instance per JVM
@@ -387,24 +384,6 @@ int getCurrentDirectoryIndex() {
387384
return currentContext.get().dirNumLastAccessed.get();
388385
}
389386

390-
/**
391-
* Format a string, log at debug and append it to the history as a new line.
392-
*
393-
* @param history history to fill in
394-
* @param fmt format string
395-
* @param args varags
396-
*/
397-
private void note(StringBuilder history, String fmt, Object... args) {
398-
try {
399-
final String s = String.format(fmt, args);
400-
history.append(s).append("\n");
401-
LOG.debug(s);
402-
} catch (Exception e) {
403-
// some resilience in case the format string is wrong
404-
LOG.debug(fmt, e);
405-
}
406-
}
407-
408387
/** Get a path from the local FS. If size is known, we go
409388
* round-robin over the set of disks (via the configured dirs) and return
410389
* the first complete path which has enough space.
@@ -414,12 +393,6 @@ private void note(StringBuilder history, String fmt, Object... args) {
414393
*/
415394
public Path getLocalPathForWrite(String pathStr, long size,
416395
Configuration conf, boolean checkWrite) throws IOException {
417-
418-
// history is built up and logged at error if the alloc
419-
StringBuilder history = new StringBuilder();
420-
421-
note(history, "Searchng for a directory for file at %s, size = %,d; checkWrite=%s",
422-
pathStr, size, checkWrite);
423396
Context ctx = confChanged(conf);
424397
int numDirs = ctx.localDirs.length;
425398
int numDirsSearched = 0;
@@ -433,56 +406,27 @@ public Path getLocalPathForWrite(String pathStr, long size,
433406
pathStr = pathStr.substring(1);
434407
}
435408
Path returnPath = null;
436-
437-
final int dirCount = ctx.dirDF.length;
438-
long[] availableOnDisk = new long[dirCount];
439-
long totalAvailable = 0;
440-
441-
StringBuilder pathNames = new StringBuilder();
442-
443-
//build the "roulette wheel"
444-
for (int i =0; i < dirCount; ++i) {
445-
final DF target = ctx.dirDF[i];
446-
// attempt to recreate the dir so that getAvailable() is valid
447-
// if it fails, getAvailable() will return 0, so the dir will
448-
// be declared unavailable.
449-
// return value is logged at debug to keep spotbugs quiet.
450-
final String name = target.getDirPath();
451-
pathNames.append(" ").append(name);
452-
final File dirPath = new File(name);
453-
454-
// existence probe
455-
if (!dirPath.exists()) {
456-
LOG.debug("creating buffer dir {}", name);
457-
if (dirPath.mkdirs()) {
458-
note(history, "Created buffer dir %s", name);
459-
} else {
460-
note(history, "Failed to create buffer dir %s", name);
461-
}
462-
}
463-
464-
// path already existed or the mkdir call had an outcome
465-
// make sure the path is present and a dir, and if so add its availability
466-
if (dirPath.isDirectory()) {
467-
final long available = target.getAvailable();
468-
availableOnDisk[i] = available;
469-
note(history, "%s available under path %s", pathStr, available);
409+
410+
if(size == SIZE_UNKNOWN) { //do roulette selection: pick dir with probability
411+
//proportional to available size
412+
long[] availableOnDisk = new long[ctx.dirDF.length];
413+
long totalAvailable = 0;
414+
415+
//build the "roulette wheel"
416+
for(int i =0; i < ctx.dirDF.length; ++i) {
417+
final DF target = ctx.dirDF[i];
418+
// attempt to recreate the dir so that getAvailable() is valid
419+
// if it fails, getAvailable() will return 0, so the dir will
420+
// be declared unavailable.
421+
// return value is logged at debug to keep spotbugs quiet.
422+
final boolean b = new File(target.getDirPath()).mkdirs();
423+
LOG.debug("mkdirs of {}={}", target, b);
424+
availableOnDisk[i] = target.getAvailable();
470425
totalAvailable += availableOnDisk[i];
471-
} else {
472-
note(history, "%s does not exist/is not a directory", pathStr);
473426
}
474-
}
475-
476-
note(history, "Directory count is %d; total available capacity is %,d{}",
477-
dirCount, totalAvailable);
478427

479-
if (size == SIZE_UNKNOWN) {
480-
//do roulette selection: pick dir with probability
481-
// proportional to available size
482-
note(history, "Size not specified, so picking at random.");
483-
484-
if (totalAvailable == 0) {
485-
throw new DiskErrorException(E_NO_SPACE_AVAILABLE + pathNames + "; history=" + history);
428+
if (totalAvailable == 0){
429+
throw new DiskErrorException("No space available in any of the local directories.");
486430
}
487431

488432
// Keep rolling the wheel till we get a valid path
@@ -495,19 +439,14 @@ public Path getLocalPathForWrite(String pathStr, long size,
495439
dir++;
496440
}
497441
ctx.dirNumLastAccessed.set(dir);
498-
final Path localDir = ctx.localDirs[dir];
499-
returnPath = createPath(localDir, pathStr, checkWrite);
442+
returnPath = createPath(ctx.localDirs[dir], pathStr, checkWrite);
500443
if (returnPath == null) {
501444
totalAvailable -= availableOnDisk[dir];
502445
availableOnDisk[dir] = 0; // skip this disk
503446
numDirsSearched++;
504-
note(history, "No capacity in %s", localDir);
505-
} else {
506-
note(history, "Allocated file %s in %s", returnPath, localDir);
507447
}
508448
}
509449
} else {
510-
note(history, "Size is %,d; searching", size);
511450
// Start linear search with random increment if possible
512451
int randomInc = 1;
513452
if (numDirs > 2) {
@@ -520,22 +459,17 @@ public Path getLocalPathForWrite(String pathStr, long size,
520459
maxCapacity = capacity;
521460
}
522461
if (capacity > size) {
523-
final Path localDir = ctx.localDirs[dirNum];
524462
try {
525-
returnPath = createPath(localDir, pathStr, checkWrite);
463+
returnPath = createPath(ctx.localDirs[dirNum], pathStr,
464+
checkWrite);
526465
} catch (IOException e) {
527466
errorText = e.getMessage();
528467
diskException = e;
529-
note(history, "Exception while creating path %s: %s", localDir, errorText);
530-
LOG.debug("DiskException caught for dir {}", localDir, e);
468+
LOG.debug("DiskException caught for dir {}", ctx.localDirs[dirNum], e);
531469
}
532470
if (returnPath != null) {
533-
// success
534471
ctx.getAndIncrDirNumLastAccessed(numDirsSearched);
535-
note(history, "Allocated file %s in %s", returnPath, localDir);
536472
break;
537-
} else {
538-
note(history, "No capacity in %s", localDir);
539473
}
540474
}
541475
dirNum++;
@@ -550,14 +484,10 @@ public Path getLocalPathForWrite(String pathStr, long size,
550484
//no path found
551485
String newErrorText = "Could not find any valid local directory for " +
552486
pathStr + " with requested size " + size +
553-
" as the max capacity in any directory"
554-
+ " (" + pathNames + " )"
555-
+ " is " + maxCapacity;
487+
" as the max capacity in any directory is " + maxCapacity;
556488
if (errorText != null) {
557489
newErrorText = newErrorText + " due to " + errorText;
558490
}
559-
LOG.error(newErrorText);
560-
LOG.error(history.toString());
561491
throw new DiskErrorException(newErrorText, diskException);
562492
}
563493

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalDirAllocator.java

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,14 @@
2626
import java.util.NoSuchElementException;
2727

2828
import org.apache.hadoop.conf.Configuration;
29+
import org.apache.hadoop.test.LambdaTestUtils;
2930
import org.apache.hadoop.util.DiskChecker.DiskErrorException;
3031
import org.apache.hadoop.util.Shell;
3132

32-
import org.assertj.core.api.Assertions;
3333
import org.junit.jupiter.api.Timeout;
3434
import org.junit.jupiter.params.ParameterizedTest;
3535
import org.junit.jupiter.params.provider.MethodSource;
3636

37-
import static org.apache.hadoop.fs.LocalDirAllocator.E_NO_SPACE_AVAILABLE;
38-
import static org.apache.hadoop.test.LambdaTestUtils.intercept;
3937
import static org.apache.hadoop.test.PlatformAssumptions.assumeNotWindows;
4038
import static org.junit.jupiter.api.Assertions.assertEquals;
4139
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -566,8 +564,13 @@ public void testGetLocalPathForWriteForInvalidPaths(String paramRoot, String par
566564
throws Exception {
567565
initTestLocalDirAllocator(paramRoot, paramPrefix);
568566
conf.set(CONTEXT, " ");
569-
intercept(IOException.class, E_NO_SPACE_AVAILABLE, () ->
570-
dirAllocator.getLocalPathForWrite("/test", conf));
567+
try {
568+
dirAllocator.getLocalPathForWrite("/test", conf);
569+
fail("not throwing the exception");
570+
} catch (IOException e) {
571+
assertEquals("No space available in any of the local directories.",
572+
e.getMessage(), "Incorrect exception message");
573+
}
571574
}
572575

573576
/**
@@ -584,13 +587,10 @@ public void testGetLocalPathForWriteForLessSpace(String paramRoot, String paramP
584587
String dir0 = buildBufferDir(root, 0);
585588
String dir1 = buildBufferDir(root, 1);
586589
conf.set(CONTEXT, dir0 + "," + dir1);
587-
final DiskErrorException ex = intercept(DiskErrorException.class,
590+
LambdaTestUtils.intercept(DiskErrorException.class,
588591
String.format("Could not find any valid local directory for %s with requested size %s",
589592
"p1/x", Long.MAX_VALUE - 1), "Expect a DiskErrorException.",
590593
() -> dirAllocator.getLocalPathForWrite("p1/x", Long.MAX_VALUE - 1, conf));
591-
Assertions.assertThat(ex.getMessage())
592-
.contains(new File(dir0).getName())
593-
.contains(new File(dir1).getName());
594594
}
595595

596596
/**
@@ -614,31 +614,5 @@ public void testDirectoryRecovery(String paramRoot, String paramPrefix) throws T
614614
// and expect to get a new file back
615615
dirAllocator.getLocalPathForWrite("file2", -1, conf);
616616
}
617-
618-
619-
/**
620-
* Test for HADOOP-19554. LocalDirAllocator still doesn't always recover
621-
* from directory tree deletion.
622-
*/
623-
@Timeout(value = 30)
624-
@MethodSource("params")
625-
@ParameterizedTest
626-
public void testDirectoryRecoveryKnownSize(String paramRoot, String paramPrefix) throws Throwable {
627-
initTestLocalDirAllocator(paramRoot, paramPrefix);
628-
String dir0 = buildBufferDir(root, 0);
629-
String subdir = dir0 + "/subdir1/subdir2";
630-
631-
conf.set(CONTEXT, subdir);
632-
// get local path and an ancestor
633-
final Path pathForWrite = dirAllocator.getLocalPathForWrite("file", 512, conf);
634-
final Path ancestor = pathForWrite.getParent().getParent();
635-
636-
// delete that ancestor
637-
localFs.delete(ancestor, true);
638-
// and expect to get a new file back
639-
dirAllocator.getLocalPathForWrite("file2", -1, conf);
640-
}
641-
642-
643617
}
644618

0 commit comments

Comments
 (0)