diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java index 35460a7c4..2c46f8eb4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java @@ -1,5 +1,6 @@ /* - * Copyright (C) 2008, Shawn O. Pearce + * Copyright (C) 2008, Shawn O. Pearce , + * Copyright (C) 2013, Gustaf Lundh * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -50,10 +51,22 @@ /** A queue of commits sorted by commit time order. */ public class DateRevQueue extends AbstractRevQueue { + private static final int REBUILD_INDEX_COUNT = 1000; + private Entry head; private Entry free; + private int inQueue; + + private int sinceLastIndex; + + private Entry[] index; + + private int first; + + private int last = -1; + /** Create an empty date queue. */ public DateRevQueue() { super(); @@ -70,10 +83,36 @@ public DateRevQueue() { } public void add(final RevCommit c) { + sinceLastIndex++; + if (++inQueue > REBUILD_INDEX_COUNT + && sinceLastIndex > REBUILD_INDEX_COUNT) + buildIndex(); + Entry q = head; final long when = c.commitTime; + + if (first <= last && index[first].commit.commitTime > when) { + int low = first, high = last; + while (low <= high) { + int mid = (low + high) >>> 1; + int t = index[mid].commit.commitTime; + if (t < when) + high = mid - 1; + else if (t > when) + low = mid + 1; + else { + low = mid - 1; + break; + } + } + low = Math.min(low, high); + while (low >= first && when == index[low].commit.commitTime) + --low; + q = index[low]; + } + final Entry n = newEntry(c); - if (q == null || when > q.commit.commitTime) { + if (q == null || (q == head && when > q.commit.commitTime)) { n.next = q; head = n; } else { @@ -91,11 +130,28 @@ public RevCommit next() { final Entry q = head; if (q == null) return null; + + if (index != null && q == index[first]) + index[first++] = null; + inQueue--; + head = q.next; freeEntry(q); return q.commit; } + private void buildIndex() { + sinceLastIndex = 0; + first = 0; + index = new Entry[inQueue / 100 + 1]; + int qi = 0, ii = 0; + for (Entry q = head; q != null; q = q.next) { + if (++qi % 100 == 0) + index[ii++] = q; + } + last = ii - 1; + } + /** * Peek at the next commit, without removing it. * @@ -108,6 +164,10 @@ public RevCommit peek() { public void clear() { head = null; free = null; + index = null; + inQueue = 0; + sinceLastIndex = 0; + last = -1; } boolean everbodyHasFlag(final int f) {