Always use a single WindowCache for the entire JVM
[egit/zawir.git] / org.spearce.jgit / src / org / spearce / jgit / lib / UnpackedObjectCache.java
blob2d9559401ddfc1588bfb75417606399063b47d4e
1 /*
2 * Copyright (C) 2008 Shawn Pearce <spearce@spearce.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License, version 2, as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
17 package org.spearce.jgit.lib;
19 import java.lang.ref.SoftReference;
21 class UnpackedObjectCache {
22 private static final int CACHE_SZ = 256;
24 private static final int MB = 1024 * 1024;
26 private static final SoftReference<Entry> DEAD;
28 private static int hash(final WindowedFile pack, final long position) {
29 int h = pack.hash + (int) position;
30 h += h >> 16;
31 h += h >> 8;
32 return h % CACHE_SZ;
35 private static int maxByteCount;
37 private static final Slot[] cache;
39 private static Slot lruHead;
41 private static Slot lruTail;
43 private static int openByteCount;
45 static {
46 DEAD = new SoftReference<Entry>(null);
47 maxByteCount = 10 * MB;
49 cache = new Slot[CACHE_SZ];
50 for (int i = 0; i < CACHE_SZ; i++)
51 cache[i] = new Slot();
54 static synchronized void reconfigure(final int dbLimit) {
55 if (maxByteCount != dbLimit) {
56 maxByteCount = dbLimit;
57 releaseMemory();
61 static synchronized Entry get(final WindowedFile pack, final long position) {
62 final Slot e = cache[hash(pack, position)];
63 if (e.provider == pack && e.position == position) {
64 final Entry buf = e.data.get();
65 if (buf != null) {
66 moveToHead(e);
67 return buf;
70 return null;
73 static synchronized void store(final WindowedFile pack,
74 final long position, final byte[] data, final int objectType) {
75 if (data.length > maxByteCount)
76 return; // Too large to cache.
78 final Slot e = cache[hash(pack, position)];
79 clearEntry(e);
81 openByteCount += data.length;
82 releaseMemory();
84 e.provider = pack;
85 e.position = position;
86 e.data = new SoftReference<Entry>(new Entry(data, objectType));
87 moveToHead(e);
90 private static void releaseMemory() {
91 while (openByteCount > maxByteCount && lruTail != null) {
92 final Slot currOldest = lruTail;
93 final Slot nextOldest = currOldest.lruPrev;
95 clearEntry(currOldest);
96 currOldest.lruPrev = null;
97 currOldest.lruNext = null;
99 if (nextOldest == null)
100 lruHead = null;
101 else
102 nextOldest.lruNext = null;
103 lruTail = nextOldest;
107 static synchronized void purge(final WindowedFile file) {
108 for (final Slot e : cache) {
109 if (e.provider == file) {
110 clearEntry(e);
111 unlink(e);
116 private static void moveToHead(final Slot e) {
117 unlink(e);
118 e.lruPrev = null;
119 e.lruNext = lruHead;
120 if (lruHead != null)
121 lruHead.lruPrev = e;
122 else
123 lruTail = e;
124 lruHead = e;
127 private static void unlink(final Slot e) {
128 final Slot prev = e.lruPrev;
129 final Slot next = e.lruNext;
130 if (prev != null)
131 prev.lruNext = next;
132 if (next != null)
133 next.lruPrev = prev;
136 private static void clearEntry(final Slot e) {
137 final Entry old = e.data.get();
138 if (old != null)
139 openByteCount -= old.data.length;
140 e.provider = null;
141 e.data = DEAD;
144 private UnpackedObjectCache() {
145 throw new UnsupportedOperationException();
148 static class Entry {
149 final byte[] data;
151 final int type;
153 Entry(final byte[] aData, final int aType) {
154 data = aData;
155 type = aType;
159 private static class Slot {
160 Slot lruPrev;
162 Slot lruNext;
164 WindowedFile provider;
166 long position;
168 SoftReference<Entry> data = DEAD;