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