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