View Javadoc
1   /*
2    * Copyright (C) 2020, Google LLC and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.internal.revwalk;
11  
12  import java.io.IOException;
13  import java.util.ArrayList;
14  import java.util.Arrays;
15  import java.util.Collection;
16  import java.util.Iterator;
17  import java.util.List;
18  import java.util.Optional;
19  import java.util.stream.Stream;
20  
21  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
22  import org.eclipse.jgit.errors.MissingObjectException;
23  import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
24  import org.eclipse.jgit.revwalk.BitmapWalker;
25  import org.eclipse.jgit.revwalk.ObjectReachabilityChecker;
26  import org.eclipse.jgit.revwalk.ObjectWalk;
27  import org.eclipse.jgit.revwalk.RevObject;
28  
29  /**
30   * Checks if all objects are reachable from certain starting points using
31   * bitmaps.
32   */
33  public class BitmappedObjectReachabilityChecker
34  		implements ObjectReachabilityChecker {
35  
36  	private final ObjectWalk walk;
37  
38  	/**
39  	 * New instance of the reachability checker using a existing walk.
40  	 *
41  	 * @param walk
42  	 *            ObjectWalk instance to reuse. Caller retains ownership.
43  	 */
44  	public BitmappedObjectReachabilityChecker(ObjectWalk walk) {
45  		this.walk = walk;
46  	}
47  
48  	/**
49  	 * {@inheritDoc}
50  	 *
51  	 * This implementation tries to shortcut the check adding starters
52  	 * incrementally. Ordering the starters by relevance can improve performance
53  	 * in the average case.
54  	 */
55  	@Override
56  	public Optional<RevObject> areAllReachable(Collection<RevObject> targets,
57  			Stream<RevObject> starters) throws IOException {
58  
59  		try {
60  			List<RevObject> remainingTargets = new ArrayList<>(targets);
61  			BitmapWalker bitmapWalker = new BitmapWalker(walk,
62  					walk.getObjectReader().getBitmapIndex(), null);
63  
64  			Iterator<RevObject> starterIt = starters.iterator();
65  			BitmapBuilder seen = null;
66  			while (starterIt.hasNext()) {
67  				List<RevObject> asList = Arrays.asList(starterIt.next());
68  				BitmapBuilder visited = bitmapWalker.findObjects(asList, seen,
69  						true);
70  				seen = seen == null ? visited : seen.or(visited);
71  
72  				remainingTargets.removeIf(seen::contains);
73  				if (remainingTargets.isEmpty()) {
74  					return Optional.empty();
75  				}
76  			}
77  
78  			return Optional.of(remainingTargets.get(0));
79  		} catch (MissingObjectException | IncorrectObjectTypeException e) {
80  			throw new IllegalStateException(e);
81  		}
82  	}
83  }