diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java index ec03146627..d442f86987 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java @@ -204,13 +204,7 @@ public class SegmentBlob extends Record implements Blob { private static String readLongBlobId(Segment segment, int recordNumber) { RecordId blobId = segment.readRecordId(recordNumber, 1); - // if the blob id lives in the same segment, avoid reading again - // the segment, as it will trigger an SNFE on standby, see OAK-8006 - if (blobId.getSegmentId().equals(segment.getSegmentId())) { - return segment.readString(blobId.getRecordNumber()); - } else { - return blobId.getSegment().readString(blobId.getRecordNumber()); - } + return blobId.getSegment().readString(blobId.getRecordNumber()); } private List getBulkRecordIds() { diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java index 3768454a1a..c6d4fdc20c 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java @@ -252,6 +252,7 @@ class SegmentNodeStoreRegistrar { if (cfg.isStandbyInstance()) { builder.withSnfeListener(IGNORE_SNFE); + builder.withEagerSegmentCaching(true); } FileStore store; diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java index 756df4e0fd..c86236f630 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java @@ -132,6 +132,8 @@ public class FileStore extends AbstractFileStore { private final GarbageCollectionStrategy garbageCollectionStrategy = newGarbageCollectionStrategy(); + private final boolean eagerSegmentCaching; + FileStore(final FileStoreBuilder builder) throws InvalidFileStoreVersionException, IOException { super(builder); @@ -197,6 +199,7 @@ public class FileStore extends AbstractFileStore { ); this.snfeListener = builder.getSnfeListener(); + this.eagerSegmentCaching = builder.getEagerSegmentCaching(); TimerStats flushTimer = statsProvider.getTimer("oak.segment.flush", METRICS_ONLY); fileStoreScheduler.scheduleWithFixedDelay(format("TarMK flush [%s]", directory), 5, SECONDS, () -> { @@ -528,6 +531,11 @@ public class FileStore extends AbstractFileStore { } segment = new Segment(tracker, segmentReader, id, data); + + if (eagerSegmentCaching) { + segmentCache.putSegment(segment); + } + generation = segment.getGcGeneration(); references = readReferences(segment); binaryReferences = readBinaryReferences(segment); @@ -544,7 +552,7 @@ public class FileStore extends AbstractFileStore { ); // Keep this data segment in memory as it's likely to be accessed soon. - if (segment != null) { + if (!eagerSegmentCaching && segment != null) { segmentCache.putSegment(segment); } } diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStoreBuilder.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStoreBuilder.java index 1345a87a70..55d10a27cc 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStoreBuilder.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStoreBuilder.java @@ -137,6 +137,8 @@ public class FileStoreBuilder { private boolean strictVersionCheck; + private boolean eagerSegmentCaching; + private boolean built; /** @@ -357,6 +359,19 @@ public class FileStoreBuilder { return this; } + /** + * Enable eager segment caching. This proves useful when segments need to + * be cached as soon as they are created, right before persisting them to disk. + * One such scenario is the cold standby, see OAK-8006. + * + * @param eagerSegmentCaching enables eager segment caching iff {@code true}. + * @return this instance + */ + public FileStoreBuilder withEagerSegmentCaching(boolean eagerSegmentCaching) { + this.eagerSegmentCaching = eagerSegmentCaching; + return this; + } + public Backend buildProcBackend(AbstractFileStore fileStore) throws IOException { return new FileStoreProcBackend(fileStore, persistence); } @@ -525,6 +540,10 @@ public class FileStoreBuilder { return strictVersionCheck; } + boolean getEagerSegmentCaching() { + return eagerSegmentCaching; + } + @Override public String toString() { return "FileStoreBuilder{" + diff --git a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/test/TemporaryFileStore.java b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/test/TemporaryFileStore.java index adef2b20a6..851cccefa8 100644 --- a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/test/TemporaryFileStore.java +++ b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/test/TemporaryFileStore.java @@ -36,7 +36,7 @@ public class TemporaryFileStore extends ExternalResource { private final TemporaryFolder folder; private final TemporaryBlobStore blobStore; - + private final boolean standby; private ScheduledExecutorService executor; @@ -62,7 +62,7 @@ public class TemporaryFileStore extends ExternalResource { .withMaxFileSize(1) .withMemoryMapping(false) .withNodeDeduplicationCacheSize(1) - .withSegmentCacheSize(0) + .withSegmentCacheSize(256) .withStringCacheSize(0) .withTemplateCacheSize(0) .withStatisticsProvider(new DefaultStatisticsProvider(executor)); @@ -71,7 +71,8 @@ public class TemporaryFileStore extends ExternalResource { .setRetainedGenerations(1); builder .withGCOptions(gcOptions) - .withSnfeListener(SegmentNotFoundExceptionListener.IGNORE_SNFE); + .withSnfeListener(SegmentNotFoundExceptionListener.IGNORE_SNFE) + .withEagerSegmentCaching(true); } if (blobStore != null) { builder.withBlobStore(blobStore.blobStore());