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