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