blob: 0efcc359bac72e62399dc62e9b5990fd1579396b [file]
/*
* Copyright (c) 2026 Vector Informatik GmbH
*
* 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.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
final class TopoInDegreePhase extends TopoPhase {
private final TopoExplorePhase explorePhase;
private final AbstractCommitRewriter rewriter;
private final RevFlag topoSeen;
private final AbstractRevQueue ready;
private int minGeneration = Constants.COMMIT_GENERATION_UNKNOWN;
TopoInDegreePhase(RevWalk walker, TopoExplorePhase explorePhase,
boolean needsRewrite) {
super(walker, "INDEGREE"); //$NON-NLS-1$
this.explorePhase = explorePhase;
this.rewriter = needsRewrite ? new TopoRewriter() : null;
this.topoSeen = walker.newFlag("TOPO_SEEN"); //$NON-NLS-1$
this.ready = RevWalk.newDateRevQueue(walker.isFirstParent());
}
void initialize(AbstractRevQueue p) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
List<RevCommit> roots = new ArrayList<>();
for (RevCommit root = p.next(); root != null; root = p.next()) {
roots.add(root);
checkUpdateMinGeneration(root);
explorePhase.enqueue(root);
enqueue(root);
}
calculateInDegrees(minGeneration);
for (RevCommit root : roots) {
checkAddReady(root);
}
}
void calculateInDegrees(int cutoff) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
RevCommit c;
while ((c = tryRemove(cutoff)) != null) {
// Only perform inDegree calculation on commits, whose history has
// been rewritten
c = rewriteIfNeeded(c);
visitChild(c);
}
}
private RevCommit rewriteIfNeeded(RevCommit c)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
explorePhase.explore(c.getEffectiveGeneration());
if (rewriter != null) {
return rewriter.rewriteParents(c);
}
return c;
}
private void visitChild(RevCommit c) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
for (RevCommit p : c.getParents()) {
if (p.has(RevFlag.UNINTERESTING) || p.has(RevFlag.UNSHALLOW)) {
continue;
}
p.inDegree++;
enqueue(p);
if (walker.isFirstParent()) {
break;
}
}
}
RevCommit nextReady() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
RevCommit c = ready.next();
if (c == null) {
return null;
}
expand(c);
return c;
}
@Override
int getAllocatedFlags() {
return super.getAllocatedFlags() | topoSeen.mask;
}
private void expand(RevCommit c) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
for (RevCommit p : c.getParents()) {
if (p.has(RevFlag.UNINTERESTING)) {
continue;
}
if (checkUpdateMinGeneration(p)) {
calculateInDegrees(minGeneration);
}
p.inDegree--;
checkAddReady(p);
if (walker.isFirstParent()) {
return;
}
}
}
private void checkAddReady(RevCommit p) {
if (p.inDegree == 0 && !p.has(topoSeen)) {
p.add(topoSeen);
ready.add(p);
}
}
private boolean checkUpdateMinGeneration(RevCommit c)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
RevWalkUtils.ensureHeadersParsed(c, walker);
int generation = c.getEffectiveGeneration();
if (generation < minGeneration) {
minGeneration = generation;
return true;
}
return false;
}
private class TopoRewriter extends AbstractCommitRewriter {
TopoRewriter() {
super(walker.isFirstParent());
}
@Override
void applyFilterToParents(RevCommit c) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
for (RevCommit p : c.getParents()) {
if ((p.flags & RevWalk.TREE_REV_FILTER_APPLIED) == 0) {
RevWalkUtils.ensureHeadersParsed(p, walker);
explorePhase.explore(p.getEffectiveGeneration());
}
}
}
}
}