Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 372:155c1893bda4
Issue 22: UnsupportedOperationException on empty manifest entry
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 06 Jan 2012 00:42:15 +0300 |
parents | 8107b95f4280 |
children | 6150555eb41d |
comparison
equal
deleted
inserted
replaced
371:aa2e589d4e84 | 372:155c1893bda4 |
---|---|
322 try { | 322 try { |
323 if (!inspector.begin(revisionNumber, new Nodeid(nodeid, true), linkRevision)) { | 323 if (!inspector.begin(revisionNumber, new Nodeid(nodeid, true), linkRevision)) { |
324 iterateControl.stop(); | 324 iterateControl.stop(); |
325 return; | 325 return; |
326 } | 326 } |
327 Path fname = null; | 327 if (!da.isEmpty()) { |
328 Flags flags = null; | 328 // although unlikely, manifest entry may be empty, when all files have been deleted from the repository |
329 Nodeid nid = null; | 329 Path fname = null; |
330 int i; | 330 Flags flags = null; |
331 byte[] data = da.byteArray(); | 331 Nodeid nid = null; |
332 for (i = 0; i < actualLen; i++) { | 332 int i; |
333 int x = i; | 333 byte[] data = da.byteArray(); |
334 for( ; data[i] != '\n' && i < actualLen; i++) { | 334 for (i = 0; i < actualLen; i++) { |
335 if (fname == null && data[i] == 0) { | 335 int x = i; |
336 PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x)); | 336 for( ; data[i] != '\n' && i < actualLen; i++) { |
337 // if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit | 337 if (fname == null && data[i] == 0) { |
338 // cpython 0..10k: hits: 15 989 152, misses: 3020 | 338 PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x)); |
339 fname = px.freeze(); | 339 // if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit |
340 x = i+1; | 340 // cpython 0..10k: hits: 15 989 152, misses: 3020 |
341 fname = px.freeze(); | |
342 x = i+1; | |
343 } | |
341 } | 344 } |
345 if (i < actualLen) { | |
346 assert data[i] == '\n'; | |
347 int nodeidLen = i - x < 40 ? i-x : 40; // if > 40, there are flags | |
348 DigestHelper.ascii2bin(data, x, nodeidLen, nodeidLookupBuffer); // ignore return value as it's unlikely to have NULL in manifest | |
349 nid = new Nodeid(nodeidLookupBuffer, false); // this Nodeid is for pool lookup only, mock object | |
350 Nodeid cached = nodeidPool.unify(nid); | |
351 if (cached == nid) { | |
352 // buffer now belongs to the cached nodeid | |
353 nodeidLookupBuffer = new byte[20]; | |
354 } else { | |
355 nid = cached; // use existing version, discard the lookup object | |
356 } // for cpython 0..10k, cache hits are 15 973 301, vs 18871 misses. | |
357 thisRevPool.record(nid); // memorize revision for the next iteration. | |
358 if (nodeidLen + x < i) { | |
359 // 'x' and 'l' for executable bits and symlinks? | |
360 // hg --debug manifest shows 644 for each regular file in my repo | |
361 // for cpython 0..10k, there are 4361062 flag checks, and there's only 1 unique flag | |
362 flags = Flags.parse(data, x + nodeidLen, i-x-nodeidLen); | |
363 } else { | |
364 flags = null; | |
365 } | |
366 boolean good2go; | |
367 if (inspector2 == null) { | |
368 String flagString = flags == null ? null : flags.nativeString(); | |
369 good2go = inspector.next(nid, fname.toString(), flagString); | |
370 } else { | |
371 good2go = inspector2.next(nid, fname, flags); | |
372 } | |
373 if (!good2go) { | |
374 iterateControl.stop(); | |
375 return; | |
376 } | |
377 } | |
378 nid = null; | |
379 fname = null; | |
380 flags = null; | |
342 } | 381 } |
343 if (i < actualLen) { | |
344 assert data[i] == '\n'; | |
345 int nodeidLen = i - x < 40 ? i-x : 40; // if > 40, there are flags | |
346 DigestHelper.ascii2bin(data, x, nodeidLen, nodeidLookupBuffer); // ignore return value as it's unlikely to have NULL in manifest | |
347 nid = new Nodeid(nodeidLookupBuffer, false); // this Nodeid is for pool lookup only, mock object | |
348 Nodeid cached = nodeidPool.unify(nid); | |
349 if (cached == nid) { | |
350 // buffer now belongs to the cached nodeid | |
351 nodeidLookupBuffer = new byte[20]; | |
352 } else { | |
353 nid = cached; // use existing version, discard the lookup object | |
354 } // for cpython 0..10k, cache hits are 15 973 301, vs 18871 misses. | |
355 thisRevPool.record(nid); // memorize revision for the next iteration. | |
356 if (nodeidLen + x < i) { | |
357 // 'x' and 'l' for executable bits and symlinks? | |
358 // hg --debug manifest shows 644 for each regular file in my repo | |
359 // for cpython 0..10k, there are 4361062 flag checks, and there's only 1 unique flag | |
360 flags = Flags.parse(data, x + nodeidLen, i-x-nodeidLen); | |
361 } else { | |
362 flags = null; | |
363 } | |
364 boolean good2go; | |
365 if (inspector2 == null) { | |
366 String flagString = flags == null ? null : flags.nativeString(); | |
367 good2go = inspector.next(nid, fname.toString(), flagString); | |
368 } else { | |
369 good2go = inspector2.next(nid, fname, flags); | |
370 } | |
371 if (!good2go) { | |
372 iterateControl.stop(); | |
373 return; | |
374 } | |
375 } | |
376 nid = null; | |
377 fname = null; | |
378 flags = null; | |
379 } | 382 } |
380 if (!inspector.end(revisionNumber)) { | 383 if (!inspector.end(revisionNumber)) { |
381 iterateControl.stop(); | 384 iterateControl.stop(); |
382 return; | 385 return; |
383 } | 386 } |