From f2be5bca043f3e8ddfbc8b03fc17ff4a65896045 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Thu, 14 May 2015 16:24:15 -0700 Subject: [PATCH] Allow ObjectWalk to be filtered by an arbitrary predicate This will make it possible to declare a collection of objects as ineligible for the walk en masse, for example if they are known to be uninteresting via a bitmap. Change-Id: I637008b25bf9fb57df60ebb2133a70214930546a Signed-off-by: Jonathan Nieder --- .../org/eclipse/jgit/revwalk/ObjectWalk.java | 52 ++++++++++- .../jgit/revwalk/filter/ObjectFilter.java | 87 +++++++++++++++++++ 2 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java index 18c4233eb..89a06b141 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java @@ -60,6 +60,7 @@ import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.filter.ObjectFilter; import org.eclipse.jgit.util.RawParseUtils; /** @@ -99,6 +100,8 @@ public class ObjectWalk extends RevWalk { private BlockObjQueue pendingObjects; + private ObjectFilter objectFilter; + private TreeVisit freeVisit; private TreeVisit currVisit; @@ -132,6 +135,7 @@ public ObjectWalk(ObjectReader or) { setRetainBody(false); rootObjects = new ArrayList(); pendingObjects = new BlockObjQueue(); + objectFilter = ObjectFilter.ALL; pathBuf = new byte[256]; } @@ -250,6 +254,38 @@ public void sort(RevSort s, boolean use) { boundary = hasRevSort(RevSort.BOUNDARY); } + /** + * Get the currently configured object filter. + * + * @return the current filter. Never null as a filter is always needed. + * + * @since 4.1 + */ + public ObjectFilter getObjectFilter() { + return objectFilter; + } + + /** + * Set the object filter for this walker. This filter affects the objects + * visited by {@link #nextObject()}. It does not affect the commits + * listed by {@link #next()}. + *

+ * If the filter returns false for an object, then that object is skipped + * and objects reachable from it are not enqueued to be walked recursively. + * This can be used to speed up the object walk by skipping subtrees that + * are known to be uninteresting. + * + * @param newFilter + * the new filter. If null the special {@link ObjectFilter#ALL} + * filter will be used instead, which as it matches every object. + * + * @since 4.1 + */ + public void setObjectFilter(ObjectFilter newFilter) { + assertNotStarted(); + objectFilter = newFilter != null ? newFilter : ObjectFilter.ALL; + } + @Override public RevCommit next() throws MissingObjectException, IncorrectObjectTypeException, IOException { @@ -258,13 +294,19 @@ public RevCommit next() throws MissingObjectException, if (r == null) { return null; } + final RevTree t = r.getTree(); if ((r.flags & UNINTERESTING) != 0) { - markTreeUninteresting(r.getTree()); - if (boundary) + if (objectFilter.include(this, t)) { + markTreeUninteresting(t); + } + if (boundary) { return r; + } continue; } - pendingObjects.add(r.getTree()); + if (objectFilter.include(this, t)) { + pendingObjects.add(t); + } return r; } } @@ -296,6 +338,10 @@ public RevObject nextObject() throws MissingObjectException, idBuffer.fromRaw(buf, ptr); ptr += ID_SZ; + if (!objectFilter.include(this, idBuffer)) { + continue; + } + RevObject obj = objects.get(idBuffer); if (obj != null && (obj.flags & SEEN) != 0) continue; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java new file mode 100644 index 000000000..a1d66c8e3 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/ObjectFilter.java @@ -0,0 +1,87 @@ +/** + * Copyright (C) 2015, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.revwalk.filter; + +import java.io.IOException; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.StopWalkException; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.revwalk.ObjectWalk; + +/** + * Selects interesting objects when walking. + *

+ * Applications should install the filter on an ObjectWalk by + * {@link ObjectWalk#setObjectFilter(ObjectFilter)} prior to starting traversal. + * + * @since 4.1 + */ +public abstract class ObjectFilter { + /** Default filter that always returns true. */ + public static final ObjectFilter ALL = new AllFilter(); + + private static final class AllFilter extends ObjectFilter { + @Override + public boolean include(ObjectWalk walker, AnyObjectId o) { + return true; + } + } + + /** + * Determine if the named object should be included in the walk. + * + * @param walker + * the active walker this filter is being invoked from within. + * @param objid + * the object currently being tested. + * @throws IOException + * an object the filter needed to consult to determine its answer + * was missing, of the wrong type, or could not be read. + */ + public abstract boolean include(ObjectWalk walker, AnyObjectId objid) + throws MissingObjectException, IncorrectObjectTypeException, + IOException; +}