Browse Source

Revert "RevWalk: stop mixing lines of history in topo sort"

This reverts commit b5e764abd2.

PlotWalk uses the TopoSortGenerator, which is causing problems for EGit users
who rely on the emission of commits being somewhat based on date as in the
previous topo-sort algorithm.

Bug: 560529
Change-Id: I3dbd3598a7aeb960de3fc39352699b4f11a8c226
Signed-off-by: Alex Spradlin <alexaspradlin@google.com>
stable-5.8
Alex Spradlin 5 years ago
parent
commit
e40c38ab08
  1. 4
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
  2. 88
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/PlotCommitListTest.java
  3. 106
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java
  4. 2
      org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java
  5. 8
      org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
  6. 34
      org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java

4
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java

@ -563,10 +563,10 @@ public class RebaseCommandTest extends RepositoryTestCase {
RevCommit newD = rw.next(); RevCommit newD = rw.next();
assertDerivedFrom(newD, d); assertDerivedFrom(newD, d);
assertEquals(2, newD.getParentCount()); assertEquals(2, newD.getParentCount());
RevCommit newE = rw.next();
assertEquals(e, newE);
RevCommit newC = rw.next(); RevCommit newC = rw.next();
assertDerivedFrom(newC, c); assertDerivedFrom(newC, c);
RevCommit newE = rw.next();
assertEquals(e, newE);
assertEquals(newC, newD.getParent(0)); assertEquals(newC, newD.getParent(0));
assertEquals(e, newD.getParent(1)); assertEquals(e, newD.getParent(1));
assertEquals(g, rw.next()); assertEquals(g, rw.next());

88
org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/PlotCommitListTest.java

@ -254,12 +254,12 @@ public class PlotCommitListTest extends RevWalkTestCase {
int posI = test.commit(i).lanePos(childPositions).parents(h) int posI = test.commit(i).lanePos(childPositions).parents(h)
.getLanePos(); .getLanePos();
test.commit(h).lanePos(posI).parents(f); test.commit(h).lanePos(posI).parents(f);
test.commit(g).lanePos(childPositions).parents(a);
test.commit(f).lanePos(posI).parents(e, d); test.commit(f).lanePos(posI).parents(e, d);
test.commit(d).lanePos(1).parents(b);
test.commit(e).lanePos(posI).parents(c); test.commit(e).lanePos(posI).parents(c);
test.commit(d).lanePos(2).parents(b);
test.commit(c).lanePos(posI).parents(b); test.commit(c).lanePos(posI).parents(b);
test.commit(b).lanePos(posI).parents(a); test.commit(b).lanePos(posI).parents(a);
test.commit(g).lanePos(childPositions).parents(a);
test.commit(a).lanePos(0).parents(); test.commit(a).lanePos(0).parents();
} }
} }
@ -325,42 +325,42 @@ public class PlotCommitListTest extends RevWalkTestCase {
.lanePos(mainPos); .lanePos(mainPos);
test.commit(merge_update_eclipse) test.commit(merge_update_eclipse)
.parents(add_a_clear, update_eclipse).lanePos(mainPos); .parents(add_a_clear, update_eclipse).lanePos(mainPos);
test.commit(update_eclipse).parents(add_Maven).lanePos(2);
test.commit(add_a_clear).parents(fix_broken).lanePos(mainPos); test.commit(add_a_clear).parents(fix_broken).lanePos(mainPos);
test.commit(fix_broken).parents(merge_disable_comment) test.commit(fix_broken).parents(merge_disable_comment)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(merge_disable_comment) test.commit(merge_disable_comment)
.parents(merge_resolve_handler, disable_comment) .parents(merge_resolve_handler, disable_comment)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(disable_comment).parents(clone_operation).lanePos(3); test.commit(disable_comment).parents(clone_operation).lanePos(2);
test.commit(merge_resolve_handler) test.commit(merge_resolve_handler)
.parents(clone_operation, resolve_handler).lanePos(mainPos); .parents(clone_operation, resolve_handler).lanePos(mainPos);
test.commit(resolve_handler).parents(merge_fix).lanePos(4); test.commit(update_eclipse).parents(add_Maven).lanePos(3);
test.commit(clone_operation).parents(merge_changeset_implementation) test.commit(clone_operation).parents(merge_changeset_implementation)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(merge_changeset_implementation) test.commit(merge_changeset_implementation)
.parents(merge_disable_source, changeset_implementation) .parents(merge_disable_source, changeset_implementation)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(changeset_implementation).parents(clear_repositorycache)
.lanePos(1);
test.commit(merge_disable_source) test.commit(merge_disable_source)
.parents(update_eclipse_iplog2, disable_source) .parents(update_eclipse_iplog2, disable_source)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(disable_source).parents(merge_use_remote).lanePos(3);
test.commit(update_eclipse_iplog2).parents(merge_use_remote) test.commit(update_eclipse_iplog2).parents(merge_use_remote)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(disable_source).parents(merge_use_remote).lanePos(1);
test.commit(merge_use_remote) test.commit(merge_use_remote)
.parents(update_eclipse_iplog, use_remote).lanePos(mainPos); .parents(update_eclipse_iplog, use_remote).lanePos(mainPos);
test.commit(use_remote).parents(clear_repositorycache).lanePos(3); test.commit(changeset_implementation).parents(clear_repositorycache)
.lanePos(2);
test.commit(update_eclipse_iplog).parents(merge_add_Maven) test.commit(update_eclipse_iplog).parents(merge_add_Maven)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(merge_add_Maven).parents(findToolBar_layout, add_Maven) test.commit(merge_add_Maven).parents(findToolBar_layout, add_Maven)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(add_Maven).parents(clear_repositorycache).lanePos(2);
test.commit(findToolBar_layout).parents(clear_repositorycache) test.commit(findToolBar_layout).parents(clear_repositorycache)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(use_remote).parents(clear_repositorycache).lanePos(1);
test.commit(add_Maven).parents(clear_repositorycache).lanePos(3);
test.commit(clear_repositorycache).parents(merge_remove) test.commit(clear_repositorycache).parents(merge_remove)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(resolve_handler).parents(merge_fix).lanePos(4);
test.commit(merge_remove).parents(add_simple, remove_unused) test.commit(merge_remove).parents(add_simple, remove_unused)
.lanePos(mainPos); .lanePos(mainPos);
test.commit(remove_unused).parents(merge_fix).lanePos(1); test.commit(remove_unused).parents(merge_fix).lanePos(1);
@ -453,36 +453,33 @@ public class PlotCommitListTest extends RevWalkTestCase {
pcl.source(pw); pcl.source(pw);
pcl.fillTo(Integer.MAX_VALUE); pcl.fillTo(Integer.MAX_VALUE);
Set<Integer> positions = asSet(0, 1); // test that the commits b1, b2 and b3 are on the same position
CommitListAssert test = new CommitListAssert(pcl); int bPos = pcl.get(9).lane.position; // b1
int posA = test.commit(a5).lanePos(positions).getLanePos(); assertEquals("b2 is an a different position", bPos,
test.commit(a4); pcl.get(7).lane.position);
test.commit(a3).lanePos(posA); assertEquals("b3 is on a different position", bPos,
test.commit(e); pcl.get(4).lane.position);
test.commit(d);
test.commit(a2).lanePos(posA); // test that nothing blocks the connections between b1, b2 and b3
int posB = test.commit(b3).lanePos(positions).getLanePos(); assertNotEquals("b lane is blocked by c", bPos,
test.commit(b2).lanePos(posB); pcl.get(8).lane.position);
test.commit(b1).lanePos(posB); assertNotEquals("b lane is blocked by a2", bPos,
test.commit(c); pcl.get(6).lane.position);
test.commit(a1).lanePos(posA); assertNotEquals("b lane is blocked by d", bPos,
test.noMoreCommits(); pcl.get(5).lane.position);
assertNotEquals("a lane is the same as b lane", posA, posB);
} }
} }
/** /**
* <pre> * <pre>
* b3 * b3
* a5 |
* | |
* a4 | * a4 |
* | \| * | \|
* | b2 * | b2
* a3 | * a3 |
* | \| * | \|
* | b1
* a2 | * a2 |
* | b1
* | / * | /
* a1 * a1
* </pre> * </pre>
@ -497,11 +494,10 @@ public class PlotCommitListTest extends RevWalkTestCase {
final RevCommit a3 = commit(a2, b1); final RevCommit a3 = commit(a2, b1);
final RevCommit b2 = commit(b1); final RevCommit b2 = commit(b1);
final RevCommit a4 = commit(a3, b2); final RevCommit a4 = commit(a3, b2);
final RevCommit a5 = commit(a4);
final RevCommit b3 = commit(b2); final RevCommit b3 = commit(b2);
try (PlotWalk pw = new PlotWalk(db)) { try (PlotWalk pw = new PlotWalk(db)) {
pw.markStart(pw.lookupCommit(a5)); pw.markStart(pw.lookupCommit(a4));
pw.markStart(pw.lookupCommit(b3)); pw.markStart(pw.lookupCommit(b3));
PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); PlotCommitList<PlotLane> pcl = new PlotCommitList<>();
pcl.source(pw); pcl.source(pw);
@ -510,12 +506,11 @@ public class PlotCommitListTest extends RevWalkTestCase {
Set<Integer> positions = asSet(0, 1); Set<Integer> positions = asSet(0, 1);
CommitListAssert test = new CommitListAssert(pcl); CommitListAssert test = new CommitListAssert(pcl);
int posB = test.commit(b3).lanePos(positions).getLanePos(); int posB = test.commit(b3).lanePos(positions).getLanePos();
int posA = test.commit(a5).lanePos(positions).getLanePos(); int posA = test.commit(a4).lanePos(positions).getLanePos();
test.commit(a4).lanePos(posA);
test.commit(b2).lanePos(posB); test.commit(b2).lanePos(posB);
test.commit(a3).lanePos(posA); test.commit(a3).lanePos(posA);
test.commit(b1).lanePos(posB);
test.commit(a2).lanePos(posA); test.commit(a2).lanePos(posA);
test.commit(b1).lanePos(posB);
test.commit(a1).lanePos(posA); test.commit(a1).lanePos(posA);
test.noMoreCommits(); test.noMoreCommits();
} }
@ -524,17 +519,13 @@ public class PlotCommitListTest extends RevWalkTestCase {
/** /**
* <pre> * <pre>
* a4 * a4
* | * | b3
* a3 * a3 |
* | \\ * | \\|
* a2 \\ * | |\\
* | \\
* | b3 ||
* | | ||
* | b2|| * | b2||
* | | // * a2 | //
* | b1 * | b1
* | |
* | / * | /
* a1 * a1
* </pre> * </pre>
@ -561,10 +552,10 @@ public class PlotCommitListTest extends RevWalkTestCase {
Set<Integer> positions = asSet(0, 1); Set<Integer> positions = asSet(0, 1);
CommitListAssert test = new CommitListAssert(pcl); CommitListAssert test = new CommitListAssert(pcl);
int posA = test.commit(a4).lanePos(positions).getLanePos(); int posA = test.commit(a4).lanePos(positions).getLanePos();
test.commit(a3).lanePos(posA);
test.commit(a2).lanePos(posA);
int posB = test.commit(b3).lanePos(positions).getLanePos(); int posB = test.commit(b3).lanePos(positions).getLanePos();
test.commit(a3).lanePos(posA);
test.commit(b2).lanePos(posB); test.commit(b2).lanePos(posB);
test.commit(a2).lanePos(posA);
// b1 is not repositioned, uses "detour lane" // b1 is not repositioned, uses "detour lane"
// (drawn as a double arc in the ascii graph above) // (drawn as a double arc in the ascii graph above)
test.commit(b1).lanePos(posB); test.commit(b1).lanePos(posB);
@ -578,14 +569,13 @@ public class PlotCommitListTest extends RevWalkTestCase {
* b2 * b2
* a4 | * a4 |
* | \ | * | \ |
* | b1 * a3 \|
* a3 |
* | \ | * | \ |
* | c | * | c |
* | / | * | / |
* a2 | * a2 |
* | | * | b1
* | / * /
* | / * | /
* a1 * a1
* </pre> * </pre>
@ -614,10 +604,10 @@ public class PlotCommitListTest extends RevWalkTestCase {
CommitListAssert test = new CommitListAssert(pcl); CommitListAssert test = new CommitListAssert(pcl);
int posB = test.commit(b2).lanePos(positions).getLanePos(); int posB = test.commit(b2).lanePos(positions).getLanePos();
int posA = test.commit(a4).lanePos(positions).getLanePos(); int posA = test.commit(a4).lanePos(positions).getLanePos();
test.commit(b1).lanePos(posB); // repositioned to go around c
test.commit(a3).lanePos(posA); test.commit(a3).lanePos(posA);
test.commit(c).lanePos(positions); test.commit(c).lanePos(positions);
test.commit(a2).lanePos(posA); test.commit(a2).lanePos(posA);
test.commit(b1).lanePos(posB); // repositioned to go around c
test.commit(a1).lanePos(posA); test.commit(a1).lanePos(posA);
test.noMoreCommits(); test.noMoreCommits();
} }

106
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java

@ -144,110 +144,4 @@ public class RevWalkSortTest extends RevWalkTestCase {
assertCommit(d, rw.next()); assertCommit(d, rw.next());
assertNull(rw.next()); assertNull(rw.next());
} }
@Test
public void testSort_TOPO_OutOfOrderCommitTimes() throws Exception {
// b is committed before c2 in a different line of history.
//
final RevCommit a = commit();
final RevCommit c1 = commit(a);
final RevCommit b = commit(a);
final RevCommit c2 = commit(c1);
final RevCommit d = commit(b, c2);
rw.sort(RevSort.TOPO);
markStart(d);
assertCommit(d, rw.next());
assertCommit(c2, rw.next());
assertCommit(c1, rw.next());
assertCommit(b, rw.next());
assertCommit(a, rw.next());
assertNull(rw.next());
}
@Test
public void testSort_TOPO_MultipleLinesOfHistory() throws Exception {
final RevCommit a1 = commit();
final RevCommit b1 = commit(a1);
final RevCommit a2 = commit(a1, b1);
final RevCommit b2 = commit(b1);
final RevCommit b3 = commit(b1);
final RevCommit a3 = commit(a2, b2);
final RevCommit a4 = commit(a3, b3);
rw.sort(RevSort.TOPO);
markStart(a4);
assertCommit(a4, rw.next());
assertCommit(b3, rw.next());
assertCommit(a3, rw.next());
assertCommit(b2, rw.next());
assertCommit(a2, rw.next());
assertCommit(b1, rw.next());
assertCommit(a1, rw.next());
assertNull(rw.next());
}
@Test
public void testSort_TOPO_REVERSE_MultipleLinesOfHistory()
throws Exception {
final RevCommit a1 = commit();
final RevCommit b1 = commit(a1);
final RevCommit a2 = commit(a1, b1);
final RevCommit b2 = commit(b1);
final RevCommit b3 = commit(b1);
final RevCommit a3 = commit(a2, b2);
final RevCommit a4 = commit(a3, b3);
rw.sort(RevSort.TOPO);
rw.sort(RevSort.REVERSE, true);
markStart(a4);
assertCommit(a1, rw.next());
assertCommit(b1, rw.next());
assertCommit(a2, rw.next());
assertCommit(b2, rw.next());
assertCommit(a3, rw.next());
assertCommit(b3, rw.next());
assertCommit(a4, rw.next());
assertNull(rw.next());
}
@Test
public void testSort_TOPO_ParentOfMultipleStartChildren() throws Exception {
final RevCommit a = commit();
final RevCommit b = commit(a);
final RevCommit c = commit(a);
final RevCommit d1 = commit(a);
final RevCommit d2 = commit(d1);
final RevCommit e = commit(a);
rw.sort(RevSort.TOPO);
markStart(b);
markStart(c);
markStart(d2);
markStart(e);
assertCommit(e, rw.next());
assertCommit(d2, rw.next());
assertCommit(d1, rw.next());
assertCommit(c, rw.next());
assertCommit(b, rw.next());
assertCommit(a, rw.next());
assertNull(rw.next());
}
@Test
public void testSort_TOPO_Uninteresting() throws Exception {
final RevCommit a1 = commit();
final RevCommit a2 = commit(a1);
final RevCommit a3 = commit(a2);
final RevCommit b = commit(a1);
final RevCommit a4 = commit(a3, b);
rw.sort(RevSort.TOPO);
markStart(a4);
markUninteresting(a2);
assertCommit(a4, rw.next());
assertCommit(b, rw.next());
assertCommit(a3, rw.next());
assertNull(rw.next());
}
} }

2
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevObject.java

@ -151,7 +151,7 @@ public abstract class RevObject extends ObjectIdOwnerMap.Entry {
* buffer to append a debug description of core RevFlags onto. * buffer to append a debug description of core RevFlags onto.
*/ */
protected void appendCoreFlags(StringBuilder s) { protected void appendCoreFlags(StringBuilder s) {
s.append((flags & RevWalk.TOPO_QUEUED) != 0 ? 'o' : '-'); s.append((flags & RevWalk.TOPO_DELAY) != 0 ? 'o' : '-');
s.append((flags & RevWalk.TEMP_MARK) != 0 ? 't' : '-'); s.append((flags & RevWalk.TEMP_MARK) != 0 ? 't' : '-');
s.append((flags & RevWalk.REWRITE) != 0 ? 'r' : '-'); s.append((flags & RevWalk.REWRITE) != 0 ? 'r' : '-');
s.append((flags & RevWalk.UNINTERESTING) != 0 ? 'u' : '-'); s.append((flags & RevWalk.UNINTERESTING) != 0 ? 'u' : '-');

8
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java

@ -125,11 +125,11 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
/** /**
* Temporary mark for use within {@link TopoSortGenerator}. * Temporary mark for use within {@link TopoSortGenerator}.
* <p> * <p>
* This mark indicates the commit has been queued for emission in * This mark indicates the commit could not produce when it wanted to, as at
* {@link TopoSortGenerator} and can be produced. This mark is removed when * least one child was behind it. Commits with this flag are delayed until
* the commit has been produced. * all children have been output first.
*/ */
static final int TOPO_QUEUED = 1 << 5; static final int TOPO_DELAY = 1 << 5;
/** Number of flag bits we keep internal for our own use. See above flags. */ /** Number of flag bits we keep internal for our own use. See above flags. */
static final int RESERVED_FLAGS = 6; static final int RESERVED_FLAGS = 6;

34
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java

@ -17,7 +17,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
/** Sorts commits in topological order. */ /** Sorts commits in topological order. */
class TopoSortGenerator extends Generator { class TopoSortGenerator extends Generator {
private static final int TOPO_QUEUED = RevWalk.TOPO_QUEUED; private static final int TOPO_DELAY = RevWalk.TOPO_DELAY;
private final FIFORevQueue pending; private final FIFORevQueue pending;
@ -47,16 +47,12 @@ class TopoSortGenerator extends Generator {
if (c == null) { if (c == null) {
break; break;
} }
if ((c.flags & TOPO_QUEUED) == 0) {
for (RevCommit p : c.parents) { for (RevCommit p : c.parents) {
p.inDegree++; p.inDegree++;
if (firstParent) { if (firstParent) {
break; break;
} }
} }
}
c.flags |= TOPO_QUEUED;
pending.add(c); pending.add(c);
} }
} }
@ -75,42 +71,34 @@ class TopoSortGenerator extends Generator {
RevCommit next() throws MissingObjectException, RevCommit next() throws MissingObjectException,
IncorrectObjectTypeException, IOException { IncorrectObjectTypeException, IOException {
for (;;) { for (;;) {
RevCommit c = pending.next(); final RevCommit c = pending.next();
if (c == null) { if (c == null)
return null; return null;
}
if (c.inDegree > 0) { if (c.inDegree > 0) {
// At least one of our children is missing. We delay // At least one of our children is missing. We delay
// production until all of our children are output. // production until all of our children are output.
// //
c.flags |= TOPO_DELAY;
continue; continue;
} }
if ((c.flags & TOPO_QUEUED) == 0) { // All of our children have already produced,
// c is a parent that already produced or a parent that // so it is OK for us to produce now as well.
// was never in the priority queue and should never produce.
// //
continue;
}
for (RevCommit p : c.parents) { for (RevCommit p : c.parents) {
if (--p.inDegree == 0 && (p.flags & TOPO_QUEUED) != 0) { if (--p.inDegree == 0 && (p.flags & TOPO_DELAY) != 0) {
// The parent has no unproduced interesting children. unpop // This parent tried to come before us, but we are
// the parent so it goes right behind this child. This means // his last child. unpop the parent so it goes right
// that this parent commit may appear in "pending" more than // behind this child.
// once, but this is safe since upon the second and
// subsequent iterations with this commit, it will no longer
// have TOPO_QUEUED set, and thus will be skipped.
// //
p.flags &= ~TOPO_DELAY;
pending.unpop(p); pending.unpop(p);
} }
if (firstParent) { if (firstParent) {
break; break;
} }
} }
c.flags &= ~TOPO_QUEUED;
return c; return c;
} }
} }

Loading…
Cancel
Save