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 }