comparison src/org/tmatesoft/hg/repo/HgChangelog.java @ 196:e2115da4cf6a

Pool objects to avoid memory polution with duplicates
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 18 Apr 2011 18:04:24 +0200
parents f26ffe04ced0
children 644ee58c9f16
comparison
equal deleted inserted replaced
195:c9b305df0b89 196:e2115da4cf6a
28 import java.util.List; 28 import java.util.List;
29 import java.util.Locale; 29 import java.util.Locale;
30 import java.util.Map; 30 import java.util.Map;
31 import java.util.TimeZone; 31 import java.util.TimeZone;
32 32
33 import org.tmatesoft.hg.core.HgBadStateException;
33 import org.tmatesoft.hg.core.Nodeid; 34 import org.tmatesoft.hg.core.Nodeid;
34 import org.tmatesoft.hg.internal.DataAccess; 35 import org.tmatesoft.hg.internal.DataAccess;
36 import org.tmatesoft.hg.internal.Pool;
35 import org.tmatesoft.hg.internal.RevlogStream; 37 import org.tmatesoft.hg.internal.RevlogStream;
36 38
37 /** 39 /**
38 * Representation of the Mercurial changelog file (list of ChangeSets) 40 * Representation of the Mercurial changelog file (list of ChangeSets)
39 * 41 *
49 public void all(final HgChangelog.Inspector inspector) { 51 public void all(final HgChangelog.Inspector inspector) {
50 range(0, getLastRevision(), inspector); 52 range(0, getLastRevision(), inspector);
51 } 53 }
52 54
53 public void range(int start, int end, final HgChangelog.Inspector inspector) { 55 public void range(int start, int end, final HgChangelog.Inspector inspector) {
54 RevlogStream.Inspector i = new RevlogStream.Inspector() { 56 if (inspector == null) {
55 57 throw new IllegalArgumentException();
56 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { 58 }
57 RawChangeset cset = RawChangeset.parse(da); 59 content.iterate(start, end, true, new RawCsetParser(inspector));
58 // XXX there's no guarantee for Changeset.Callback that distinct instance comes each time, consider instance reuse
59 inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset);
60 }
61 };
62 content.iterate(start, end, true, i);
63 } 60 }
64 61
65 public List<RawChangeset> range(int start, int end) { 62 public List<RawChangeset> range(int start, int end) {
66 final ArrayList<RawChangeset> rv = new ArrayList<RawChangeset>(end - start + 1); 63 final RawCsetCollector c = new RawCsetCollector(end - start + 1);
67 RevlogStream.Inspector i = new RevlogStream.Inspector() { 64 range(start, end, c);
68 65 return c.result;
69 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) {
70 RawChangeset cset = RawChangeset.parse(da);
71 rv.add(cset);
72 }
73 };
74 content.iterate(start, end, true, i);
75 return rv;
76 } 66 }
77 67
78 public void range(final HgChangelog.Inspector inspector, final int... revisions) { 68 public void range(final HgChangelog.Inspector inspector, final int... revisions) {
79 if (revisions == null || revisions.length == 0) { 69 if (revisions == null || revisions.length == 0) {
80 return; 70 return;
81 } 71 }
82 RevlogStream.Inspector i = new RevlogStream.Inspector() { 72 RevlogStream.Inspector i = new RevlogStream.Inspector() {
73 private final RawCsetParser delegate = new RawCsetParser(inspector);
83 74
84 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { 75 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) {
85 if (Arrays.binarySearch(revisions, revisionNumber) >= 0) { 76 if (Arrays.binarySearch(revisions, revisionNumber) >= 0) {
86 RawChangeset cset = RawChangeset.parse(da); 77 delegate.next(revisionNumber, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, nodeid, da);
87 inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset);
88 } 78 }
89 } 79 }
90 }; 80 };
91 Arrays.sort(revisions); 81 Arrays.sort(revisions);
92 content.iterate(revisions[0], revisions[revisions.length - 1], true, i); 82 content.iterate(revisions[0], revisions[revisions.length - 1], true, i);
204 194
205 public static RawChangeset parse(DataAccess da) { 195 public static RawChangeset parse(DataAccess da) {
206 try { 196 try {
207 byte[] data = da.byteArray(); 197 byte[] data = da.byteArray();
208 RawChangeset rv = new RawChangeset(); 198 RawChangeset rv = new RawChangeset();
209 rv.init(data, 0, data.length); 199 rv.init(data, 0, data.length, null);
210 return rv; 200 return rv;
211 } catch (IOException ex) { 201 } catch (IOException ex) {
212 throw new IllegalArgumentException(ex); // FIXME better handling of IOExc 202 throw new HgBadStateException(ex); // FIXME "Error reading changeset data"
213 } 203 }
214 } 204 }
215 205
216 /* package-local */void init(byte[] data, int offset, int length) { 206 // @param usersPool - it's likely user names get repeated again and again throughout repository. can be null
207 /* package-local */void init(byte[] data, int offset, int length, Pool<String> usersPool) {
217 final int bufferEndIndex = offset + length; 208 final int bufferEndIndex = offset + length;
218 final byte lineBreak = (byte) '\n'; 209 final byte lineBreak = (byte) '\n';
219 int breakIndex1 = indexOf(data, lineBreak, offset, bufferEndIndex); 210 int breakIndex1 = indexOf(data, lineBreak, offset, bufferEndIndex);
220 if (breakIndex1 == -1) { 211 if (breakIndex1 == -1) {
221 throw new IllegalArgumentException("Bad Changeset data"); 212 throw new IllegalArgumentException("Bad Changeset data");
224 int breakIndex2 = indexOf(data, lineBreak, breakIndex1 + 1, bufferEndIndex); 215 int breakIndex2 = indexOf(data, lineBreak, breakIndex1 + 1, bufferEndIndex);
225 if (breakIndex2 == -1) { 216 if (breakIndex2 == -1) {
226 throw new IllegalArgumentException("Bad Changeset data"); 217 throw new IllegalArgumentException("Bad Changeset data");
227 } 218 }
228 String _user = new String(data, breakIndex1 + 1, breakIndex2 - breakIndex1 - 1); 219 String _user = new String(data, breakIndex1 + 1, breakIndex2 - breakIndex1 - 1);
220 if (usersPool != null) {
221 _user = usersPool.unify(_user);
222 }
229 int breakIndex3 = indexOf(data, lineBreak, breakIndex2 + 1, bufferEndIndex); 223 int breakIndex3 = indexOf(data, lineBreak, breakIndex2 + 1, bufferEndIndex);
230 if (breakIndex3 == -1) { 224 if (breakIndex3 == -1) {
231 throw new IllegalArgumentException("Bad Changeset data"); 225 throw new IllegalArgumentException("Bad Changeset data");
232 } 226 }
233 String _timeString = new String(data, breakIndex2 + 1, breakIndex3 - breakIndex2 - 1); 227 String _timeString = new String(data, breakIndex2 + 1, breakIndex3 - breakIndex2 - 1);
310 } 304 }
311 return -1; 305 return -1;
312 } 306 }
313 } 307 }
314 308
309 private static class RawCsetCollector implements Inspector {
310 final ArrayList<RawChangeset> result;
311
312 public RawCsetCollector(int count) {
313 result = new ArrayList<RawChangeset>(count > 0 ? count : 5);
314 }
315
316 public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) {
317 result.add(cset.clone());
318 }
319 }
320
321 private static class RawCsetParser implements RevlogStream.Inspector {
322
323 private final Inspector inspector;
324 private final Pool<String> usersPool;
325 private final RawChangeset cset = new RawChangeset();
326
327 public RawCsetParser(HgChangelog.Inspector delegate) {
328 assert delegate != null;
329 inspector = delegate;
330 usersPool = new Pool<String>();
331 }
332
333 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) {
334 try {
335 byte[] data = da.byteArray();
336 cset.init(data, 0, data.length, usersPool);
337 // XXX there's no guarantee for Changeset.Callback that distinct instance comes each time, consider instance reuse
338 inspector.next(revisionNumber, Nodeid.fromBinary(nodeid, 0), cset);
339 } catch (Exception ex) {
340 throw new HgBadStateException(ex); // FIXME exception handling
341 }
342 }
343 }
315 } 344 }