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.IOException;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.HashSet;
51 import java.util.List;
52 import java.util.Set;
53 import java.util.zip.DataFormatException;
54 import java.util.zip.Inflater;
55
56 import org.eclipse.jgit.annotations.Nullable;
57 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
58 import org.eclipse.jgit.errors.MissingObjectException;
59 import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
60 import org.eclipse.jgit.internal.JGitText;
61 import org.eclipse.jgit.internal.storage.pack.CachedPack;
62 import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
63 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
64 import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
65 import org.eclipse.jgit.internal.storage.pack.PackWriter;
66 import org.eclipse.jgit.lib.AbbreviatedObjectId;
67 import org.eclipse.jgit.lib.AnyObjectId;
68 import org.eclipse.jgit.lib.BitmapIndex;
69 import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
70 import org.eclipse.jgit.lib.Constants;
71 import org.eclipse.jgit.lib.InflaterCache;
72 import org.eclipse.jgit.lib.ObjectId;
73 import org.eclipse.jgit.lib.ObjectInserter;
74 import org.eclipse.jgit.lib.ObjectLoader;
75 import org.eclipse.jgit.lib.ObjectReader;
76 import org.eclipse.jgit.lib.ProgressMonitor;
77
78
79 final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
80
81 final byte[] tempId = new byte[Constants.OBJECT_ID_LENGTH];
82
83 private Inflater inf;
84
85 private ByteWindow window;
86
87 private DeltaBaseCache baseCache;
88
89 @Nullable
90 private final ObjectInserter createdFromInserter;
91
92 final FileObjectDatabase db;
93
94 WindowCursor(FileObjectDatabase db) {
95 this.db = db;
96 this.createdFromInserter = null;
97 this.streamFileThreshold = WindowCache.getStreamFileThreshold();
98 }
99
100 WindowCursor(FileObjectDatabase db,
101 @Nullable ObjectDirectoryInserter createdFromInserter) {
102 this.db = db;
103 this.createdFromInserter = createdFromInserter;
104 this.streamFileThreshold = WindowCache.getStreamFileThreshold();
105 }
106
107 DeltaBaseCache getDeltaBaseCache() {
108 if (baseCache == null)
109 baseCache = new DeltaBaseCache();
110 return baseCache;
111 }
112
113 @Override
114 public ObjectReader newReader() {
115 return new WindowCursor(db);
116 }
117
118 @Override
119 public BitmapIndex getBitmapIndex() throws IOException {
120 for (PackFile pack : db.getPacks()) {
121 PackBitmapIndex index = pack.getBitmapIndex();
122 if (index != null)
123 return new BitmapIndexImpl(index);
124 }
125 return null;
126 }
127
128 @Override
129 public Collection<CachedPack> getCachedPacksAndUpdate(
130 BitmapBuilder needBitmap) throws IOException {
131 for (PackFile pack : db.getPacks()) {
132 PackBitmapIndex index = pack.getBitmapIndex();
133 if (needBitmap.removeAllOrNone(index))
134 return Collections.<CachedPack> singletonList(
135 new LocalCachedPack(Collections.singletonList(pack)));
136 }
137 return Collections.emptyList();
138 }
139
140 @Override
141 public Collection<ObjectId> resolve(AbbreviatedObjectId id)
142 throws IOException {
143 if (id.isComplete())
144 return Collections.singleton(id.toObjectId());
145 HashSet<ObjectId> matches = new HashSet<>(4);
146 db.resolve(matches, id);
147 return matches;
148 }
149
150 @Override
151 public boolean has(AnyObjectId objectId) throws IOException {
152 return db.has(objectId);
153 }
154
155 @Override
156 public ObjectLoader open(AnyObjectId objectId, int typeHint)
157 throws MissingObjectException, IncorrectObjectTypeException,
158 IOException {
159 final ObjectLoader ldr = db.openObject(this, objectId);
160 if (ldr == null) {
161 if (typeHint == OBJ_ANY)
162 throw new MissingObjectException(objectId.copy(),
163 JGitText.get().unknownObjectType2);
164 throw new MissingObjectException(objectId.copy(), typeHint);
165 }
166 if (typeHint != OBJ_ANY && ldr.getType() != typeHint)
167 throw new IncorrectObjectTypeException(objectId.copy(), typeHint);
168 return ldr;
169 }
170
171 @Override
172 public Set<ObjectId> getShallowCommits() throws IOException {
173 return db.getShallowCommits();
174 }
175
176 @Override
177 public long getObjectSize(AnyObjectId objectId, int typeHint)
178 throws MissingObjectException, IncorrectObjectTypeException,
179 IOException {
180 long sz = db.getObjectSize(this, objectId);
181 if (sz < 0) {
182 if (typeHint == OBJ_ANY)
183 throw new MissingObjectException(objectId.copy(),
184 JGitText.get().unknownObjectType2);
185 throw new MissingObjectException(objectId.copy(), typeHint);
186 }
187 return sz;
188 }
189
190 @Override
191 public LocalObjectToPack newObjectToPack(AnyObjectId objectId, int type) {
192 return new LocalObjectToPack(objectId, type);
193 }
194
195 @Override
196 public void selectObjectRepresentation(PackWriter packer,
197 ProgressMonitor monitor, Iterable<ObjectToPack> objects)
198 throws IOException, MissingObjectException {
199 for (ObjectToPack otp : objects) {
200 db.selectObjectRepresentation(packer, otp, this);
201 monitor.update(1);
202 }
203 }
204
205 @Override
206 public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
207 boolean validate) throws IOException,
208 StoredObjectRepresentationNotAvailableException {
209 LocalObjectToPack src = (LocalObjectToPack) otp;
210 src.pack.copyAsIs(out, src, validate, this);
211 }
212
213 @Override
214 public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
215 throws IOException {
216 for (ObjectToPack otp : list)
217 out.writeObject(otp);
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 int copy(final PackFile pack, long position, final byte[] dstbuf,
243 int dstoff, final int cnt) throws IOException {
244 final long length = pack.length;
245 int need = cnt;
246 while (need > 0 && position < length) {
247 pin(pack, position);
248 final int r = window.copy(position, dstbuf, dstoff, need);
249 position += r;
250 dstoff += r;
251 need -= r;
252 }
253 return cnt - need;
254 }
255
256 @Override
257 public void copyPackAsIs(PackOutputStream out, CachedPack pack)
258 throws IOException {
259 ((LocalCachedPack) pack).copyAsIs(out, this);
260 }
261
262 void copyPackAsIs(final PackFile pack, final long length,
263 final PackOutputStream out) throws IOException {
264 long position = 12;
265 long remaining = length - (12 + 20);
266 while (0 < remaining) {
267 pin(pack, position);
268
269 int ptr = (int) (position - window.start);
270 int n = (int) Math.min(window.size() - ptr, remaining);
271 window.write(out, position, n);
272 position += n;
273 remaining -= n;
274 }
275 }
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298 int inflate(final PackFile pack, long position, final byte[] dstbuf,
299 boolean headerOnly) throws IOException, DataFormatException {
300 prepareInflater();
301 pin(pack, position);
302 position += window.setInput(position, inf);
303 for (int dstoff = 0;;) {
304 int n = inf.inflate(dstbuf, dstoff, dstbuf.length - dstoff);
305 dstoff += n;
306 if (inf.finished() || (headerOnly && dstoff == dstbuf.length))
307 return dstoff;
308 if (inf.needsInput()) {
309 pin(pack, position);
310 position += window.setInput(position, inf);
311 } else if (n == 0)
312 throw new DataFormatException();
313 }
314 }
315
316 ByteArrayWindow quickCopy(PackFile p, long pos, long cnt)
317 throws IOException {
318 pin(p, pos);
319 if (window instanceof ByteArrayWindow
320 && window.contains(p, pos + (cnt - 1)))
321 return (ByteArrayWindow) window;
322 return null;
323 }
324
325 Inflater inflater() {
326 prepareInflater();
327 return inf;
328 }
329
330 private void prepareInflater() {
331 if (inf == null)
332 inf = InflaterCache.get();
333 else
334 inf.reset();
335 }
336
337 void pin(final PackFile pack, final long position)
338 throws IOException {
339 final ByteWindow w = window;
340 if (w == null || !w.contains(pack, position)) {
341
342
343
344
345
346 window = null;
347 window = WindowCache.get(pack, position);
348 }
349 }
350
351 @Override
352 @Nullable
353 public ObjectInserter getCreatedFromInserter() {
354 return createdFromInserter;
355 }
356
357
358 @Override
359 public void close() {
360 window = null;
361 baseCache = null;
362 try {
363 InflaterCache.release(inf);
364 } finally {
365 inf = null;
366 }
367 }
368 }