View Javadoc
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  
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(PackFile 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 PackFile pack, final long position,
67  			final byte[] data, final int objectType) {
68  		if (data.length > maxByteCount)
69  			return; // Too large to cache.
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 		PackFile provider;
150 
151 		long position;
152 
153 		int sz;
154 
155 		SoftReference<Entry> data = DEAD;
156 	}
157 }