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