]> source.dussan.org Git - jgit.git/commitdiff
Introduce a PriorityQueue sorting RevCommits by commit timestamp 40/194140/36
authorLuca Milanesio <luca.milanesio@gmail.com>
Mon, 13 Jun 2022 22:09:55 +0000 (23:09 +0100)
committerMatthias Sohn <matthias.sohn@sap.com>
Fri, 19 Jan 2024 00:28:04 +0000 (01:28 +0100)
The DateRevQueue uses a tailor-made algorithm to keep
RevCommits sorted by reversed commit timestamp, which has a O(n*n/2)
complexity and caused the explosion of the Git fetch times to
tens of seconds.

The standard Java PriorityQueue provides a O(n*log(n)) complexity
and scales much better with the increase of the number of
RevCommits.

Introduce a new implementation DateRevPriorityQueue of the DateRevQueue
based on PriorityQueue.

Enable usage of the new DateRevPriorityQueue implementation by setting
the system property REVWALK_USE_PRIORITY_QUEUE=true. By default the old
implementation DateRevQueue is used.

Benchmark results:
```
(numCommits)  (usePriorityQueue)  Mode  Cnt     Score Error  Units
           5                true  avgt   10    39,4 ±   6,1  ns/op
           5               false  avgt   10    14,1 ±   2,2  ns/op
          10                true  avgt   10    29,7 ±   3,5  ns/op
          10               false  avgt   10    13,2 ±   2,0  ns/op
          50                true  avgt   10    50,4 ±   5,3  ns/op
          50               false  avgt   10    18,6 ±   0,2  ns/op
         100                true  avgt   10    58,3 ±   5,0  ns/op
         100               false  avgt   10    20,5 ±   0,8  ns/op
         500                true  avgt   10    51,7 ±   2,6  ns/op
         500               false  avgt   10    43,3 ±   0,5  ns/op
        1000                true  avgt   10    49,2 ±   2,4  ns/op
        1000               false  avgt   10    62,7 ±   0,2  ns/op
        5000                true  avgt   10    48,8 ±   1,5  ns/op
        5000               false  avgt   10   228,3 ±   0,5  ns/op
       10000                true  avgt   10    44,2 ±   0,9  ns/op
       10000               false  avgt   10   377,6 ±   2,7  ns/op
       50000                true  avgt   10    50,3 ±   1,6  ns/op
       50000               false  avgt   10   637,0 ± 111,8  ns/op
      100000                true  avgt   10    61,8 ±   4,4  ns/op
      100000               false  avgt   10   965,1 ± 268,0  ns/op
      500000                true  avgt   10   127,2 ±   7,9  ns/op
      500000               false  avgt   10  9610,2 ± 184,8  ns/op
```

Memory allocation results:
```
Number of commits loaded: 850 000
Custom implementation: 378 245 120 Bytes
Priority queue implementation: 340 495 616 Bytes
```

Bug: 580137
Change-Id: I8b33df6e9ee88933098ecc81ce32bdb189715041
Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com>
Documentation/config-options.md
org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/revwalk/DateRevQueueBenchmark.java [new file with mode: 0644]
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevPriorityQueueTest.java [new file with mode: 0644]
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCarryFlagsTest.java
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevPriorityQueue.java [new file with mode: 0644]
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevQueue.java
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java

