Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 574:88afffd39899
Improve memory consumption of HgManifest#getFileRevision(): avoid extra byte[] instances
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> | 
|---|---|
| date | Tue, 16 Apr 2013 14:44:57 +0200 | 
| parents | e4ee4bf4c7d0 | 
| children | 47dfa0ec7e35 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 573:e49f9d9513fa | 574:88afffd39899 | 
|---|---|
| 18 | 18 | 
| 19 import static org.tmatesoft.hg.core.Nodeid.NULL; | 19 import static org.tmatesoft.hg.core.Nodeid.NULL; | 
| 20 import static org.tmatesoft.hg.repo.HgRepository.*; | 20 import static org.tmatesoft.hg.repo.HgRepository.*; | 
| 21 import static org.tmatesoft.hg.util.LogFacility.Severity.Info; | 21 import static org.tmatesoft.hg.util.LogFacility.Severity.Info; | 
| 22 | 22 | 
| 23 import java.io.ByteArrayOutputStream; | |
| 24 import java.io.IOException; | 23 import java.io.IOException; | 
| 25 import java.util.ArrayList; | 24 import java.util.ArrayList; | 
| 26 import java.util.Arrays; | 25 import java.util.Arrays; | 
| 27 | 26 | 
| 28 import org.tmatesoft.hg.core.HgChangesetFileSneaker; | 27 import org.tmatesoft.hg.core.HgChangesetFileSneaker; | 
| 29 import org.tmatesoft.hg.core.Nodeid; | 28 import org.tmatesoft.hg.core.Nodeid; | 
| 29 import org.tmatesoft.hg.internal.ByteVector; | |
| 30 import org.tmatesoft.hg.internal.Callback; | 30 import org.tmatesoft.hg.internal.Callback; | 
| 31 import org.tmatesoft.hg.internal.DataAccess; | 31 import org.tmatesoft.hg.internal.DataAccess; | 
| 32 import org.tmatesoft.hg.internal.DigestHelper; | 32 import org.tmatesoft.hg.internal.DigestHelper; | 
| 33 import org.tmatesoft.hg.internal.EncodingHelper; | 33 import org.tmatesoft.hg.internal.EncodingHelper; | 
| 34 import org.tmatesoft.hg.internal.IdentityPool; | |
| 34 import org.tmatesoft.hg.internal.IntMap; | 35 import org.tmatesoft.hg.internal.IntMap; | 
| 35 import org.tmatesoft.hg.internal.IterateControlMediator; | 36 import org.tmatesoft.hg.internal.IterateControlMediator; | 
| 36 import org.tmatesoft.hg.internal.Lifecycle; | 37 import org.tmatesoft.hg.internal.Lifecycle; | 
| 37 import org.tmatesoft.hg.internal.IdentityPool; | |
| 38 import org.tmatesoft.hg.internal.RevlogStream; | 38 import org.tmatesoft.hg.internal.RevlogStream; | 
| 39 import org.tmatesoft.hg.util.CancelSupport; | 39 import org.tmatesoft.hg.util.CancelSupport; | 
| 40 import org.tmatesoft.hg.util.LogFacility.Severity; | |
| 40 import org.tmatesoft.hg.util.Path; | 41 import org.tmatesoft.hg.util.Path; | 
| 41 import org.tmatesoft.hg.util.ProgressSupport; | 42 import org.tmatesoft.hg.util.ProgressSupport; | 
| 42 import org.tmatesoft.hg.util.LogFacility.Severity; | |
| 43 | 43 | 
| 44 | 44 | 
| 45 /** | 45 /** | 
| 46 * Representation of Mercurial manifest file (list of file names and their revisions in a particular changeset) | 46 * Representation of Mercurial manifest file (list of file names and their revisions in a particular changeset) | 
| 47 * | 47 * | 
| 49 * @author Artem Tikhomirov | 49 * @author Artem Tikhomirov | 
| 50 * @author TMate Software Ltd. | 50 * @author TMate Software Ltd. | 
| 51 */ | 51 */ | 
| 52 public final class HgManifest extends Revlog { | 52 public final class HgManifest extends Revlog { | 
| 53 private RevisionMapper revisionMap; | 53 private RevisionMapper revisionMap; | 
| 54 private EncodingHelper encodingHelper; | 54 private final EncodingHelper encodingHelper; | 
| 55 private final Path.Source pathFactory; | |
| 55 | 56 | 
| 56 /** | 57 /** | 
| 57 * File flags recorded in manifest | 58 * File flags recorded in manifest | 
| 58 */ | 59 */ | 
| 59 public enum Flags { | 60 public enum Flags { | 
| 109 if (this == RegularFile) { | 110 if (this == RegularFile) { | 
| 110 return ""; | 111 return ""; | 
| 111 } | 112 } | 
| 112 throw new IllegalStateException(toString()); | 113 throw new IllegalStateException(toString()); | 
| 113 } | 114 } | 
| 115 | |
| 116 public int fsMode() { | |
| 117 if (this == Exec) { | |
| 118 return 0755; | |
| 119 } | |
| 120 return 0644; | |
| 121 } | |
| 114 } | 122 } | 
| 115 | 123 | 
| 116 /*package-local*/ HgManifest(HgRepository hgRepo, RevlogStream content, EncodingHelper eh) { | 124 /*package-local*/ HgManifest(HgRepository hgRepo, RevlogStream content, EncodingHelper eh) { | 
| 117 super(hgRepo, content); | 125 super(hgRepo, content); | 
| 118 encodingHelper = eh; | 126 encodingHelper = eh; | 
| 127 pathFactory = hgRepo.getSessionContext().getPathFactory(); | |
| 119 } | 128 } | 
| 120 | 129 | 
| 121 /** | 130 /** | 
| 122 * Walks manifest revisions that correspond to specified range of changesets. The order in which manifest versions get reported | 131 * Walks manifest revisions that correspond to specified range of changesets. The order in which manifest versions get reported | 
| 123 * to the inspector corresponds to physical order of manifest revisions, not that of changesets (with few exceptions as noted below). | 132 * to the inspector corresponds to physical order of manifest revisions, not that of changesets (with few exceptions as noted below). | 
| 444 return hash; | 453 return hash; | 
| 445 } | 454 } | 
| 446 | 455 | 
| 447 public Path freeze() { | 456 public Path freeze() { | 
| 448 if (result == null) { | 457 if (result == null) { | 
| 449 Path.Source pathFactory = HgManifest.this.getRepo().getSessionContext().getPathFactory(); | 458 Path.Source pf = HgManifest.this.pathFactory; | 
| 450 result = pathFactory.path(HgManifest.this.encodingHelper.fromManifest(data, start, length)); | 459 result = pf.path(HgManifest.this.encodingHelper.fromManifest(data, start, length)); | 
| 451 // release reference to bigger data array, make a copy of relevant part only | 460 // release reference to bigger data array, make a copy of relevant part only | 
| 452 // use original bytes, not those from String above to avoid cache misses due to different encodings | 461 // use original bytes, not those from String above to avoid cache misses due to different encodings | 
| 453 byte[] d = new byte[length]; | 462 byte[] d = new byte[length]; | 
| 454 System.arraycopy(data, start, d, 0, length); | 463 System.arraycopy(data, start, d, 0, length); | 
| 455 data = d; | 464 data = d; | 
| 687 void walk(int[] manifestRevIndexes, RevlogStream content) { | 696 void walk(int[] manifestRevIndexes, RevlogStream content) { | 
| 688 content.iterate(manifestRevIndexes, true, this); | 697 content.iterate(manifestRevIndexes, true, this); | 
| 689 } | 698 } | 
| 690 | 699 | 
| 691 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { | 700 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { | 
| 692 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | 701 ByteVector byteVector = new ByteVector(256, 128); // allocate for long paths right away | 
| 693 try { | 702 try { | 
| 694 byte b; | 703 byte b; | 
| 695 while (!data.isEmpty() && (b = data.readByte()) != '\n') { | 704 while (!data.isEmpty() && (b = data.readByte()) != '\n') { | 
| 696 if (b != 0) { | 705 if (b != 0) { | 
| 697 bos.write(b); | 706 byteVector.add(b); | 
| 698 } else { | 707 } else { | 
| 699 byte[] byteArray = bos.toByteArray(); | 708 if (byteVector.equalsTo(filenameAsBytes)) { | 
| 700 bos.reset(); | |
| 701 if (Arrays.equals(filenameAsBytes, byteArray)) { | |
| 702 Nodeid fileRev = null; | 709 Nodeid fileRev = null; | 
| 703 Flags flags = null; | 710 Flags flags = null; | 
| 704 if (csetIndex2FileRev != null || delegate != null) { | 711 if (csetIndex2FileRev != null || delegate != null) { | 
| 705 byte[] nid = new byte[40]; | 712 byte[] nid = new byte[40]; | 
| 706 data.readBytes(nid, 0, 40); | 713 data.readBytes(nid, 0, 40); | 
| 707 fileRev = Nodeid.fromAscii(nid, 0, 40); | 714 fileRev = Nodeid.fromAscii(nid, 0, 40); | 
| 708 } else { | 715 } else { | 
| 709 data.skip(40); | 716 data.skip(40); | 
| 710 } | 717 } | 
| 711 if (csetIndex2Flags != null || delegate != null) { | 718 if (csetIndex2Flags != null || delegate != null) { | 
| 719 byteVector.clear(); | |
| 712 while (!data.isEmpty() && (b = data.readByte()) != '\n') { | 720 while (!data.isEmpty() && (b = data.readByte()) != '\n') { | 
| 713 bos.write(b); | 721 byteVector.add(b); | 
| 714 } | 722 } | 
| 715 if (bos.size() == 0) { | 723 if (byteVector.size() == 0) { | 
| 716 flags = Flags.RegularFile; | 724 flags = Flags.RegularFile; | 
| 717 } else { | 725 } else { | 
| 718 flags = Flags.parse(bos.toByteArray(), 0, bos.size()); | 726 flags = Flags.parse(byteVector.toByteArray(), 0, byteVector.size()); | 
| 719 } | 727 } | 
| 720 | |
| 721 } | 728 } | 
| 722 if (delegate != null) { | 729 if (delegate != null) { | 
| 723 assert flags != null; | 730 assert flags != null; | 
| 724 assert fileRev != null; | 731 assert fileRev != null; | 
| 725 delegate.begin(revisionNumber, Nodeid.fromBinary(nodeid, 0), linkRevision); | 732 delegate.begin(revisionNumber, Nodeid.fromBinary(nodeid, 0), linkRevision); | 
| 739 data.skip(40); | 746 data.skip(40); | 
| 740 } | 747 } | 
| 741 // else skip to the end of line | 748 // else skip to the end of line | 
| 742 while (!data.isEmpty() && (b = data.readByte()) != '\n') | 749 while (!data.isEmpty() && (b = data.readByte()) != '\n') | 
| 743 ; | 750 ; | 
| 751 | |
| 752 byteVector.clear(); | |
| 744 } | 753 } | 
| 745 } | 754 } | 
| 746 } catch (IOException ex) { | 755 } catch (IOException ex) { | 
| 747 throw new HgInvalidControlFileException("Failed reading manifest", ex, null); | 756 throw new HgInvalidControlFileException("Failed reading manifest", ex, null); | 
| 748 } | 757 } | 
