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 package org.eclipse.jgit.internal.storage.dfs;
45
46 import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
47
48 import java.io.EOFException;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.nio.ByteBuffer;
52 import java.security.MessageDigest;
53 import java.util.Collections;
54 import java.util.List;
55 import java.util.zip.CRC32;
56 import java.util.zip.Deflater;
57
58 import org.eclipse.jgit.internal.storage.file.PackIndex;
59 import org.eclipse.jgit.internal.storage.file.PackLock;
60 import org.eclipse.jgit.lib.AnyObjectId;
61 import org.eclipse.jgit.lib.Constants;
62 import org.eclipse.jgit.lib.ProgressMonitor;
63 import org.eclipse.jgit.transport.PackParser;
64 import org.eclipse.jgit.transport.PackedObjectInfo;
65
66
67 public class DfsPackParser extends PackParser {
68 private final DfsObjDatabase objdb;
69
70 private final DfsInserter objins;
71
72
73 private final CRC32 crc;
74
75
76 private final MessageDigest packDigest;
77
78
79 private int blockSize;
80
81
82 private long packEnd;
83
84
85 private byte[] packHash;
86
87
88 private Deflater def;
89
90
91 private boolean isEmptyPack;
92
93
94 private DfsPackDescription packDsc;
95
96
97 private DfsPackKey packKey;
98
99
100 private PackIndex packIndex;
101
102
103 private DfsOutputStream out;
104
105
106 private byte[] currBuf;
107 private long currPos;
108 private int currEnd;
109
110
111 private DfsBlockCache blockCache;
112
113
114 private long readPos;
115 private DfsBlock readBlock;
116
117
118
119
120
121
122
123
124
125
126
127 protected DfsPackParser(DfsObjDatabase db, DfsInserter ins, InputStream in) {
128 super(db, in);
129 this.objdb = db;
130 this.objins = ins;
131 this.crc = new CRC32();
132 this.packDigest = Constants.newMessageDigest();
133 }
134
135 @Override
136 public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
137 throws IOException {
138 boolean rollback = true;
139 try {
140 blockCache = DfsBlockCache.getInstance();
141 super.parse(receiving, resolving);
142 if (isEmptyPack)
143 return null;
144 buffer(packHash, 0, packHash.length);
145 if (currEnd != 0)
146 flushBlock();
147 out.close();
148 out = null;
149 currBuf = null;
150 readBlock = null;
151 packDsc.addFileExt(PACK);
152 packDsc.setFileSize(PACK, packEnd);
153
154 writePackIndex();
155 objdb.commitPack(Collections.singletonList(packDsc), null);
156 rollback = false;
157
158 DfsPackFile p = blockCache.getOrCreate(packDsc, packKey);
159 p.setBlockSize(blockSize);
160 if (packIndex != null)
161 p.setPackIndex(packIndex);
162
163 objdb.addPack(p);
164
165 return null;
166 } finally {
167 blockCache = null;
168 currBuf = null;
169 readBlock = null;
170
171 if (def != null) {
172 def.end();
173 def = null;
174 }
175
176 if (out != null) {
177 try {
178 out.close();
179 } catch (IOException err) {
180
181 }
182 out = null;
183 }
184
185 if (rollback && packDsc != null) {
186 try {
187 objdb.rollbackPack(Collections.singletonList(packDsc));
188 } finally {
189 packDsc = null;
190 }
191 }
192 }
193 }
194
195
196 public DfsPackDescription getPackDescription() {
197 return packDsc;
198 }
199
200 @Override
201 protected void onPackHeader(long objectCount) throws IOException {
202 if (objectCount == 0) {
203 isEmptyPack = true;
204 currBuf = new byte[256];
205 return;
206 }
207
208 packDsc = objdb.newPack(DfsObjDatabase.PackSource.RECEIVE);
209 packKey = new DfsPackKey();
210
211 out = objdb.writeFile(packDsc, PACK);
212 int size = out.blockSize();
213 if (size <= 0)
214 size = blockCache.getBlockSize();
215 else if (size < blockCache.getBlockSize())
216 size = (blockCache.getBlockSize() / size) * size;
217 blockSize = size;
218 currBuf = new byte[blockSize];
219 }
220
221 @Override
222 protected void onBeginWholeObject(long streamPosition, int type,
223 long inflatedSize) throws IOException {
224 crc.reset();
225 }
226
227 @Override
228 protected void onEndWholeObject(PackedObjectInfo info) throws IOException {
229 info.setCRC((int) crc.getValue());
230 }
231
232 @Override
233 protected void onBeginOfsDelta(long streamPosition,
234 long baseStreamPosition, long inflatedSize) throws IOException {
235 crc.reset();
236 }
237
238 @Override
239 protected void onBeginRefDelta(long streamPosition, AnyObjectId baseId,
240 long inflatedSize) throws IOException {
241 crc.reset();
242 }
243
244 @Override
245 protected UnresolvedDelta onEndDelta() throws IOException {
246 UnresolvedDelta delta = new UnresolvedDelta();
247 delta.setCRC((int) crc.getValue());
248 return delta;
249 }
250
251 @Override
252 protected void onInflatedObjectData(PackedObjectInfo obj, int typeCode,
253 byte[] data) throws IOException {
254
255 }
256
257 @Override
258 protected void onObjectHeader(Source src, byte[] raw, int pos, int len)
259 throws IOException {
260 crc.update(raw, pos, len);
261 }
262
263 @Override
264 protected void onObjectData(Source src, byte[] raw, int pos, int len)
265 throws IOException {
266 crc.update(raw, pos, len);
267 }
268
269 @Override
270 protected void onStoreStream(byte[] raw, int pos, int len)
271 throws IOException {
272 buffer(raw, pos, len);
273 packDigest.update(raw, pos, len);
274 }
275
276 private void buffer(byte[] raw, int pos, int len) throws IOException {
277 while (0 < len) {
278 int n = Math.min(len, currBuf.length - currEnd);
279 if (n == 0) {
280 DfsBlock v = flushBlock();
281 currBuf = new byte[blockSize];
282 currEnd = 0;
283 currPos += v.size();
284 continue;
285 }
286
287 System.arraycopy(raw, pos, currBuf, currEnd, n);
288 pos += n;
289 len -= n;
290 currEnd += n;
291 packEnd += n;
292 }
293 }
294
295 private DfsBlock flushBlock() throws IOException {
296 if (isEmptyPack)
297 throw new IOException(DfsText.get().willNotStoreEmptyPack);
298
299 out.write(currBuf, 0, currEnd);
300
301 byte[] buf;
302 if (currEnd == currBuf.length) {
303 buf = currBuf;
304 } else {
305 buf = new byte[currEnd];
306 System.arraycopy(currBuf, 0, buf, 0, currEnd);
307 }
308
309 DfsBlock v = new DfsBlock(packKey, currPos, buf);
310 readBlock = v;
311 blockCache.put(v);
312 return v;
313 }
314
315 @Override
316 protected void onPackFooter(byte[] hash) throws IOException {
317
318
319
320
321 packHash = hash;
322 }
323
324 @Override
325 protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
326 ObjectTypeAndSize info) throws IOException {
327 readPos = obj.getOffset();
328 crc.reset();
329 return readObjectHeader(info);
330 }
331
332 @Override
333 protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
334 ObjectTypeAndSize info) throws IOException {
335 readPos = delta.getOffset();
336 crc.reset();
337 return readObjectHeader(info);
338 }
339
340 @Override
341 protected int readDatabase(byte[] dst, int pos, int cnt) throws IOException {
342 if (cnt == 0)
343 return 0;
344
345 if (currPos <= readPos) {
346
347 int p = (int) (readPos - currPos);
348 int n = Math.min(cnt, currEnd - p);
349 if (n == 0)
350 throw new EOFException();
351 System.arraycopy(currBuf, p, dst, pos, n);
352 readPos += n;
353 return n;
354 }
355
356 if (readBlock == null || !readBlock.contains(packKey, readPos)) {
357 long start = toBlockStart(readPos);
358 readBlock = blockCache.get(packKey, start);
359 if (readBlock == null) {
360 int size = (int) Math.min(blockSize, packEnd - start);
361 byte[] buf = new byte[size];
362 if (read(start, buf, 0, size) != size)
363 throw new EOFException();
364 readBlock = new DfsBlock(packKey, start, buf);
365 blockCache.put(readBlock);
366 }
367 }
368
369 int n = readBlock.copy(readPos, dst, pos, cnt);
370 readPos += n;
371 return n;
372 }
373
374 private int read(long pos, byte[] dst, int off, int len) throws IOException {
375 if (len == 0)
376 return 0;
377
378 int cnt = 0;
379 while (0 < len) {
380 int r = out.read(pos, ByteBuffer.wrap(dst, off, len));
381 if (r <= 0)
382 break;
383 pos += r;
384 off += r;
385 len -= r;
386 cnt += r;
387 }
388 return cnt != 0 ? cnt : -1;
389 }
390
391 private long toBlockStart(long pos) {
392 return (pos / blockSize) * blockSize;
393 }
394
395 @Override
396 protected boolean checkCRC(int oldCRC) {
397 return oldCRC == (int) crc.getValue();
398 }
399
400 @Override
401 protected boolean onAppendBase(final int typeCode, final byte[] data,
402 final PackedObjectInfo info) throws IOException {
403 info.setOffset(packEnd);
404
405 final byte[] buf = buffer();
406 int sz = data.length;
407 int len = 0;
408 buf[len++] = (byte) ((typeCode << 4) | sz & 15);
409 sz >>>= 4;
410 while (sz > 0) {
411 buf[len - 1] |= 0x80;
412 buf[len++] = (byte) (sz & 0x7f);
413 sz >>>= 7;
414 }
415
416 packDigest.update(buf, 0, len);
417 crc.reset();
418 crc.update(buf, 0, len);
419 buffer(buf, 0, len);
420
421 if (def == null)
422 def = new Deflater(Deflater.DEFAULT_COMPRESSION, false);
423 else
424 def.reset();
425 def.setInput(data);
426 def.finish();
427
428 while (!def.finished()) {
429 len = def.deflate(buf);
430 packDigest.update(buf, 0, len);
431 crc.update(buf, 0, len);
432 buffer(buf, 0, len);
433 }
434
435 info.setCRC((int) crc.getValue());
436 return true;
437 }
438
439 @Override
440 protected void onEndThinPack() throws IOException {
441
442
443
444
445
446 packHash = packDigest.digest();
447 }
448
449 private void writePackIndex() throws IOException {
450 List<PackedObjectInfo> list = getSortedObjectList(null );
451 packIndex = objins.writePackIndex(packDsc, packHash, list);
452 }
453 }