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