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