Fix the UnpackedObjectCache hash function to prevent overflow
[egit.git] / org.spearce.jgit / src / org / spearce / jgit / lib / UnpackedObjectCache.java
blobee6a680e4d155c40deeaf0ac7e691c816321f0f0
1 /*
2 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org.spearce.jgit.lib;
40 import java.lang.ref.SoftReference;
42 class UnpackedObjectCache {
43 private static final int CACHE_SZ = 256;
45 private static final int MB = 1024 * 1024;
47 private static final SoftReference<Entry> DEAD;
49 private static int hash(final WindowedFile pack, final long position) {
50 int h = pack.hash + (int) position;
51 h += h >>> 16;
52 h += h >>> 8;
53 return h & (CACHE_SZ - 1);
56 private static int maxByteCount;
58 private static final Slot[] cache;
60 private static Slot lruHead;
62 private static Slot lruTail;
64 private static int openByteCount;
66 static {
67 DEAD = new SoftReference<Entry>(null);
68 maxByteCount = 10 * MB;
70 cache = new Slot[CACHE_SZ];
71 for (int i = 0; i < CACHE_SZ; i++)
72 cache[i] = new Slot();
75 static synchronized void reconfigure(final int dbLimit) {
76 if (maxByteCount != dbLimit) {
77 maxByteCount = dbLimit;
78 releaseMemory();
82 static synchronized Entry get(final WindowedFile pack, final long position) {
83 final Slot e = cache[hash(pack, position)];
84 if (e.provider == pack && e.position == position) {
85 final Entry buf = e.data.get();
86 if (buf != null) {
87 moveToHead(e);
88 return buf;
91 return null;
94 static synchronized void store(final WindowedFile pack,
95 final long position, final byte[] data, final int objectType) {
96 if (data.length > maxByteCount)
97 return; // Too large to cache.
99 final Slot e = cache[hash(pack, position)];
100 clearEntry(e);
102 openByteCount += data.length;
103 releaseMemory();
105 e.provider = pack;
106 e.position = position;
107 e.data = new SoftReference<Entry>(new Entry(data, objectType));
108 moveToHead(e);
111 private static void releaseMemory() {
112 while (openByteCount > maxByteCount && lruTail != null) {
113 final Slot currOldest = lruTail;
114 final Slot nextOldest = currOldest.lruPrev;
116 clearEntry(currOldest);
117 currOldest.lruPrev = null;
118 currOldest.lruNext = null;
120 if (nextOldest == null)
121 lruHead = null;
122 else
123 nextOldest.lruNext = null;
124 lruTail = nextOldest;
128 static synchronized void purge(final WindowedFile file) {
129 for (final Slot e : cache) {
130 if (e.provider == file) {
131 clearEntry(e);
132 unlink(e);
137 private static void moveToHead(final Slot e) {
138 unlink(e);
139 e.lruPrev = null;
140 e.lruNext = lruHead;
141 if (lruHead != null)
142 lruHead.lruPrev = e;
143 else
144 lruTail = e;
145 lruHead = e;
148 private static void unlink(final Slot e) {
149 final Slot prev = e.lruPrev;
150 final Slot next = e.lruNext;
151 if (prev != null)
152 prev.lruNext = next;
153 if (next != null)
154 next.lruPrev = prev;
157 private static void clearEntry(final Slot e) {
158 final Entry old = e.data.get();
159 if (old != null)
160 openByteCount -= old.data.length;
161 e.provider = null;
162 e.data = DEAD;
165 private UnpackedObjectCache() {
166 throw new UnsupportedOperationException();
169 static class Entry {
170 final byte[] data;
172 final int type;
174 Entry(final byte[] aData, final int aType) {
175 data = aData;
176 type = aType;
180 private static class Slot {
181 Slot lruPrev;
183 Slot lruNext;
185 WindowedFile provider;
187 long position;
189 SoftReference<Entry> data = DEAD;