Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentTracker.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentTracker.java (revision 1698136) +++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentTracker.java (working copy) @@ -23,6 +23,7 @@ import java.security.SecureRandom; import java.util.Queue; import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; @@ -37,6 +38,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.cache.Weigher; + /** * Tracker of references to segment identifiers and segment instances * that are currently kept in memory. @@ -106,6 +109,13 @@ */ private final CacheLIRS segmentCache; + private final static Weigher segmentCacheWeigher = new Weigher() { + @Override + public int weigh(SegmentId key, Segment value) { + return value.size(); + } + }; + public SegmentTracker(SegmentStore store, int cacheSizeMB, SegmentVersion version) { for (int i = 0; i < tables.length; i++) { @@ -128,6 +138,7 @@ .module("SegmentTracker") .maximumSize((int) Math.min(Integer.MAX_VALUE, cacheSizeMB * MB)) .averageWeight(Segment.MAX_SEGMENT_SIZE/2) + .weigher(segmentCacheWeigher) .evictionCallback(new EvictionCallback() { @Override public void evicted(SegmentId segmentId, Segment segment) { @@ -149,7 +160,8 @@ @Nonnull public CacheStats getSegmentCacheStats() { - return new CacheStats(segmentCache, "Segment Cache", null, -1); + return new CacheStats(segmentCache, "Segment Cache", + segmentCacheWeigher, segmentCache.getMaxMemory()); } @CheckForNull @@ -192,25 +204,47 @@ * @return segment with the given {@code id} or {@code null} if not in the cache */ Segment getCachedSegment(SegmentId id) { + return segmentCache.getIfPresent(id); + } + + private Callable loader(final SegmentId id) { + return new Callable() { + @Override + public Segment call() throws Exception { + return loadSegmentFromStore(id); + } + }; + } + + /** + * Read a segment from the segment store. + * @param id segment id + * @return segment with the given id + * @throws SegmentNotFoundException if no segment with the given {@code id} exists. + */ + Segment readSegment(SegmentId id) { try { - return segmentCache.get(id); + // TODO should bulk segments go into the cache? + Segment s = segmentCache.get(id, loader(id)); + id.setSegment(s); + return s; } catch (ExecutionException e) { - log.error("Error reading from segment cache", e); - return null; + if (e.getCause() instanceof SegmentNotFoundException) { + throw (SegmentNotFoundException) e.getCause(); + } + throw new SegmentNotFoundException(id, e.getCause()); } } /** - * Read a segment from the underlying segment store. + * Performs the actual IO operation to read a segment from the underlying store. * @param id segment id * @return segment with the given id * @throws SegmentNotFoundException if no segment with the given {@code id} exists. */ - Segment readSegment(SegmentId id) { + private Segment loadSegmentFromStore(SegmentId id) { try { - Segment segment = store.readSegment(id); - setSegment(id, segment); - return segment; + return store.readSegment(id); } catch (SegmentNotFoundException snfe) { long delta = System.currentTimeMillis() - id.getCreationTime(); log.error("Segment not found: {}. Creation date delta is {} ms.",