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