Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class SegmentManagerUnlinkFailureTest {

Expand Down Expand Up @@ -123,12 +124,17 @@ public void testFailedUnlinkRetainsBookkeepingAndUsesSuccessorPath() throws Exce
byte[] original = java.nio.file.Files.readAllBytes(Paths.get(failedPath));

FailingFilesFacade facade = new FailingFilesFacade(failedPath, null, null);
AtomicLong ticks = new AtomicLong();
try (SegmentManager manager = new SegmentManager(
segmentSize, TimeUnit.SECONDS.toNanos(60), segmentSize * 8, facade)) {
segmentSize, TimeUnit.SECONDS.toNanos(60), segmentSize * 8, facade, ticks::get)) {
manager.register(ring, dir, watermark);
manager.start();
Assert.assertTrue("manager never attempted the injected unlink",
facade.removeAttempted.await(5, TimeUnit.SECONDS));
ticks.set(TimeUnit.MINUTES.toNanos(1));
manager.wakeWorker();
Assert.assertTrue("manager never retried the injected unlink",
facade.removeRetried.await(5, TimeUnit.SECONDS));
Assert.assertEquals("failed unlink must retain conservative registered bytes",
ring.totalSegmentBytes(), readTotalBytes(manager));
}
Expand Down Expand Up @@ -157,6 +163,7 @@ public void testFailedUnlinkRetainsBookkeepingAndUsesSuccessorPath() throws Exce
Assert.assertTrue("successor write overwrote the failed-unlink segment",
Arrays.equals(original, java.nio.file.Files.readAllBytes(Paths.get(failedPath))));

facade.allowUnlink();
try (SegmentManager retryManager = new SegmentManager(
segmentSize, TimeUnit.SECONDS.toNanos(60), segmentSize * 8, facade)) {
retryManager.register(ring, dir, watermark);
Expand Down Expand Up @@ -243,11 +250,13 @@ private static final class FailingFilesFacade implements FilesFacade {
private final String partialLowerName;
private final String unlinkFailurePath;
private final CountDownLatch removeAttempted = new CountDownLatch(1);
private final CountDownLatch removeRetried = new CountDownLatch(1);
private int openCleanCalls;
private boolean partialFindClosed;
private long partialFindNamePtr;
private boolean partialLowerObserved;
private int unlinkFailuresRemaining = 1;
private int unlinkFailureCount;
private volatile boolean unlinkFailureEnabled = true;

private FailingFilesFacade(
String unlinkFailurePath,
Expand All @@ -259,6 +268,10 @@ private FailingFilesFacade(
this.partialLowerName = partialLowerName;
}

private void allowUnlink() {
unlinkFailureEnabled = false;
}

@Override
public boolean allocate(int fd, long size) { return INSTANCE.allocate(fd, size); }
@Override
Expand Down Expand Up @@ -333,8 +346,14 @@ public long read(int fd, long addr, long len, long offset) {
}
@Override
public boolean remove(String path) {
if (path.equals(unlinkFailurePath) && unlinkFailuresRemaining > 0) {
unlinkFailuresRemaining--;
// Keep the injected fault active until the test explicitly releases
// it. SegmentManager automatically retries failed trims, and its
// poll park may return early, so a one-shot failure can recover
// before the test observes the retained bookkeeping state.
if (unlinkFailureEnabled && path.equals(unlinkFailurePath)) {
if (++unlinkFailureCount > 1) {
removeRetried.countDown();
}
removeAttempted.countDown();
return false;
}
Expand Down
Loading