diff --git a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java index 7f4f35ad83..51b2c76bf8 100644 --- a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java +++ b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java @@ -21,12 +21,33 @@ package org.apache.jackrabbit.oak.segment.file; import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.jackrabbit.oak.commons.Buffer; +import org.apache.jackrabbit.oak.segment.Segment; import org.apache.jackrabbit.oak.segment.SegmentId; import org.apache.jackrabbit.oak.segment.SegmentNodeBuilder; import org.apache.jackrabbit.oak.segment.SegmentNodeState; +import org.apache.jackrabbit.oak.segment.SegmentNotFoundException; +import org.apache.jackrabbit.oak.segment.SegmentNotFoundExceptionListener; +import org.apache.jackrabbit.oak.segment.spi.RepositoryNotReachableException; +import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence; +import org.apache.jackrabbit.oak.segment.spi.persistence.persistentcache.AbstractPersistentCache; +import org.apache.jackrabbit.oak.segment.spi.persistence.persistentcache.CachingPersistence; +import org.apache.jackrabbit.oak.segment.spi.persistence.persistentcache.SegmentCacheStats; +import org.jetbrains.annotations.NotNull; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -84,5 +105,107 @@ public class FileStoreTest { } } + @Test(expected = RepositoryNotReachableException.class) + public void testRepositoryNotReachable() throws IOException, InvalidFileStoreVersionException { + FileStoreBuilder fileStoreBuilder; + FileStore fileStore = null; + try { + + fileStoreBuilder = getFileStoreBuilder(false); + + fileStore = fileStoreBuilder.build(); + + SegmentId id = new SegmentId(fileStore, 5, 5); + byte[] buffer = new byte[2]; + fileStore.writeSegment(id, buffer, 0, 2); + + assertTrue(fileStore.containsSegment(id)); + //close file store so that TarReader is used to read the segment + fileStore.close(); + + fileStoreBuilder = getFileStoreBuilder(false); + fileStore = fileStoreBuilder.build(); + + Segment segment = fileStore.readSegment(id); + assertNotNull(segment); + + fileStore.close(); + + // Construct file store that will simulate throwing RepositoryNotReachableException when reading a segment + fileStoreBuilder = getFileStoreBuilder(true); + fileStore = fileStoreBuilder.build(); + try { + fileStore.readSegment(id); + } catch (SegmentNotFoundException e) { + fail(); + } + } finally { + if (fileStore != null) { + fileStore.close(); + } + } + } + + /** + * @param repoNotReachable - if set to true, {@code RepositoryNotReachableException} will be thrown when calling {@code SegmentArchiveReader}#readSegment + * @return + */ + @NotNull + private FileStoreBuilder getFileStoreBuilder(boolean repoNotReachable) { + FileStoreBuilder fileStoreBuilder; + fileStoreBuilder = fileStoreBuilder(getFileStoreFolder()); + fileStoreBuilder.withSegmentCacheSize(10); + + SegmentNodeStorePersistence customPersistence = new CachingPersistence(new MemoryPersistentCache(repoNotReachable), fileStoreBuilder.getPersistence()); + fileStoreBuilder.withCustomPersistence(customPersistence); + return fileStoreBuilder; + } + + class MemoryPersistentCache extends AbstractPersistentCache { + + private final Map segments = Collections.synchronizedMap(new HashMap()); + + private boolean throwException = false; + + public MemoryPersistentCache(boolean throwException) { + this.throwException = throwException; + segmentCacheStats = new SegmentCacheStats( + "Memory Cache", + () -> null, + () -> null, + () -> null, + () -> null); + } + + @Override + protected Buffer readSegmentInternal(long msb, long lsb) { + return segments.get(String.valueOf(msb) + lsb); + } + + @Override + public boolean containsSegment(long msb, long lsb) { + return segments.containsKey(String.valueOf(msb) + lsb); + } + + @Override + public void writeSegment(long msb, long lsb, Buffer buffer) { + segments.put(String.valueOf(msb) + lsb, buffer); + } + + @Override + public Buffer readSegment(long msb, long lsb, @NotNull Callable loader) throws RepositoryNotReachableException { + return super.readSegment(msb, lsb, () -> { + if (throwException) { + throw new RepositoryNotReachableException(null); + } + return loader.call(); + }); + } + + @Override + public void cleanUp() { + + } + } }