From 1daa0e2658f73c418f838fe1d85d5511e11b68c5 Mon Sep 17 00:00:00 2001 From: Andrei Dulceanu Date: Tue, 11 Aug 2020 10:02:52 +0000 Subject: [PATCH] OAK-9170 - Make loading segment disk cache fail safe in case when write operation is interrupted by failure Contribution by Miroslav Smiljanic git-svn-id: https://svn.apache.org/repos/asf/jackrabbit/oak/trunk@1880765 13f79535-47bb-0310-9956-ffa450edef68 --- .../persistentcache/PersistentDiskCache.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/oak-segment-remote/src/main/java/org/apache/jackrabbit/oak/segment/remote/persistentcache/PersistentDiskCache.java b/oak-segment-remote/src/main/java/org/apache/jackrabbit/oak/segment/remote/persistentcache/PersistentDiskCache.java index 81c3ed54727..b109588cdd6 100644 --- a/oak-segment-remote/src/main/java/org/apache/jackrabbit/oak/segment/remote/persistentcache/PersistentDiskCache.java +++ b/oak-segment-remote/src/main/java/org/apache/jackrabbit/oak/segment/remote/persistentcache/PersistentDiskCache.java @@ -33,8 +33,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; +import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.util.Comparator; @@ -131,15 +133,28 @@ public boolean containsSegment(long msb, long lsb) { public void writeSegment(long msb, long lsb, Buffer buffer) { String segmentId = new UUID(msb, lsb).toString(); File segmentFile = new File(directory, segmentId); + File tempSegmentFile = new File(directory, segmentId + System.nanoTime() + ".part"); + Buffer bufferCopy = buffer.duplicate(); Runnable task = () -> { if (lockSegmentWrite(segmentId)) { - try (FileChannel channel = new FileOutputStream(segmentFile).getChannel()) { + try (FileChannel channel = new FileOutputStream(tempSegmentFile).getChannel()) { int fileSize = bufferCopy.write(channel); + try { + Files.move(tempSegmentFile.toPath(), segmentFile.toPath(), StandardCopyOption.ATOMIC_MOVE); + } catch (AtomicMoveNotSupportedException e) { + Files.move(tempSegmentFile.toPath(), segmentFile.toPath()); + } cacheSize.addAndGet(fileSize); - } catch (Throwable t) { - logger.error("Error writing segment {} to cache: {}", segmentId, t); + } catch (Exception e) { + logger.error("Error writing segment {} to cache: {}", segmentId, e); + try { + Files.deleteIfExists(segmentFile.toPath()); + Files.deleteIfExists(tempSegmentFile.toPath()); + } catch (IOException i) { + logger.error("Error while deleting corrupted segment file {}", segmentId, i); + } } finally { unlockSegmentWrite(segmentId); }