Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 412:63c5a9d7ca3f smartgit3
Follow-up for Issue 29: unify path translation for manifest and dirstate
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> | 
|---|---|
| date | Wed, 21 Mar 2012 14:54:02 +0100 | 
| parents | 6952d9ce97f1 | 
| children | bb278ccf9866 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 411:464b4404e75d | 412:63c5a9d7ca3f | 
|---|---|
| 49 * @author Artem Tikhomirov | 49 * @author Artem Tikhomirov | 
| 50 * @author TMate Software Ltd. | 50 * @author TMate Software Ltd. | 
| 51 */ | 51 */ | 
| 52 public class HgManifest extends Revlog { | 52 public class HgManifest extends Revlog { | 
| 53 private RevisionMapper revisionMap; | 53 private RevisionMapper revisionMap; | 
| 54 private EncodingHelper encodingHelper; | |
| 54 | 55 | 
| 55 public enum Flags { | 56 public enum Flags { | 
| 56 Exec, Link; | 57 Exec, Link; | 
| 57 | 58 | 
| 58 static Flags parse(String flags) { | 59 static Flags parse(String flags) { | 
| 93 } | 94 } | 
| 94 throw new IllegalStateException(toString()); | 95 throw new IllegalStateException(toString()); | 
| 95 } | 96 } | 
| 96 } | 97 } | 
| 97 | 98 | 
| 98 /*package-local*/ HgManifest(HgRepository hgRepo, RevlogStream content) { | 99 /*package-local*/ HgManifest(HgRepository hgRepo, RevlogStream content, EncodingHelper eh) { | 
| 99 super(hgRepo, content); | 100 super(hgRepo, content); | 
| 101 encodingHelper = eh; | |
| 100 } | 102 } | 
| 101 | 103 | 
| 102 /** | 104 /** | 
| 103 * Walks manifest revisions that correspond to specified range of changesets. The order in which manifest versions get reported | 105 * Walks manifest revisions that correspond to specified range of changesets. The order in which manifest versions get reported | 
| 104 * to the inspector corresponds to physical order of manifest revisions, not that of changesets (with few exceptions as noted below). | 106 * to the inspector corresponds to physical order of manifest revisions, not that of changesets (with few exceptions as noted below). | 
| 169 // there are tool-constructed repositories that got order of changeset revisions completely different from that of manifest | 171 // there are tool-constructed repositories that got order of changeset revisions completely different from that of manifest | 
| 170 int x = manifestLast; | 172 int x = manifestLast; | 
| 171 manifestLast = manifestFirst; | 173 manifestLast = manifestFirst; | 
| 172 manifestFirst = x; | 174 manifestFirst = x; | 
| 173 } | 175 } | 
| 174 content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector)); | 176 content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector, encodingHelper)); | 
| 175 } | 177 } | 
| 176 | 178 | 
| 177 /** | 179 /** | 
| 178 * "Sparse" iteration of the manifest, more effective than accessing revisions one by one. | 180 * "Sparse" iteration of the manifest, more effective than accessing revisions one by one. | 
| 179 * <p> Inspector is invoked for each changeset revision supplied, even when there's no manifest | 181 * <p> Inspector is invoked for each changeset revision supplied, even when there's no manifest | 
| 187 public void walk(final Inspector inspector, int... revisionIndexes) throws HgInvalidControlFileException{ | 189 public void walk(final Inspector inspector, int... revisionIndexes) throws HgInvalidControlFileException{ | 
| 188 if (inspector == null || revisionIndexes == null) { | 190 if (inspector == null || revisionIndexes == null) { | 
| 189 throw new IllegalArgumentException(); | 191 throw new IllegalArgumentException(); | 
| 190 } | 192 } | 
| 191 int[] manifestRevs = toManifestRevisionIndexes(revisionIndexes, inspector); | 193 int[] manifestRevs = toManifestRevisionIndexes(revisionIndexes, inspector); | 
| 192 content.iterate(manifestRevs, true, new ManifestParser(inspector)); | 194 content.iterate(manifestRevs, true, new ManifestParser(inspector, encodingHelper)); | 
| 193 } | 195 } | 
| 194 | 196 | 
| 195 // | 197 // | 
| 196 /** | 198 /** | 
| 197 * Tells manifest revision number that corresponds to the given changeset. | 199 * Tells manifest revision number that corresponds to the given changeset. | 
| 329 private static class PathProxy { | 331 private static class PathProxy { | 
| 330 private byte[] data; | 332 private byte[] data; | 
| 331 private int start; | 333 private int start; | 
| 332 private final int hash, length; | 334 private final int hash, length; | 
| 333 private Path result; | 335 private Path result; | 
| 334 | 336 private final EncodingHelper encHelper; | 
| 335 public PathProxy(byte[] data, int start, int length) { | 337 | 
| 338 public PathProxy(byte[] data, int start, int length, EncodingHelper eh) { | |
| 336 this.data = data; | 339 this.data = data; | 
| 337 this.start = start; | 340 this.start = start; | 
| 338 this.length = length; | 341 this.length = length; | 
| 342 this.encHelper = eh; | |
| 339 | 343 | 
| 340 // copy from String.hashCode(). In fact, not necessarily match result of String(data).hashCode | 344 // copy from String.hashCode(). In fact, not necessarily match result of String(data).hashCode | 
| 341 // just need some nice algorithm here | 345 // just need some nice algorithm here | 
| 342 int h = 0; | 346 int h = 0; | 
| 343 byte[] d = data; | 347 byte[] d = data; | 
| 371 return hash; | 375 return hash; | 
| 372 } | 376 } | 
| 373 | 377 | 
| 374 public Path freeze() { | 378 public Path freeze() { | 
| 375 if (result == null) { | 379 if (result == null) { | 
| 376 result = Path.create(EncodingHelper.fromManifest(data, start, length)); | 380 result = Path.create(encHelper.fromManifest(data, start, length)); | 
| 377 // release reference to bigger data array, make a copy of relevant part only | 381 // release reference to bigger data array, make a copy of relevant part only | 
| 378 // use original bytes, not those from String above to avoid cache misses due to different encodings | 382 // use original bytes, not those from String above to avoid cache misses due to different encodings | 
| 379 byte[] d = new byte[length]; | 383 byte[] d = new byte[length]; | 
| 380 System.arraycopy(data, start, d, 0, length); | 384 System.arraycopy(data, start, d, 0, length); | 
| 381 data = d; | 385 data = d; | 
| 391 private Pool2<Nodeid> nodeidPool, thisRevPool; | 395 private Pool2<Nodeid> nodeidPool, thisRevPool; | 
| 392 private final Pool2<PathProxy> fnamePool; | 396 private final Pool2<PathProxy> fnamePool; | 
| 393 private byte[] nodeidLookupBuffer = new byte[20]; // get reassigned each time new Nodeid is added to pool | 397 private byte[] nodeidLookupBuffer = new byte[20]; // get reassigned each time new Nodeid is added to pool | 
| 394 private final ProgressSupport progressHelper; | 398 private final ProgressSupport progressHelper; | 
| 395 private IterateControlMediator iterateControl; | 399 private IterateControlMediator iterateControl; | 
| 400 private final EncodingHelper encHelper; | |
| 396 | 401 | 
| 397 public ManifestParser(Inspector delegate) { | 402 public ManifestParser(Inspector delegate, EncodingHelper eh) { | 
| 398 assert delegate != null; | 403 assert delegate != null; | 
| 399 inspector = delegate; | 404 inspector = delegate; | 
| 400 inspector2 = delegate instanceof Inspector2 ? (Inspector2) delegate : null; | 405 inspector2 = delegate instanceof Inspector2 ? (Inspector2) delegate : null; | 
| 406 encHelper = eh; | |
| 401 nodeidPool = new Pool2<Nodeid>(); | 407 nodeidPool = new Pool2<Nodeid>(); | 
| 402 fnamePool = new Pool2<PathProxy>(); | 408 fnamePool = new Pool2<PathProxy>(); | 
| 403 thisRevPool = new Pool2<Nodeid>(); | 409 thisRevPool = new Pool2<Nodeid>(); | 
| 404 progressHelper = ProgressSupport.Factory.get(delegate); | 410 progressHelper = ProgressSupport.Factory.get(delegate); | 
| 405 } | 411 } | 
| 419 byte[] data = da.byteArray(); | 425 byte[] data = da.byteArray(); | 
| 420 for (i = 0; i < actualLen; i++) { | 426 for (i = 0; i < actualLen; i++) { | 
| 421 int x = i; | 427 int x = i; | 
| 422 for( ; data[i] != '\n' && i < actualLen; i++) { | 428 for( ; data[i] != '\n' && i < actualLen; i++) { | 
| 423 if (fname == null && data[i] == 0) { | 429 if (fname == null && data[i] == 0) { | 
| 424 PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x)); | 430 PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x, encHelper)); | 
| 425 // if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit | 431 // if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit | 
| 426 // cpython 0..10k: hits: 15 989 152, misses: 3020 | 432 // cpython 0..10k: hits: 15 989 152, misses: 3020 | 
| 427 fname = px.freeze(); | 433 fname = px.freeze(); | 
| 428 x = i+1; | 434 x = i+1; | 
| 429 } | 435 } | 
