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