DeltaBaseCache.java

  1. /*
  2.  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */

  10. package org.eclipse.jgit.internal.storage.file;

  11. import java.lang.ref.SoftReference;

  12. import org.eclipse.jgit.storage.file.WindowCacheConfig;

  13. class DeltaBaseCache {
  14.     private static final int CACHE_SZ = 1024;

  15.     static final SoftReference<Entry> DEAD;

  16.     private static int hash(long position) {
  17.         return (((int) position) << 22) >>> 22;
  18.     }

  19.     private static volatile int defaultMaxByteCount;

  20.     private final int maxByteCount;

  21.     private final Slot[] cache;

  22.     private Slot lruHead;

  23.     private Slot lruTail;

  24.     private int openByteCount;

  25.     static {
  26.         DEAD = new SoftReference<>(null);
  27.         reconfigure(new WindowCacheConfig());
  28.     }

  29.     static void reconfigure(WindowCacheConfig cfg) {
  30.         defaultMaxByteCount = cfg.getDeltaBaseCacheLimit();
  31.     }

  32.     DeltaBaseCache() {
  33.         maxByteCount = defaultMaxByteCount;
  34.         cache = new Slot[CACHE_SZ];
  35.     }

  36.     Entry get(Pack pack, long position) {
  37.         Slot e = cache[hash(position)];
  38.         if (e == null)
  39.             return null;
  40.         if (e.provider == pack && e.position == position) {
  41.             final Entry buf = e.data.get();
  42.             if (buf != null) {
  43.                 moveToHead(e);
  44.                 return buf;
  45.             }
  46.         }
  47.         return null;
  48.     }

  49.     void store(final Pack pack, final long position,
  50.             final byte[] data, final int objectType) {
  51.         if (data.length > maxByteCount)
  52.             return; // Too large to cache.

  53.         Slot e = cache[hash(position)];
  54.         if (e == null) {
  55.             e = new Slot();
  56.             cache[hash(position)] = e;
  57.         } else {
  58.             clearEntry(e);
  59.         }

  60.         openByteCount += data.length;
  61.         releaseMemory();

  62.         e.provider = pack;
  63.         e.position = position;
  64.         e.sz = data.length;
  65.         e.data = new SoftReference<>(new Entry(data, objectType));
  66.         moveToHead(e);
  67.     }

  68.     private void releaseMemory() {
  69.         while (openByteCount > maxByteCount && lruTail != null) {
  70.             final Slot currOldest = lruTail;
  71.             final Slot nextOldest = currOldest.lruPrev;

  72.             clearEntry(currOldest);
  73.             currOldest.lruPrev = null;
  74.             currOldest.lruNext = null;

  75.             if (nextOldest == null)
  76.                 lruHead = null;
  77.             else
  78.                 nextOldest.lruNext = null;
  79.             lruTail = nextOldest;
  80.         }
  81.     }

  82.     private void moveToHead(Slot e) {
  83.         unlink(e);
  84.         e.lruPrev = null;
  85.         e.lruNext = lruHead;
  86.         if (lruHead != null)
  87.             lruHead.lruPrev = e;
  88.         else
  89.             lruTail = e;
  90.         lruHead = e;
  91.     }

  92.     private void unlink(Slot e) {
  93.         final Slot prev = e.lruPrev;
  94.         final Slot next = e.lruNext;
  95.         if (prev != null)
  96.             prev.lruNext = next;
  97.         if (next != null)
  98.             next.lruPrev = prev;
  99.     }

  100.     private void clearEntry(Slot e) {
  101.         openByteCount -= e.sz;
  102.         e.provider = null;
  103.         e.data = DEAD;
  104.         e.sz = 0;
  105.     }

  106.     static class Entry {
  107.         final byte[] data;

  108.         final int type;

  109.         Entry(byte[] aData, int aType) {
  110.             data = aData;
  111.             type = aType;
  112.         }
  113.     }

  114.     private static class Slot {
  115.         Slot lruPrev;

  116.         Slot lruNext;

  117.         Pack provider;

  118.         long position;

  119.         int sz;

  120.         SoftReference<Entry> data = DEAD;
  121.     }
  122. }