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
45 package org.eclipse.jgit.internal.storage.file;
46
47 import java.io.File;
48 import java.io.IOException;
49 import java.util.Collection;
50 import java.util.Set;
51
52 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
53 import org.eclipse.jgit.internal.storage.pack.PackWriter;
54 import org.eclipse.jgit.lib.AbbreviatedObjectId;
55 import org.eclipse.jgit.lib.AnyObjectId;
56 import org.eclipse.jgit.lib.Config;
57 import org.eclipse.jgit.lib.Constants;
58 import org.eclipse.jgit.lib.ObjectDatabase;
59 import org.eclipse.jgit.lib.ObjectId;
60 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
61 import org.eclipse.jgit.lib.ObjectLoader;
62 import org.eclipse.jgit.util.FS;
63
64
65
66
67
68
69
70 class CachedObjectDirectory extends FileObjectDatabase {
71
72
73
74
75 private ObjectIdOwnerMap<UnpackedObjectId> unpackedObjects;
76
77 private final ObjectDirectory wrapped;
78
79 private CachedObjectDirectory[] alts;
80
81
82
83
84
85
86
87 CachedObjectDirectory(ObjectDirectory wrapped) {
88 this.wrapped = wrapped;
89 this.unpackedObjects = scanLoose();
90 }
91
92 private ObjectIdOwnerMap<UnpackedObjectId> scanLoose() {
93 ObjectIdOwnerMap<UnpackedObjectId> m = new ObjectIdOwnerMap<>();
94 File objects = wrapped.getDirectory();
95 String[] fanout = objects.list();
96 if (fanout == null)
97 return m;
98 for (String d : fanout) {
99 if (d.length() != 2)
100 continue;
101 String[] entries = new File(objects, d).list();
102 if (entries == null)
103 continue;
104 for (String e : entries) {
105 if (e.length() != Constants.OBJECT_ID_STRING_LENGTH - 2)
106 continue;
107 try {
108 ObjectId id = ObjectId.fromString(d + e);
109 m.add(new UnpackedObjectId(id));
110 } catch (IllegalArgumentException notAnObject) {
111
112 }
113 }
114 }
115 return m;
116 }
117
118 @Override
119 public void close() {
120
121 }
122
123 @Override
124 public ObjectDatabase newCachedDatabase() {
125 return this;
126 }
127
128 @Override
129 File getDirectory() {
130 return wrapped.getDirectory();
131 }
132
133 @Override
134 File fileFor(AnyObjectId id) {
135 return wrapped.fileFor(id);
136 }
137
138 @Override
139 Config getConfig() {
140 return wrapped.getConfig();
141 }
142
143 @Override
144 FS getFS() {
145 return wrapped.getFS();
146 }
147
148 @Override
149 Set<ObjectId> getShallowCommits() throws IOException {
150 return wrapped.getShallowCommits();
151 }
152
153 private CachedObjectDirectory[] myAlternates() {
154 if (alts == null) {
155 ObjectDirectory.AlternateHandle[] src = wrapped.myAlternates();
156 alts = new CachedObjectDirectory[src.length];
157 for (int i = 0; i < alts.length; i++)
158 alts[i] = src[i].db.newCachedFileObjectDatabase();
159 }
160 return alts;
161 }
162
163 @Override
164 void resolve(Set<ObjectId> matches, AbbreviatedObjectId id)
165 throws IOException {
166
167
168
169
170
171 wrapped.resolve(matches, id);
172 }
173
174 @Override
175 public boolean has(final AnyObjectId objectId) throws IOException {
176 if (unpackedObjects.contains(objectId))
177 return true;
178 if (wrapped.hasPackedObject(objectId))
179 return true;
180 for (CachedObjectDirectory alt : myAlternates()) {
181 if (alt.has(objectId))
182 return true;
183 }
184 return false;
185 }
186
187 @Override
188 ObjectLoader openObject(final WindowCursor curs,
189 final AnyObjectId objectId) throws IOException {
190 ObjectLoader ldr = openLooseObject(curs, objectId);
191 if (ldr != null)
192 return ldr;
193 ldr = wrapped.openPackedObject(curs, objectId);
194 if (ldr != null)
195 return ldr;
196 for (CachedObjectDirectory alt : myAlternates()) {
197 ldr = alt.openObject(curs, objectId);
198 if (ldr != null)
199 return ldr;
200 }
201 return null;
202 }
203
204 @Override
205 long getObjectSize(WindowCursor curs, AnyObjectId objectId)
206 throws IOException {
207
208
209 return wrapped.getObjectSize(curs, objectId);
210 }
211
212 @Override
213 ObjectLoader openLooseObject(WindowCursor curs, AnyObjectId id)
214 throws IOException {
215 if (unpackedObjects.contains(id)) {
216 ObjectLoader ldr = wrapped.openLooseObject(curs, id);
217 if (ldr != null)
218 return ldr;
219 unpackedObjects = scanLoose();
220 }
221 return null;
222 }
223
224 @Override
225 InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId objectId,
226 boolean createDuplicate) throws IOException {
227 InsertLooseObjectResult result = wrapped.insertUnpackedObject(tmp,
228 objectId, createDuplicate);
229 switch (result) {
230 case INSERTED:
231 case EXISTS_LOOSE:
232 unpackedObjects.addIfAbsent(new UnpackedObjectId(objectId));
233 break;
234
235 case EXISTS_PACKED:
236 case FAILURE:
237 break;
238 }
239 return result;
240 }
241
242 @Override
243 PackFile openPack(File pack) throws IOException {
244 return wrapped.openPack(pack);
245 }
246
247 @Override
248 void selectObjectRepresentation(PackWriter packer, ObjectToPack otp,
249 WindowCursor curs) throws IOException {
250 wrapped.selectObjectRepresentation(packer, otp, curs);
251 }
252
253 @Override
254 Collection<PackFile> getPacks() {
255 return wrapped.getPacks();
256 }
257
258 private static class UnpackedObjectId extends ObjectIdOwnerMap.Entry {
259 UnpackedObjectId(AnyObjectId id) {
260 super(id);
261 }
262 }
263 }