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 }