1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.file;
12
13 import java.lang.ref.SoftReference;
14
15 import org.eclipse.jgit.storage.file.WindowCacheConfig;
16
17 class DeltaBaseCache {
18 private static final int CACHE_SZ = 1024;
19
20 static final SoftReference<Entry> DEAD;
21
22 private static int hash(long position) {
23 return (((int) position) << 22) >>> 22;
24 }
25
26 private static volatile int defaultMaxByteCount;
27
28 private final int maxByteCount;
29
30 private final Slot[] cache;
31
32 private Slot lruHead;
33
34 private Slot lruTail;
35
36 private int openByteCount;
37
38 static {
39 DEAD = new SoftReference<>(null);
40 reconfigure(new WindowCacheConfig());
41 }
42
43 static void reconfigure(WindowCacheConfig cfg) {
44 defaultMaxByteCount = cfg.getDeltaBaseCacheLimit();
45 }
46
47 DeltaBaseCache() {
48 maxByteCount = defaultMaxByteCount;
49 cache = new Slot[CACHE_SZ];
50 }
51
52 Entry get(Pack pack, long position) {
53 Slot e = cache[hash(position)];
54 if (e == null)
55 return null;
56 if (e.provider == pack && e.position == position) {
57 final Entry buf = e.data.get();
58 if (buf != null) {
59 moveToHead(e);
60 return buf;
61 }
62 }
63 return null;
64 }
65
66 void store(final Pack pack, final long position,
67 final byte[] data, final int objectType) {
68 if (data.length > maxByteCount)
69 return;
70
71 Slot e = cache[hash(position)];
72 if (e == null) {
73 e = new Slot();
74 cache[hash(position)] = e;
75 } else {
76 clearEntry(e);
77 }
78
79 openByteCount += data.length;
80 releaseMemory();
81
82 e.provider = pack;
83 e.position = position;
84 e.sz = data.length;
85 e.data = new SoftReference<>(new Entry(data, objectType));
86 moveToHead(e);
87 }
88
89 private void releaseMemory() {
90 while (openByteCount > maxByteCount && lruTail != null) {
91 final Slot currOldest = lruTail;
92 final Slot nextOldest = currOldest.lruPrev;
93
94 clearEntry(currOldest);
95 currOldest.lruPrev = null;
96 currOldest.lruNext = null;
97
98 if (nextOldest == null)
99 lruHead = null;
100 else
101 nextOldest.lruNext = null;
102 lruTail = nextOldest;
103 }
104 }
105
106 private void moveToHead(Slot e) {
107 unlink(e);
108 e.lruPrev = null;
109 e.lruNext = lruHead;
110 if (lruHead != null)
111 lruHead.lruPrev = e;
112 else
113 lruTail = e;
114 lruHead = e;
115 }
116
117 private void unlink(Slot e) {
118 final Slot prev = e.lruPrev;
119 final Slot next = e.lruNext;
120 if (prev != null)
121 prev.lruNext = next;
122 if (next != null)
123 next.lruPrev = prev;
124 }
125
126 private void clearEntry(Slot e) {
127 openByteCount -= e.sz;
128 e.provider = null;
129 e.data = DEAD;
130 e.sz = 0;
131 }
132
133 static class Entry {
134 final byte[] data;
135
136 final int type;
137
138 Entry(byte[] aData, int aType) {
139 data = aData;
140 type = aType;
141 }
142 }
143
144 private static class Slot {
145 Slot lruPrev;
146
147 Slot lruNext;
148
149 Pack provider;
150
151 long position;
152
153 int sz;
154
155 SoftReference<Entry> data = DEAD;
156 }
157 }