Index: oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/FileCache.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/FileCache.java (revision d3e86763fdee56edce3ec3cc0c7a785d0ab53c9f) +++ oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/FileCache.java (date 1517397476000) @@ -51,8 +51,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.apache.commons.io.FileUtils.copyInputStreamToFile; import static org.apache.commons.io.FilenameUtils.normalizeNoEndSeparator; +import static org.apache.jackrabbit.oak.commons.FileIOUtils.copyInputStreamToFile; /** */ @@ -137,6 +137,9 @@ is = loader.load(key); copyInputStreamToFile(is, cachedFile); threw = false; + } catch (Exception e) { + LOG.warn("Error reading object for id [{}] from backend", key, e); + throw e; } finally { Closeables.close(is, threw); } Index: oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/AbstractDataStoreCacheTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/AbstractDataStoreCacheTest.java (revision d3e86763fdee56edce3ec3cc0c7a785d0ab53c9f) +++ oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/AbstractDataStoreCacheTest.java (date 1517397476000) @@ -94,7 +94,7 @@ static class TestCacheLoader extends CacheLoader { - private final File root; + protected final File root; public TestCacheLoader(File dir) { this.root = new File(dir, "datastore"); @@ -117,6 +117,43 @@ } } + + /** + * Throws error after reading partially defined by max + */ + private static class ErrorInputStream extends FileInputStream { + private long bytesread; + private long max; + + ErrorInputStream(File file, long max) throws FileNotFoundException { + super(file); + this.max = max; + } + + @Override + public int read(byte b[]) throws IOException { + bytesread += b.length; + if (bytesread > max) { + throw new IOException("Disconnected"); + } + return super.read(b); + } + + } + + static class TestErrorCacheLoader extends TestCacheLoader { + private long max; + + public TestErrorCacheLoader(File dir, long max) { + super(dir); + this.max = max; + } + + @Override public FileInputStream load(@Nonnull String key) throws Exception { + return new ErrorInputStream(getFile(key, root), max); + } + } + static class TestPoolExecutor extends ThreadPoolExecutor { private final CountDownLatch beforeLatch; private final CountDownLatch afterLatch; Index: oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileCacheTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileCacheTest.java (revision d3e86763fdee56edce3ec3cc0c7a785d0ab53c9f) +++ oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileCacheTest.java (date 1517397476000) @@ -38,6 +38,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestName; @@ -58,6 +59,9 @@ private TestCacheLoader loader; private Closer closer; + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + @Rule public TemporaryFolder folder = new TemporaryFolder(new File("target")); @@ -111,6 +115,26 @@ LOG.info("Finished zeroCache"); } + @Test + public void loadError() throws Exception { + LOG.info("Started loadError"); + + loader = new TestErrorCacheLoader(folder.newFolder(), 8192); + cache = FileCache.build(12 * 1024/* KB */, root, loader, null); + closer.register(cache); + File f = createFile(0, loader, cache, folder, 12 * 1024); + File ferr = null; + try { + ferr = cache.get(ID_PREFIX + 0); + } catch (IOException e) { + } + + expectedEx.expect(IOException.class); + cache.get(ID_PREFIX + 0); + + LOG.info("Finished loadError"); + } + /** * Load and get from cache. * @throws Exception @@ -503,9 +527,14 @@ assertTrue(Files.equal(f, cached)); } + private static File createFile(int seed, TestCacheLoader loader, FileCache cache, TemporaryFolder folder) + throws Exception { + return createFile(seed, loader, cache, folder, 4 * 1024); + } + private static File createFile(int seed, TestCacheLoader loader, FileCache cache, - TemporaryFolder folder) throws Exception { - File f = copyToFile(randomStream(0, 4 * 1024), + TemporaryFolder folder, int size) throws Exception { + File f = copyToFile(randomStream(0, size), folder.newFile()); loader.write(ID_PREFIX + seed, f); assertNull(cache.getIfPresent(ID_PREFIX + seed)); Index: oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/FileIOUtils.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/FileIOUtils.java (revision d3e86763fdee56edce3ec3cc0c7a785d0ab53c9f) +++ oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/FileIOUtils.java (date 1517397476000) @@ -52,7 +52,6 @@ import static com.google.common.io.Files.move; import static com.google.common.io.Files.newWriter; import static java.io.File.createTempFile; -import static org.apache.commons.io.FileUtils.copyInputStreamToFile; import static org.apache.commons.io.FileUtils.forceDelete; import static org.apache.commons.io.IOUtils.closeQuietly; import static org.apache.commons.io.IOUtils.copyLarge; @@ -316,6 +315,23 @@ }); } + /** + * + * Copy the input stream to the given file. Delete the file in case of exception. + * + * @param source the input stream source + * @param destination the file to write to + * @throws IOException + */ + public static void copyInputStreamToFile(final InputStream source, final File destination) throws IOException { + try { + FileUtils.copyInputStreamToFile(source, destination); + } catch (Exception e) { + forceDelete(destination); + throw new IOException(e); + } + } + /** * Decorates the given comparator and applies the function before delegating to the decorated * comparator. Index: oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java (revision d3e86763fdee56edce3ec3cc0c7a785d0ab53c9f) +++ oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java (date 1517397552000) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.0.0") +@Version("1.1.0") package org.apache.jackrabbit.oak.commons; -import org.osgi.annotation.versioning.Version; \ No newline at end of file +import org.osgi.annotation.versioning.Version;