/* Copyright (c) 2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Johnathan Garrett (LMN Solutions) - initial implementation
*/
package org.locationtech.geogig.api.plumbing;
import java.util.Iterator;
import org.locationtech.geogig.api.AbstractGeoGigOp;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.storage.GraphDatabase;
import org.locationtech.geogig.storage.GraphDatabase.Direction;
import org.locationtech.geogig.storage.GraphDatabase.GraphEdge;
import org.locationtech.geogig.storage.GraphDatabase.GraphNode;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
/**
* Determines if there are any sparse commits between the start commit and the end commit, not
* including the end commit.
*/
public class CheckSparsePath extends AbstractGeoGigOp<Boolean> {
private ObjectId start;
private ObjectId end;
private GraphDatabase graphDb;
/**
* Construct a new {@code CheckSparsePath} using the specified {@link GraphDatabase}.
*
* @param repository the repository
*/
@Inject
public CheckSparsePath(GraphDatabase graphDb) {
this.graphDb = graphDb;
}
/**
* @param start the start {@link ObjectId}
*/
public CheckSparsePath setStart(ObjectId start) {
this.start = start;
return this;
}
/**
* @param end the end {@link ObjectId}
*/
public CheckSparsePath setEnd(ObjectId end) {
this.end = end;
return this;
}
/**
* Determines if there are any sparse commits between the start commit and the end commit, not
* including the end commit.
*
* @return true if there are any sparse commits between start and end
*/
@Override
protected Boolean _call() {
Preconditions.checkState(start != null, "start commit has not been set.");
Preconditions.checkState(end != null, "end commit has not been set.");
GraphNode node = graphDb.getNode(start);
return isSparsePath(node, end, false);
}
/**
* Recursive brute force function to exhaustively search for all paths between the start and end
* node. This should be optimized to avoid unnecessary work in the future.
*/
private boolean isSparsePath(GraphNode node, ObjectId end, boolean sparse) {
if (node.getIdentifier().equals(end)) {
return sparse;
}
Iterator<GraphEdge> outgoing = node.getEdges(Direction.OUT);
if (outgoing.hasNext()) {
boolean node_sparse = node.isSparse();
boolean combined_sparse = false;
while (outgoing.hasNext()) {
GraphEdge parent = outgoing.next();
GraphNode parentNode = parent.getToNode();
combined_sparse = combined_sparse
|| isSparsePath(parentNode, end, sparse || node_sparse);
}
return combined_sparse;
}
return false;
}
}