comparison src/org/tmatesoft/hg/repo/Revlog.java @ 448:2e402c12ebc6 smartgit3

Issue 31: Revlog#walk() fails with AIOOBE when start > 0
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 06 Jun 2012 21:23:57 +0200
parents d0e5dc3cae6e
children 7bcfbc255f48
comparison
equal deleted inserted replaced
447:056f724bdc21 448:2e402c12ebc6
34 import org.tmatesoft.hg.core.HgInvalidRevisionException; 34 import org.tmatesoft.hg.core.HgInvalidRevisionException;
35 import org.tmatesoft.hg.core.Nodeid; 35 import org.tmatesoft.hg.core.Nodeid;
36 import org.tmatesoft.hg.internal.ArrayHelper; 36 import org.tmatesoft.hg.internal.ArrayHelper;
37 import org.tmatesoft.hg.internal.DataAccess; 37 import org.tmatesoft.hg.internal.DataAccess;
38 import org.tmatesoft.hg.internal.Experimental; 38 import org.tmatesoft.hg.internal.Experimental;
39 import org.tmatesoft.hg.internal.IntMap;
39 import org.tmatesoft.hg.internal.Preview; 40 import org.tmatesoft.hg.internal.Preview;
40 import org.tmatesoft.hg.internal.RevlogStream; 41 import org.tmatesoft.hg.internal.RevlogStream;
41 import org.tmatesoft.hg.util.Adaptable; 42 import org.tmatesoft.hg.util.Adaptable;
42 import org.tmatesoft.hg.util.ByteChannel; 43 import org.tmatesoft.hg.util.ByteChannel;
43 import org.tmatesoft.hg.util.CancelSupport; 44 import org.tmatesoft.hg.util.CancelSupport;
257 } 258 }
258 259
259 @Experimental 260 @Experimental
260 public final void walk(int start, int end, final Revlog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException { 261 public final void walk(int start, int end, final Revlog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException {
261 int lastRev = getLastRevision(); 262 int lastRev = getLastRevision();
262 if (start == TIP) { 263 final int _start = start == TIP ? lastRev : start;
263 start = lastRev;
264 }
265 if (end == TIP) { 264 if (end == TIP) {
266 end = lastRev; 265 end = lastRev;
267 } 266 }
268 final RevisionInspector revisionInsp = Adaptable.Factory.getAdapter(inspector, RevisionInspector.class, null); 267 final RevisionInspector revisionInsp = Adaptable.Factory.getAdapter(inspector, RevisionInspector.class, null);
269 final ParentInspector parentInsp = Adaptable.Factory.getAdapter(inspector, ParentInspector.class, null); 268 final ParentInspector parentInsp = Adaptable.Factory.getAdapter(inspector, ParentInspector.class, null);
270 final Nodeid[] allRevisions = parentInsp == null ? null : new Nodeid[end - start + 1]; 269 final Nodeid[] allRevisions = parentInsp == null ? null : new Nodeid[end - _start + 1];
271 if (parentInsp != null && start != 0) { 270 // next are to build set of parent indexes that are not part of the range iteration
272 // e.g. start == 6, end == 7 and parentOf(start) == 5. allRevisions.length == 2, allRevisions[parentOf(start)] => AIOOBE 271 // i.e. those parents we need to read separately. See Issue 31 for details.
273 throw new IllegalStateException("There's a defect in the code that doesn't allow walks other than from the very beginning"); 272 final int[] firstParentIndexes = parentInsp == null || _start == 0 ? null : new int[allRevisions.length];
274 // TestAuxUtilities#testRevlogInspectors 273 final int[] secondParentIndexes = parentInsp == null || _start == 0 ? null : new int[allRevisions.length];
275 } 274 final IntMap<Nodeid> missingParents = parentInsp == null || _start == 0 ? null : new IntMap<Nodeid>(16);
276 275
277 content.iterate(start, end, false, new RevlogStream.Inspector() { 276 content.iterate(_start, end, false, new RevlogStream.Inspector() {
277 private int i = 0;
278 278
279 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { 279 public void next(int revisionIndex, int actualLen, int baseRevIndex, int linkRevIndex, int parent1RevIndex, int parent2RevIndex, byte[] nodeid, DataAccess data) {
280 Nodeid nid = Nodeid.fromBinary(nodeid, 0); 280 Nodeid nid = Nodeid.fromBinary(nodeid, 0);
281 if (revisionInsp != null) { 281 if (revisionInsp != null) {
282 revisionInsp.next(revisionNumber, nid, linkRevision); 282 revisionInsp.next(revisionIndex, nid, linkRevIndex);
283 } 283 }
284 if (parentInsp != null) { 284 if (parentInsp != null) {
285 Nodeid p1 = parent1Revision == -1 ? Nodeid.NULL : allRevisions[parent1Revision]; 285 allRevisions[i] = nid;
286 Nodeid p2 = parent2Revision == -1 ? Nodeid.NULL : allRevisions[parent2Revision]; 286 if (_start > 0) {
287 allRevisions[revisionNumber] = nid; 287 firstParentIndexes[i] = parent1RevIndex;
288 parentInsp.next(revisionNumber, nid, parent1Revision, parent2Revision, p1, p2); 288 secondParentIndexes[i] = parent2RevIndex;
289 if (parent1RevIndex < _start && parent1RevIndex >= 0) {
290 missingParents.put(parent1RevIndex, null);
291 }
292 if (parent2RevIndex < _start && parent2RevIndex >= 0) {
293 missingParents.put(parent2RevIndex, null);
294 }
295 } else {
296 Nodeid p1 = parent1RevIndex == -1 ? Nodeid.NULL : allRevisions[parent1RevIndex];
297 Nodeid p2 = parent2RevIndex == -1 ? Nodeid.NULL : allRevisions[parent2RevIndex];
298 parentInsp.next(revisionIndex, allRevisions[i], parent1RevIndex, parent2RevIndex, p1, p2);
299 }
300 i++;
289 } 301 }
290 } 302 }
291 }); 303 });
304 if (parentInsp != null && _start > 0) {
305 assert missingParents.size() > 0; // in fact, more relaxed than assert. rather 'assume'
306 // TODO int[] IntMap#keys() or even sort of iterator that can modify values
307 for (int k = missingParents.firstKey(), l = missingParents.lastKey(); k <= l; k++) {
308 if (missingParents.containsKey(k)) {
309 Nodeid nid = getRepo().getChangelog().getRevision(k);
310 missingParents.put(k, nid);
311 }
312 }
313
314 for (int i = 0, revNum = _start; i < allRevisions.length; i++, revNum++) {
315 int riP1 = firstParentIndexes[i];
316 int riP2 = secondParentIndexes[i];
317 Nodeid p1, p2;
318 p1 = p2 = Nodeid.NULL;
319 if (riP1 >= _start) {
320 // p1 of revNum's revision is out of iterated range
321 // (don't check for riP1<end as I assume parents come prior to children in the changelog)
322 p1 = allRevisions[riP1 - start];
323 } else if (riP1 != -1) {
324 assert riP1 >=0 && riP1 < _start;
325 p1 = missingParents.get(riP1);
326 }
327 // same for Pp2
328 if (riP2 >= _start) {
329 p2 = allRevisions[riP2 - start];
330 } else if (riP2 != -1) {
331 assert riP2 >= 0 && riP2 < _start;
332 p2 = missingParents.get(riP2);
333 }
334 parentInsp.next(revNum, allRevisions[i], riP1, riP2, p1, p2);
335 }
336 }
292 } 337 }
293 338
294 /** 339 /**
295 * MARKER 340 * MARKER
296 */ 341 */