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 } |
