Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 571:e4ee4bf4c7d0
Let session context control creation of Path instances
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> | 
|---|---|
| date | Thu, 11 Apr 2013 16:27:06 +0200 | 
| parents | c1478cc31f45 | 
| children | 88afffd39899 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 570:36853bb80a35 | 571:e4ee4bf4c7d0 | 
|---|---|
| 192 // there are tool-constructed repositories that got order of changeset revisions completely different from that of manifest | 192 // there are tool-constructed repositories that got order of changeset revisions completely different from that of manifest | 
| 193 int x = manifestLast; | 193 int x = manifestLast; | 
| 194 manifestLast = manifestFirst; | 194 manifestLast = manifestFirst; | 
| 195 manifestFirst = x; | 195 manifestFirst = x; | 
| 196 } | 196 } | 
| 197 content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector, encodingHelper)); | 197 content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector)); | 
| 198 } | 198 } | 
| 199 | 199 | 
| 200 /** | 200 /** | 
| 201 * "Sparse" iteration of the manifest, more effective than accessing revisions one by one. | 201 * "Sparse" iteration of the manifest, more effective than accessing revisions one by one. | 
| 202 * <p> Inspector is invoked for each changeset revision supplied, even when there's no manifest | 202 * <p> Inspector is invoked for each changeset revision supplied, even when there's no manifest | 
| 212 public void walk(final Inspector inspector, int... revisionIndexes) throws HgRuntimeException, IllegalArgumentException { | 212 public void walk(final Inspector inspector, int... revisionIndexes) throws HgRuntimeException, IllegalArgumentException { | 
| 213 if (inspector == null || revisionIndexes == null) { | 213 if (inspector == null || revisionIndexes == null) { | 
| 214 throw new IllegalArgumentException(); | 214 throw new IllegalArgumentException(); | 
| 215 } | 215 } | 
| 216 int[] manifestRevs = toManifestRevisionIndexes(revisionIndexes, inspector); | 216 int[] manifestRevs = toManifestRevisionIndexes(revisionIndexes, inspector); | 
| 217 content.iterate(manifestRevs, true, new ManifestParser(inspector, encodingHelper)); | 217 content.iterate(manifestRevs, true, new ManifestParser(inspector)); | 
| 218 } | 218 } | 
| 219 | 219 | 
| 220 // | 220 // | 
| 221 /** | 221 /** | 
| 222 * Tells manifest revision number that corresponds to the given changeset. May return {@link HgRepository#BAD_REVISION} | 222 * Tells manifest revision number that corresponds to the given changeset. May return {@link HgRepository#BAD_REVISION} | 
| 397 * | 397 * | 
| 398 * When String (Path) is wrapped into {@link PathProxy}, there's extra overhead of byte[] representation | 398 * When String (Path) is wrapped into {@link PathProxy}, there's extra overhead of byte[] representation | 
| 399 * of the String, but these are only for unique Strings (Paths) (3020 in the example above). Besides, I save | 399 * of the String, but these are only for unique Strings (Paths) (3020 in the example above). Besides, I save | 
| 400 * useless char[] and byte->char conversions. | 400 * useless char[] and byte->char conversions. | 
| 401 */ | 401 */ | 
| 402 private static class PathProxy { | 402 private final class PathProxy { | 
| 403 private byte[] data; | 403 private byte[] data; | 
| 404 private int start; | 404 private int start; | 
| 405 private final int hash, length; | 405 private final int hash, length; | 
| 406 private Path result; | 406 private Path result; | 
| 407 private final EncodingHelper encHelper; | 407 | 
| 408 | 408 public PathProxy(byte[] data, int start, int length) { | 
| 409 public PathProxy(byte[] data, int start, int length, EncodingHelper eh) { | |
| 410 this.data = data; | 409 this.data = data; | 
| 411 this.start = start; | 410 this.start = start; | 
| 412 this.length = length; | 411 this.length = length; | 
| 413 this.encHelper = eh; | |
| 414 | 412 | 
| 415 // copy from String.hashCode(). In fact, not necessarily match result of String(data).hashCode | 413 // copy from String.hashCode(). In fact, not necessarily match result of String(data).hashCode | 
| 416 // just need some nice algorithm here | 414 // just need some nice algorithm here | 
| 417 int h = 0; | 415 int h = 0; | 
| 418 byte[] d = data; | 416 byte[] d = data; | 
| 446 return hash; | 444 return hash; | 
| 447 } | 445 } | 
| 448 | 446 | 
| 449 public Path freeze() { | 447 public Path freeze() { | 
| 450 if (result == null) { | 448 if (result == null) { | 
| 451 result = Path.create(encHelper.fromManifest(data, start, length)); | 449 Path.Source pathFactory = HgManifest.this.getRepo().getSessionContext().getPathFactory(); | 
| 450 result = pathFactory.path(HgManifest.this.encodingHelper.fromManifest(data, start, length)); | |
| 452 // release reference to bigger data array, make a copy of relevant part only | 451 // release reference to bigger data array, make a copy of relevant part only | 
| 453 // use original bytes, not those from String above to avoid cache misses due to different encodings | 452 // use original bytes, not those from String above to avoid cache misses due to different encodings | 
| 454 byte[] d = new byte[length]; | 453 byte[] d = new byte[length]; | 
| 455 System.arraycopy(data, start, d, 0, length); | 454 System.arraycopy(data, start, d, 0, length); | 
| 456 data = d; | 455 data = d; | 
| 458 } | 457 } | 
| 459 return result; | 458 return result; | 
| 460 } | 459 } | 
| 461 } | 460 } | 
| 462 | 461 | 
| 463 private static class ManifestParser implements RevlogStream.Inspector, Lifecycle { | 462 private class ManifestParser implements RevlogStream.Inspector, Lifecycle { | 
| 464 private final Inspector inspector; | 463 private final Inspector inspector; | 
| 465 private IdentityPool<Nodeid> nodeidPool, thisRevPool; | 464 private IdentityPool<Nodeid> nodeidPool, thisRevPool; | 
| 466 private final IdentityPool<PathProxy> fnamePool; | 465 private final IdentityPool<PathProxy> fnamePool; | 
| 467 private byte[] nodeidLookupBuffer = new byte[20]; // get reassigned each time new Nodeid is added to pool | 466 private byte[] nodeidLookupBuffer = new byte[20]; // get reassigned each time new Nodeid is added to pool | 
| 468 private final ProgressSupport progressHelper; | 467 private final ProgressSupport progressHelper; | 
| 469 private IterateControlMediator iterateControl; | 468 private IterateControlMediator iterateControl; | 
| 470 private final EncodingHelper encHelper; | 469 | 
| 471 | 470 public ManifestParser(Inspector delegate) { | 
| 472 public ManifestParser(Inspector delegate, EncodingHelper eh) { | |
| 473 assert delegate != null; | 471 assert delegate != null; | 
| 474 inspector = delegate; | 472 inspector = delegate; | 
| 475 encHelper = eh; | |
| 476 nodeidPool = new IdentityPool<Nodeid>(); | 473 nodeidPool = new IdentityPool<Nodeid>(); | 
| 477 fnamePool = new IdentityPool<PathProxy>(); | 474 fnamePool = new IdentityPool<PathProxy>(); | 
| 478 thisRevPool = new IdentityPool<Nodeid>(); | 475 thisRevPool = new IdentityPool<Nodeid>(); | 
| 479 progressHelper = ProgressSupport.Factory.get(delegate); | 476 progressHelper = ProgressSupport.Factory.get(delegate); | 
| 480 } | 477 } | 
| 494 byte[] data = da.byteArray(); | 491 byte[] data = da.byteArray(); | 
| 495 for (i = 0; i < actualLen; i++) { | 492 for (i = 0; i < actualLen; i++) { | 
| 496 int x = i; | 493 int x = i; | 
| 497 for( ; data[i] != '\n' && i < actualLen; i++) { | 494 for( ; data[i] != '\n' && i < actualLen; i++) { | 
| 498 if (fname == null && data[i] == 0) { | 495 if (fname == null && data[i] == 0) { | 
| 499 PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x, encHelper)); | 496 PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x)); | 
| 500 // if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit | 497 // if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit | 
| 501 // cpython 0..10k: hits: 15 989 152, misses: 3020 | 498 // cpython 0..10k: hits: 15 989 152, misses: 3020 | 
| 502 fname = px.freeze(); | 499 fname = px.freeze(); | 
| 503 x = i+1; | 500 x = i+1; | 
| 504 } | 501 } | 