index 36b25c8e366c01b58cc7b99856aa2938eed65304..9075a5903de283fb9c01115a8313e9330b460740 100644 (file)
@@ -123,4 +123,10 @@ Proxy configuration uses the standard Java mechanisms via class `java.net.ProxyS
 
 |  option | default | git option | description |
 |---------|---------|------------|-------------|
-| `repack.packKeptObjects` | `true` when `pack.buildBitmaps` is set, `false` otherwise | &#x2705; | Include objects in packs locked by a `.keep` file when repacking. |
\ No newline at end of file
+| `repack.packKeptObjects` | `true` when `pack.buildBitmaps` is set, `false` otherwise | &#x2705; | Include objects in packs locked by a `.keep` file when repacking. |
+
+## Java System Properties
+
+| system property | default | description |
+|-----------------|---------|-------------|
+| `REVWALK_USE_PRIORITY_QUEUE` | `false` | If set to `true` `RevWalk` uses `DateRevPriorityQueue` which is faster, otherwise it uses the old `DateRevQueue`. |
diff --git a/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/revwalk/DateRevQueueBenchmark.java b/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/revwalk/DateRevQueueBenchmark.java
new file mode 100644 (file)
index 0000000..71075a8
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023, GerritForge Ltd
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.revwalk;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FileUtils;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+@State(Scope.Thread)
+public class DateRevQueueBenchmark {
+
+       ThreadLocalRandom commitsIndex = ThreadLocalRandom.current();
+
+       @State(Scope.Benchmark)
+       public static class BenchmarkState {
+
+               @Param({ "5", "10", "50", "100", "500", "1000", "5000", "10000",
+                               "50000", "100000", "500000" })
+               int numCommits;
+
+               @Param({ "true", "false" })
+               boolean usePriorityQueue;
+
+               int low, count;
+
+               RevCommit[] commits = new RevCommit[numCommits];
+
+               private Path testDir;
+
+               private TestRepository<Repository> repoUtil;
+
+               DateRevQueue queue;
+
+               @Setup
+               public void setupBenchmark() throws Exception {
+                       testDir = Files.createTempDirectory("testrepos");
+                       String repoName = "commits-" + numCommits + "-usePriorityQueue-"
+                                       + usePriorityQueue;
+                       Path workDir = testDir.resolve(repoName);
+                       Git git = Git.init().setDirectory(workDir.toFile()).call();
+                       repoUtil = new TestRepository<>(git.getRepository());
+
+                       RevCommit parent = repoUtil.commit().create();
+                       commits = new RevCommit[numCommits];
+                       commits[0] = parent;
+                       for (int i = 1; i < numCommits; i++) {
+                               parent = repoUtil.parseBody(repoUtil.commit(i, parent));
+                               commits[i] = parent;
+                               if (i % 10000 == 0) {
+                                       System.out.println(" " + i + " done");
+                               }
+                       }
+
+                       if (usePriorityQueue) {
+                               queue = new DateRevPriorityQueue(false);
+                       } else {
+                               queue = new DateRevQueue(false);
+                       }
+
+                       low = 9 * numCommits / 10;
+                       ThreadLocalRandom random = ThreadLocalRandom.current();
+                       // add 90% * numCommits commits, benchmark adding commits from
+                       // 90-100%
+                       for (int i = 0; i < low; i++) {
+                               RevCommit commit = commits[random.nextInt(numCommits)];
+                               queue.add(commit);
+                               ++count;
+                       }
+               }
+
+               @TearDown(Level.Invocation)
+               public void check() {
+                       // if queue is full remove 10% of its entries
+                       if (++count == numCommits) {
+                               do {
+                                       queue.next();
+                               } while (--count > low);
+                       }
+               }
+
+               @TearDown
+               public void teardown() throws IOException {
+                       repoUtil.close();
+                       FileUtils.delete(testDir.toFile(),
+                                       FileUtils.RECURSIVE | FileUtils.RETRY);
+               }
+       }
+
+       @Benchmark
+       @BenchmarkMode({ Mode.AverageTime })
+       @OutputTimeUnit(TimeUnit.NANOSECONDS)
+       @Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+       @Measurement(iterations = 10, time = 10, timeUnit = TimeUnit.SECONDS)
+       public void testDataRevQueue(BenchmarkState state) throws Exception {
+               RevCommit commit = state.commits[commitsIndex
+                               .nextInt(state.numCommits)];
+               state.queue.add(commit);
+       }
+
+       public static void main(String[] args) throws RunnerException {
+               Options opt = new OptionsBuilder()
+                               .include(DateRevQueueBenchmark.class.getSimpleName()).forks(1)
+                               .jvmArgs("-ea").build();
+               new Runner(opt).run();
+       }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevPriorityQueueTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevPriorityQueueTest.java
new file mode 100644 (file)
index 0000000..369e2fa
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023, GerritForge Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.revwalk;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+public class DateRevPriorityQueueTest extends RevQueueTestCase<DateRevPriorityQueue> {
+       @Override
+       protected DateRevPriorityQueue create() {
+               return new DateRevPriorityQueue();
+       }
+
+       @Override
+       @Test
+       public void testEmpty() throws Exception {
+               super.testEmpty();
+               assertNull(q.peek());
+               assertEquals(Generator.SORT_COMMIT_TIME_DESC, q.outputType());
+       }
+
+       @Test
+       public void testCloneEmpty() throws Exception {
+               q = new DateRevPriorityQueue(AbstractRevQueue.EMPTY_QUEUE);
+               assertNull(q.next());
+       }
+
+       @Test
+       public void testInsertOutOfOrder() throws Exception {
+               final RevCommit a = parseBody(commit());
+               final RevCommit b = parseBody(commit(10, a));
+               final RevCommit c1 = parseBody(commit(5, b));
+               final RevCommit c2 = parseBody(commit(-50, b));
+
+               q.add(c2);
+               q.add(a);
+               q.add(b);
+               q.add(c1);
+
+               assertCommit(c1, q.next());
+               assertCommit(b, q.next());
+               assertCommit(a, q.next());
+               assertCommit(c2, q.next());
+               assertNull(q.next());
+       }
+
+       @Test
+       public void testInsertTie() throws Exception {
+               final RevCommit a = parseBody(commit());
+               final RevCommit b = parseBody(commit(0, a));
+               final RevCommit c = parseBody(commit(0, b));
+
+               {
+                       q = create();
+                       q.add(a);
+                       q.add(b);
+                       q.add(c);
+
+                       assertCommit(a, q.next());
+                       assertCommit(b, q.next());
+                       assertCommit(c, q.next());
+                       assertNull(q.next());
+               }
+               {
+                       q = create();
+                       q.add(c);
+                       q.add(b);
+                       q.add(a);
+
+                       assertCommit(c, q.next());
+                       assertCommit(b, q.next());
+                       assertCommit(a, q.next());
+                       assertNull(q.next());
+               }
+       }
+
+       @Test
+       public void testCloneFIFO() throws Exception {
+               final RevCommit a = parseBody(commit());
+               final RevCommit b = parseBody(commit(200, a));
+               final RevCommit c = parseBody(commit(200, b));
+
+               final FIFORevQueue src = new FIFORevQueue();
+               src.add(a);
+               src.add(b);
+               src.add(c);
+
+               q = new DateRevPriorityQueue(src);
+               assertFalse(q.everbodyHasFlag(RevWalk.UNINTERESTING));
+               assertFalse(q.anybodyHasFlag(RevWalk.UNINTERESTING));
+               assertCommit(c, q.peek());
+               assertCommit(c, q.peek());
+
+               assertCommit(c, q.next());
+               assertCommit(b, q.next());
+               assertCommit(a, q.next());
+               assertNull(q.next());
+       }
+}
index 8c25e059867ecfc6d2599a471f112dc00067983c..529d5a9f096eecba7629fd3dfb2c65439f76651f 100644 (file)
@@ -39,7 +39,7 @@ public class RevWalkCarryFlagsTest extends RevWalkTestCase {
        /**
         * Similar to {@link #testRevWalkCarryUninteresting_fastClock()} but the
         * last merge commit is created so fast that he has the same creationdate as
-        * the previous commit. This will cause the underlying {@link DateRevQueue}
+        * the previous commit. This will cause the underlying {@link AbstractRevQueue}
         * is not able to sort the commits in a way matching the topology. A parent
         * (one of the commits which are merged) is handled before the child (the
         * merge commit). This makes carrying over flags more complicated
index 3ac1fde6f0f6559eee833c970fc96fa8bd17ac6e..45a67947f1dcf9b344b6956e9072d62d7ffb16ee 100644 (file)
@@ -551,6 +551,7 @@ nothingToPush=Nothing to push.
 notMergedExceptionMessage=Branch was not deleted as it has not been merged yet; use the force option to delete it anyway
 notShallowedUnshallow=The server sent a unshallow for a commit that wasn''t marked as shallow: {0}
 noXMLParserAvailable=No XML parser available.
+nullRevCommit=RevCommit is null
 numberDoesntFit=Number doesn't fit in a single byte
 objectAtHasBadZlibStream=Object at {0} in {1} has bad zlib stream
 objectIsCorrupt=Object {0} is corrupt: {1}
index 3b5cc3d1f5244034e4583eed9f9e5116f0852bd9..c7cad43d960f3727451740d5dc0d685cf7906ceb 100644 (file)
@@ -580,6 +580,7 @@ public class JGitText extends TranslationBundle {
        /***/ public String notMergedExceptionMessage;
        /***/ public String notShallowedUnshallow;
        /***/ public String noXMLParserAvailable;
+       /***/ public String nullRevCommit;
        /***/ public String numberDoesntFit;
        /***/ public String objectAtHasBadZlibStream;
        /***/ public String objectIsCorrupt;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevPriorityQueue.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DateRevPriorityQueue.java
new file mode 100644 (file)
index 0000000..233dd64
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2023, GerritForge Ltd
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.revwalk;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+
+import java.io.IOException;
+import java.util.Comparator;
+import java.util.PriorityQueue;
+
+/**
+ * A queue of commits sorted by commit time order using a Java PriorityQueue.
+ * For the commits with the same commit time insertion order will be preserved.
+ */
+class DateRevPriorityQueue extends DateRevQueue {
+       private PriorityQueue<RevCommitEntry> queue;
+
+       private final AtomicInteger sequence = new AtomicInteger(1);
+
+       /**
+        * Create an empty queue of commits sorted by commit time order.
+        */
+       public DateRevPriorityQueue() {
+               this(false);
+       }
+
+       /**
+        * Create an empty queue of commits sorted by commit time order.
+        *
+        * @param firstParent
+        *            treat first element as a parent
+        */
+       DateRevPriorityQueue(boolean firstParent) {
+               super(firstParent);
+               initPriorityQueue();
+       }
+
+       private void initPriorityQueue() {
+               sequence.set(1);
+               queue = new PriorityQueue<>(Comparator.comparingInt(
+                                               (RevCommitEntry ent) -> ent.getEntry().getCommitTime())
+                               .reversed()
+                               .thenComparingInt(RevCommitEntry::getInsertSequenceNumber));
+       }
+
+    DateRevPriorityQueue(Generator s) throws MissingObjectException,
+                       IncorrectObjectTypeException, IOException {
+               this(s.firstParent);
+               for (;;) {
+                       final RevCommit c = s.next();
+                       if (c == null) {
+                               break;
+                       }
+                       add(c);
+               }
+       }
+
+       @Override
+       public void add(RevCommit c) {
+               // PriorityQueue does not accept null values. To keep the same behaviour
+               // do the same check and throw the same exception before creating entry
+               if (c == null) {
+                       throw new NullPointerException(JGitText.get().nullRevCommit);
+               }
+               queue.add(new RevCommitEntry(sequence.getAndIncrement(), c));
+       }
+
+       @Override
+       public RevCommit next() {
+               RevCommitEntry entry = queue.poll();
+               return entry == null ? null : entry.getEntry();
+       }
+
+       /**
+        * Peek at the next commit, without removing it.
+        *
+        * @return the next available commit; null if there are no commits left.
+        */
+       @Override
+       public @Nullable RevCommit peek() {
+               RevCommitEntry entry = queue.peek();
+               return entry == null ? null : entry.getEntry();
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void clear() {
+               sequence.set(1);
+               queue.clear();
+       }
+
+       @Override
+       boolean everbodyHasFlag(int f) {
+               return queue.stream().map(RevCommitEntry::getEntry)
+                               .noneMatch(c -> (c.flags & f) == 0);
+       }
+
+       @Override
+       boolean anybodyHasFlag(int f) {
+               return queue.stream().map(RevCommitEntry::getEntry)
+                               .anyMatch(c -> (c.flags & f) != 0);
+       }
+
+       @Override
+       int outputType() {
+               return outputType | SORT_COMMIT_TIME_DESC;
+       }
+
+       @Override
+       public String toString() {
+               final StringBuilder s = new StringBuilder();
+               for (RevCommitEntry e : queue) {
+                       describe(s, e.getEntry());
+               }
+               return s.toString();
+       }
+
+       private static class RevCommitEntry {
+               private final int insertSequenceNumber;
+
+               private final RevCommit entry;
+
+               public RevCommitEntry(int insertSequenceNumber, RevCommit entry) {
+                       this.insertSequenceNumber = insertSequenceNumber;
+                       this.entry = entry;
+               }
+
+               public int getInsertSequenceNumber() {
+                       return insertSequenceNumber;
+               }
+
+               public RevCommit getEntry() {
+                       return entry;
+               }
+       }
+}
index 0cabf07057a2c5f018c823f01717a2b39beffa9c..905dcb62ad89642ef4313f5bd7cce5b87caf106c 100644 (file)
@@ -8,11 +8,11 @@
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
-
 package org.eclipse.jgit.revwalk;
 
 import java.io.IOException;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
@@ -36,11 +36,17 @@ public class DateRevQueue extends AbstractRevQueue {
 
        private int last = -1;
 
-       /** Create an empty date queue. */
+       /** Create an empty DateRevQueue. */
        public DateRevQueue() {
                super(false);
        }
 
+       /**
+        * Create an empty DateRevQueue.
+        *
+        * @param firstParent
+        *            treat first element as a parent
+        */
        DateRevQueue(boolean firstParent) {
                super(firstParent);
        }
@@ -56,7 +62,6 @@ public class DateRevQueue extends AbstractRevQueue {
                }
        }
 
-       /** {@inheritDoc} */
        @Override
        public void add(RevCommit c) {
                sinceLastIndex++;
@@ -102,7 +107,6 @@ public class DateRevQueue extends AbstractRevQueue {
                }
        }
 
-       /** {@inheritDoc} */
        @Override
        public RevCommit next() {
                final Entry q = head;
@@ -135,11 +139,10 @@ public class DateRevQueue extends AbstractRevQueue {
         *
         * @return the next available commit; null if there are no commits left.
         */
-       public RevCommit peek() {
+       public @Nullable RevCommit peek() {
                return head != null ? head.commit : null;
        }
 
-       /** {@inheritDoc} */
        @Override
        public void clear() {
                head = null;
@@ -173,7 +176,6 @@ public class DateRevQueue extends AbstractRevQueue {
                return outputType | SORT_COMMIT_TIME_DESC;
        }
 
-       /** {@inheritDoc} */
        @Override
        public String toString() {
                final StringBuilder s = new StringBuilder();
index 3737c6b67b2affaed24c282040ebf6d2cd0105d3..2fb3a60690add555cd7ec3e0e6c988ba1f340867 100644 (file)
@@ -21,6 +21,7 @@ import java.util.Collection;
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.annotations.Nullable;
@@ -236,7 +237,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
                idBuffer = new MutableObjectId();
                objects = new ObjectIdOwnerMap<>();
                roots = new ArrayList<>();
-               queue = new DateRevQueue(false);
+               queue = newDateRevQueue(false);
                pending = new StartGenerator(this);
                sorting = EnumSet.of(RevSort.NONE);
                filter = RevFilter.ALL;
@@ -245,6 +246,30 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
                commitGraph = null;
        }
 
+       static AbstractRevQueue newDateRevQueue(boolean firstParent) {
+               if(usePriorityQueue()) {
+                       return new DateRevPriorityQueue(firstParent);
+               }
+
+               return new DateRevQueue(firstParent);
+       }
+
+       static DateRevQueue newDateRevQueue(Generator g) throws IOException {
+               if(usePriorityQueue()) {
+                       return new DateRevPriorityQueue(g);
+               }
+
+               return new DateRevQueue(g);
+       }
+
+       @SuppressWarnings("boxing")
+       private static boolean usePriorityQueue() {
+               return Optional
+                               .ofNullable(System.getProperty("REVWALK_USE_PRIORITY_QUEUE")) //$NON-NLS-1$
+                                                       .map(Boolean::parseBoolean)
+                                                       .orElse(false);
+       }
+
        /**
         * Get the reader this walker is using to load objects.
         *
@@ -848,7 +873,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
                assertNotStarted();
                assertNoCommitsMarkedStart();
                firstParent = enable;
-               queue = new DateRevQueue(firstParent);
+               queue = newDateRevQueue(firstParent);
                pending = new StartGenerator(this);
        }
 
@@ -1566,7 +1591,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
                }
 
                roots.clear();
-               queue = new DateRevQueue(firstParent);
+               queue = newDateRevQueue(firstParent);
                pending = new StartGenerator(this);
        }
 
@@ -1587,7 +1612,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
                firstParent = false;
                objects.clear();
                roots.clear();
-               queue = new DateRevQueue(firstParent);
+               queue = newDateRevQueue(firstParent);
                pending = new StartGenerator(this);
                shallowCommitsInitialized = false;
        }
index a79901ca10e8f67861fe27c1d122ccf5d47e57da..414af3048693dedb078a2fc184a47b4b29a37e56 100644 (file)
@@ -93,10 +93,11 @@ class StartGenerator extends Generator {
 
                final DateRevQueue pending;
                int pendingOutputType = 0;
-               if (q instanceof DateRevQueue)
-                       pending = (DateRevQueue)q;
-               else
-                       pending = new DateRevQueue(q);
+               if (q instanceof DateRevQueue) {
+                       pending = (DateRevQueue) q;
+               } else {
+                       pending = RevWalk.newDateRevQueue(q);
+               }
                if (tf != TreeFilter.ALL) {
                        int rewriteFlag;
                        if (w.getRewriteParents()) {