FullConnectivityChecker.java
- /*
- * Copyright (c) 2019, Google LLC 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
- * http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- package org.eclipse.jgit.internal.transport.connectivity;
- import java.io.IOException;
- import java.util.Set;
- import org.eclipse.jgit.errors.MissingObjectException;
- import org.eclipse.jgit.internal.JGitText;
- import org.eclipse.jgit.lib.Constants;
- import org.eclipse.jgit.lib.ObjectId;
- import org.eclipse.jgit.lib.ObjectIdSubclassMap;
- import org.eclipse.jgit.lib.ProgressMonitor;
- import org.eclipse.jgit.revwalk.ObjectWalk;
- import org.eclipse.jgit.revwalk.RevBlob;
- import org.eclipse.jgit.revwalk.RevCommit;
- import org.eclipse.jgit.revwalk.RevFlag;
- import org.eclipse.jgit.revwalk.RevObject;
- import org.eclipse.jgit.revwalk.RevSort;
- import org.eclipse.jgit.revwalk.RevTree;
- import org.eclipse.jgit.transport.ConnectivityChecker;
- import org.eclipse.jgit.transport.ReceiveCommand;
- import org.eclipse.jgit.transport.ReceiveCommand.Result;
- /**
- * A connectivity checker that uses the entire reference database to perform
- * reachability checks when checking the connectivity of objects. If
- * info.isCheckObjects() is set it will also check that objects referenced by
- * deltas are either provided or reachable as well.
- */
- public final class FullConnectivityChecker implements ConnectivityChecker {
- @Override
- public void checkConnectivity(ConnectivityCheckInfo connectivityCheckInfo,
- Set<ObjectId> haves, ProgressMonitor pm)
- throws MissingObjectException, IOException {
- pm.beginTask(JGitText.get().countingObjects,
- ProgressMonitor.UNKNOWN);
- try (ObjectWalk ow = new ObjectWalk(connectivityCheckInfo.getRepository())) {
- if (!markStartAndKnownNodes(connectivityCheckInfo, ow, haves,
- pm)) {
- return;
- }
- checkCommitTree(connectivityCheckInfo, ow, pm);
- checkObjects(connectivityCheckInfo, ow, pm);
- } finally {
- pm.endTask();
- }
- }
- /**
- * @param connectivityCheckInfo
- * Source for connectivity check.
- * @param ow
- * Walk which can also check blobs.
- * @param haves
- * Set of references known for client.
- * @param pm
- * Monitor to publish progress to.
- * @return true if at least one new node was marked.
- * @throws IOException
- * an error occurred during connectivity checking.
- */
- private boolean markStartAndKnownNodes(
- ConnectivityCheckInfo connectivityCheckInfo,
- ObjectWalk ow,
- Set<ObjectId> haves, ProgressMonitor pm)
- throws IOException {
- boolean markTrees = connectivityCheckInfo
- .isCheckObjects()
- && !connectivityCheckInfo.getParser().getBaseObjectIds()
- .isEmpty();
- if (connectivityCheckInfo.isCheckObjects()) {
- ow.sort(RevSort.TOPO);
- if (!connectivityCheckInfo.getParser().getBaseObjectIds()
- .isEmpty()) {
- ow.sort(RevSort.BOUNDARY, true);
- }
- }
- boolean hasInteresting = false;
- for (ReceiveCommand cmd : connectivityCheckInfo.getCommands()) {
- if (cmd.getResult() != Result.NOT_ATTEMPTED) {
- continue;
- }
- if (cmd.getType() == ReceiveCommand.Type.DELETE) {
- continue;
- }
- if (haves.contains(cmd.getNewId())) {
- continue;
- }
- ow.markStart(ow.parseAny(cmd.getNewId()));
- pm.update(1);
- hasInteresting = true;
- }
- if (!hasInteresting) {
- return false;
- }
- for (ObjectId have : haves) {
- RevObject o = ow.parseAny(have);
- ow.markUninteresting(o);
- pm.update(1);
- if (markTrees) {
- o = ow.peel(o);
- if (o instanceof RevCommit) {
- o = ((RevCommit) o).getTree();
- }
- if (o instanceof RevTree) {
- ow.markUninteresting(o);
- }
- }
- }
- return true;
- }
- /**
- * @param connectivityCheckInfo
- * Source for connectivity check.
- * @param ow
- * Walk which can also check blobs.
- * @param pm
- * Monitor to publish progress to.
- * @throws IOException
- * an error occurred during connectivity checking.
- */
- private void checkCommitTree(ConnectivityCheckInfo connectivityCheckInfo,
- ObjectWalk ow,
- ProgressMonitor pm) throws IOException {
- RevCommit c;
- ObjectIdSubclassMap<ObjectId> newObjectIds = connectivityCheckInfo
- .getParser()
- .getNewObjectIds();
- while ((c = ow.next()) != null) {
- pm.update(1);
- if (connectivityCheckInfo.isCheckObjects()
- && !c.has(RevFlag.UNINTERESTING)
- && !newObjectIds.contains(c)) {
- throw new MissingObjectException(c, Constants.TYPE_COMMIT);
- }
- }
- }
- /**
- * @param connectivityCheckInfo
- * Source for connectivity check.
- * @param ow
- * Walk which can also check blobs.
- * @param pm
- * Monitor to publish progress to.
- * @throws IOException
- * an error occurred during connectivity checking.
- *
- */
- private void checkObjects(ConnectivityCheckInfo connectivityCheckInfo,
- ObjectWalk ow,
- ProgressMonitor pm) throws IOException {
- RevObject o;
- ObjectIdSubclassMap<ObjectId> newObjectIds = connectivityCheckInfo
- .getParser()
- .getNewObjectIds();
- while ((o = ow.nextObject()) != null) {
- pm.update(1);
- if (o.has(RevFlag.UNINTERESTING)) {
- continue;
- }
- if (connectivityCheckInfo.isCheckObjects()) {
- if (newObjectIds.contains(o)) {
- continue;
- }
- throw new MissingObjectException(o, o.getType());
- }
- if (o instanceof RevBlob
- && !connectivityCheckInfo.getRepository().getObjectDatabase()
- .has(o)) {
- throw new MissingObjectException(o, Constants.TYPE_BLOB);
- }
- }
- if (connectivityCheckInfo.isCheckObjects()) {
- for (ObjectId id : connectivityCheckInfo.getParser()
- .getBaseObjectIds()) {
- o = ow.parseAny(id);
- if (!o.has(RevFlag.UNINTERESTING)) {
- throw new MissingObjectException(o, o.getType());
- }
- }
- }
- }
- }