From bf4ffff07fb5be4a405ca13ae8baa13dee693b10 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 26 Jun 2010 14:16:06 -0700 Subject: [PATCH] Redo PackWriter object reuse selection The new selection implementation uses a public API on the ObjectReader, allowing the storage library to enumerate its candidates and select the best one for this packer without needing to build a temporary list of the candidates first. Change-Id: Ie01496434f7d3581d6d3bbb9e33c8f9fa649b6cd Signed-off-by: Shawn O. Pearce --- .../jgit/lib/CachedObjectDirectory.java | 6 + .../eclipse/jgit/lib/FileObjectDatabase.java | 6 +- .../jgit/lib/LocalObjectRepresentation.java | 80 +++++++++++ .../eclipse/jgit/lib/LocalObjectToPack.java | 16 +-- .../org/eclipse/jgit/lib/ObjectDirectory.java | 15 +- .../org/eclipse/jgit/lib/ObjectReader.java | 31 +--- .../org/eclipse/jgit/lib/ObjectReuseAsIs.java | 98 +++++++++++++ .../org/eclipse/jgit/lib/ObjectToPack.java | 50 ++++++- .../src/org/eclipse/jgit/lib/PackWriter.java | 136 +++++++++--------- .../jgit/lib/StoredObjectRepresentation.java | 88 ++++++++++++ .../org/eclipse/jgit/lib/WindowCursor.java | 18 ++- 11 files changed, 415 insertions(+), 129 deletions(-) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectRepresentation.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReuseAsIs.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredObjectRepresentation.java diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDirectory.java index 351d6817f..a32571e60 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDirectory.java @@ -175,4 +175,10 @@ ObjectLoader openObject2(WindowCursor curs, String objectName, // This method should never be invoked. throw new UnsupportedOperationException(); } + + @Override + void selectObjectRepresentation(PackWriter packer, ObjectToPack otp, + WindowCursor curs) throws IOException { + wrapped.selectObjectRepresentation(packer, otp, curs); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileObjectDatabase.java index 36e808c23..5328b327e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileObjectDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileObjectDatabase.java @@ -45,7 +45,6 @@ import java.io.File; import java.io.IOException; -import java.util.Collection; abstract class FileObjectDatabase extends ObjectDatabase { @Override @@ -160,9 +159,8 @@ final ObjectLoader openObjectImpl2(final WindowCursor curs, return null; } - void openObjectInAllPacks(Collection reuseLoaders, - WindowCursor windowCursor, AnyObjectId otp) throws IOException { - } + abstract void selectObjectRepresentation(PackWriter packer, + ObjectToPack otp, WindowCursor curs) throws IOException; abstract File getDirectory(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectRepresentation.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectRepresentation.java new file mode 100644 index 000000000..f8535bdf2 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectRepresentation.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010, 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.lib; + +import java.io.IOException; + +class LocalObjectRepresentation extends StoredObjectRepresentation { + final PackedObjectLoader ldr; + + LocalObjectRepresentation(PackedObjectLoader ldr) { + this.ldr = ldr; + } + + @Override + public int getFormat() { + if (ldr instanceof DeltaPackedObjectLoader) + return PACK_DELTA; + if (ldr instanceof WholePackedObjectLoader) + return PACK_WHOLE; + return FORMAT_OTHER; + } + + @Override + public int getWeight() { + long sz = ldr.getRawSize(); + if (Integer.MAX_VALUE < sz) + return WEIGHT_UNKNOWN; + return (int) sz; + } + + @Override + public ObjectId getDeltaBase() { + try { + return ldr.getDeltaBase(); + } catch (IOException e) { + return null; + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectToPack.java index a102e96ee..516cf631c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectToPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/LocalObjectToPack.java @@ -59,20 +59,14 @@ class LocalObjectToPack extends ObjectToPack { super(obj); } - boolean isCopyable() { - return copyFromPack != null; - } - PackedObjectLoader getCopyLoader(WindowCursor curs) throws IOException { return copyFromPack.resolveBase(curs, copyOffset); } - void setCopyFromPack(PackedObjectLoader loader) { - this.copyFromPack = loader.pack; - this.copyOffset = loader.objectOffset; - } - - void clearSourcePack() { - copyFromPack = null; + @Override + public void select(StoredObjectRepresentation ref) { + LocalObjectRepresentation ptr = (LocalObjectRepresentation)ref; + this.copyFromPack = ptr.ldr.pack; + this.copyOffset = ptr.ldr.objectOffset; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java index 810e48890..bf8f32334 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java @@ -283,17 +283,16 @@ ObjectLoader openObject1(final WindowCursor curs, } } - void openObjectInAllPacks(final Collection out, - final WindowCursor curs, final AnyObjectId objectId) - throws IOException { + @Override + void selectObjectRepresentation(PackWriter packer, ObjectToPack otp, + WindowCursor curs) throws IOException { PackList pList = packList.get(); SEARCH: for (;;) { for (final PackFile p : pList.packs) { try { - final PackedObjectLoader ldr = p.get(curs, objectId); - if (ldr != null) { - out.add(ldr); - } + PackedObjectLoader ldr = p.get(curs, otp); + if (ldr != null) + packer.select(otp, new LocalObjectRepresentation(ldr)); } catch (PackMismatchException e) { // Pack was modified; refresh the entire pack list. // @@ -309,7 +308,7 @@ void openObjectInAllPacks(final Collection out, } for (AlternateHandle h : myAlternates()) - h.db.openObjectInAllPacks(out, curs, objectId); + h.db.selectObjectRepresentation(packer, otp, curs); } boolean hasObject2(final String objectName) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java index de4b3eea5..670ead9ef 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java @@ -46,9 +46,13 @@ import java.io.IOException; import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.revwalk.RevObject; -/** Reads an {@link ObjectDatabase} for a single thread. */ +/** + * Reads an {@link ObjectDatabase} for a single thread. + *

+ * Readers that can support efficient reuse of pack encoded objects should also + * implement the companion interface {@link ObjectReuseAsIs}. + */ public abstract class ObjectReader { /** Type hint indicating the caller doesn't know the type. */ protected static final int OBJ_ANY = -1; @@ -103,29 +107,6 @@ public ObjectLoader openObject(AnyObjectId objectId) public abstract ObjectLoader openObject(AnyObjectId objectId, int typeHint) throws MissingObjectException, IOException; - /** - * Allocate a new {@code PackWriter} state structure for an object. - *

- * {@link PackWriter} allocates these objects to keep track of the - * per-object state, and how to load the objects efficiently into the - * generated stream. Implementers may override this method to provide their - * own subclass with additional object state, such as to remember what file - * and position contains the object's data. - *

- * The default implementation of this object does not provide very efficient - * packing support; it inflates the object on the fly through {@code - * openObject} and deflates it again into the generated stream. - * - * @param obj - * identity of the object that will be packed. The object's - * parsed status is undefined here. Implementers must not rely on - * the object being parsed. - * @return a new instance for this object. - */ - public ObjectToPack newObjectToPack(RevObject obj) { - return new ObjectToPack(obj, obj.getType()); - } - /** * Release any resources used by this reader. *

diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReuseAsIs.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReuseAsIs.java new file mode 100644 index 000000000..f7aebf124 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReuseAsIs.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010, 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.lib; + +import java.io.IOException; + +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.revwalk.RevObject; + +/** + * Extension of {@link ObjectReader} that supports reusing objects in packs. + *

+ * {@code ObjectReader} implementations may also optionally implement this + * interface to support {@link PackWriter} with a means of copying an object + * that is already in pack encoding format directly into the output stream, + * without incurring decompression and recompression overheads. + */ +public interface ObjectReuseAsIs { + /** + * Allocate a new {@code PackWriter} state structure for an object. + *

+ * {@link PackWriter} allocates these objects to keep track of the + * per-object state, and how to load the objects efficiently into the + * generated stream. Implementers may subclass this type with additional + * object state, such as to remember what file and offset contains the + * object's pack encoded data. + * + * @param obj + * identity of the object that will be packed. The object's + * parsed status is undefined here. Implementers must not rely on + * the object being parsed. + * @return a new instance for this object. + */ + public ObjectToPack newObjectToPack(RevObject obj); + + /** + * Select the best object representation for a packer. + *

+ * Implementations should iterate through all available representations of + * an object, and pass them in turn to the PackWriter though + * {@link PackWriter#select(ObjectToPack, StoredObjectRepresentation)} so + * the writer can select the most suitable representation to reuse into the + * output stream. + * + * @param packer + * the packer that will write the object in the near future. + * @param otp + * the object to pack. + * @throws MissingObjectException + * there is no representation available for the object, as it is + * no longer in the repository. Packing will abort. + * @throws IOException + * the repository cannot be accessed. Packing will abort. + */ + public void selectObjectRepresentation(PackWriter packer, ObjectToPack otp) + throws IOException, MissingObjectException; +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectToPack.java index c0cf8901d..34a969666 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectToPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectToPack.java @@ -57,6 +57,8 @@ public class ObjectToPack extends PackedObjectInfo { private static final int WANT_WRITE = 1 << 0; + private static final int REUSE_AS_IS = 1 << 1; + private static final int TYPE_SHIFT = 5; private static final int DELTA_SHIFT = 8; @@ -70,7 +72,8 @@ public class ObjectToPack extends PackedObjectInfo { * Bit field, from bit 0 to bit 31: *

    *
  • 1 bit: wantWrite
  • - *
  • 4 bits: unused
  • + *
  • 1 bit: canReuseAsIs
  • + *
  • 3 bits: unused
  • *
  • 3 bits: type
  • *
  • --
  • *
  • 24 bits: deltaDepth
  • @@ -186,4 +189,49 @@ boolean wantWrite() { void markWantWrite() { flags |= WANT_WRITE; } + + boolean isReuseAsIs() { + return (flags & REUSE_AS_IS) != 0; + } + + void setReuseAsIs() { + flags |= REUSE_AS_IS; + } + + void clearReuseAsIs() { + flags &= ~REUSE_AS_IS; + } + + int getFormat() { + if (isReuseAsIs()) { + if (isDeltaRepresentation()) + return StoredObjectRepresentation.PACK_DELTA; + return StoredObjectRepresentation.PACK_WHOLE; + } + return StoredObjectRepresentation.FORMAT_OTHER; + } + + // Overload weight into CRC since we don't need them at the same time. + int getWeight() { + return getCRC(); + } + + void setWeight(int weight) { + setCRC(weight); + } + + /** + * Remember a specific representation for reuse at a later time. + *

    + * Implementers should remember the representation chosen, so it can be + * reused at a later time. {@link PackWriter} may invoke this method + * multiple times for the same object, each time saving the current best + * representation found. + * + * @param ref + * the object representation. + */ + public void select(StoredObjectRepresentation ref) { + // Empty by default. + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackWriter.java index 2079931ea..462b12f39 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackWriter.java @@ -44,6 +44,9 @@ package org.eclipse.jgit.lib; +import static org.eclipse.jgit.lib.StoredObjectRepresentation.PACK_DELTA; +import static org.eclipse.jgit.lib.StoredObjectRepresentation.PACK_WHOLE; + import java.io.IOException; import java.io.OutputStream; import java.security.MessageDigest; @@ -605,82 +608,18 @@ public void writePack(OutputStream packStream) throws IOException { private void searchForReuse() throws IOException { initMonitor.beginTask(SEARCHING_REUSE_PROGRESS, getObjectsNumber()); - final Collection reuseLoaders = new ArrayList(); for (List list : objectsLists) { - for (LocalObjectToPack otp : list) { + for (ObjectToPack otp : list) { if (initMonitor.isCancelled()) throw new IOException( JGitText.get().packingCancelledDuringObjectsWriting); - reuseLoaders.clear(); - searchForReuse(reuseLoaders, otp); + windowCursor.selectObjectRepresentation(this, otp); initMonitor.update(1); } } - initMonitor.endTask(); } - private void searchForReuse( - final Collection reuseLoaders, - final LocalObjectToPack otp) throws IOException { - windowCursor.openObjectInAllPacks(otp, reuseLoaders); - if (reuseDeltas) { - selectDeltaReuseForObject(otp, reuseLoaders); - } - // delta reuse is preferred over object reuse - if (reuseObjects && !otp.isCopyable()) { - selectObjectReuseForObject(otp, reuseLoaders); - } - } - - private void selectDeltaReuseForObject(final LocalObjectToPack otp, - final Collection loaders) throws IOException { - PackedObjectLoader bestLoader = null; - ObjectId bestBase = null; - - for (PackedObjectLoader loader : loaders) { - ObjectId idBase = loader.getDeltaBase(); - if (idBase == null) - continue; - ObjectToPack otpBase = objectsMap.get(idBase); - - // only if base is in set of objects to write or thin-pack's edge - if ((otpBase != null || (thin && edgeObjects.get(idBase) != null)) - // select smallest possible delta if > 1 available - && isBetterDeltaReuseLoader(bestLoader, loader)) { - bestLoader = loader; - bestBase = (otpBase != null ? otpBase : idBase); - } - } - - if (bestLoader != null) { - otp.setCopyFromPack(bestLoader); - otp.setDeltaBase(bestBase); - } - } - - private static boolean isBetterDeltaReuseLoader( - PackedObjectLoader currentLoader, PackedObjectLoader loader) - throws IOException { - if (currentLoader == null) - return true; - if (loader.getRawSize() < currentLoader.getRawSize()) - return true; - return (loader.getRawSize() == currentLoader.getRawSize() - && loader.supportsFastCopyRawData() && !currentLoader - .supportsFastCopyRawData()); - } - - private void selectObjectReuseForObject(final LocalObjectToPack otp, - final Collection loaders) { - for (final PackedObjectLoader loader : loaders) { - if (loader instanceof WholePackedObjectLoader) { - otp.setCopyFromPack(loader); - return; - } - } - } - private void writeHeader() throws IOException { System.arraycopy(Constants.PACK_SIGNATURE, 0, buf, 0, 4); NB.encodeInt32(buf, 4, PACK_VERSION_GENERATED); @@ -708,7 +647,7 @@ private void writeObject(final LocalObjectToPack otp) throws IOException { if (deltaBase != null && !deltaBase.isWritten()) { if (deltaBase.wantWrite()) { otp.clearDeltaBase(); // cycle detected - otp.clearSourcePack(); + otp.clearReuseAsIs(); } else { writeObject(deltaBase); } @@ -742,7 +681,7 @@ private void writeObject(final LocalObjectToPack otp) throws IOException { } private PackedObjectLoader open(final LocalObjectToPack otp) throws IOException { - while (otp.isCopyable()) { + while (otp.isReuseAsIs()) { try { PackedObjectLoader reuse = otp.getCopyLoader(windowCursor); reuse.beginCopyRawData(); @@ -752,8 +691,8 @@ private PackedObjectLoader open(final LocalObjectToPack otp) throws IOException // it has been overwritten with a different layout. // otp.clearDeltaBase(); - otp.clearSourcePack(); - searchForReuse(new ArrayList(), otp); + otp.clearReuseAsIs(); + windowCursor.selectObjectRepresentation(this, otp); continue; } } @@ -898,4 +837,61 @@ public void addObject(final RevObject object) } objectsMap.add(otp); } + + /** + * Select an object representation for this writer. + *

    + * An {@link ObjectReader} implementation should invoke this method once for + * each representation available for an object, to allow the writer to find + * the most suitable one for the output. + * + * @param otp + * the object being packed. + * @param next + * the next available representation from the repository. + */ + public void select(ObjectToPack otp, StoredObjectRepresentation next) { + int nFmt = next.getFormat(); + int nWeight; + if (otp.isReuseAsIs()) { + // We've already chosen to reuse a packed form, if next + // cannot beat that break out early. + // + if (PACK_WHOLE < nFmt) + return; // next isn't packed + else if (PACK_DELTA < nFmt && otp.isDeltaRepresentation()) + return; // next isn't a delta, but we are + + nWeight = next.getWeight(); + if (otp.getWeight() <= nWeight) + return; // next would be bigger + } else + nWeight = next.getWeight(); + + if (nFmt == PACK_DELTA && reuseDeltas) { + ObjectId baseId = next.getDeltaBase(); + ObjectToPack ptr = objectsMap.get(baseId); + if (ptr != null) { + otp.setDeltaBase(ptr); + otp.setReuseAsIs(); + otp.setWeight(nWeight); + } else if (thin && edgeObjects.contains(baseId)) { + otp.setDeltaBase(baseId); + otp.setReuseAsIs(); + otp.setWeight(nWeight); + } else { + otp.clearDeltaBase(); + otp.clearReuseAsIs(); + } + } else if (nFmt == PACK_WHOLE && reuseObjects) { + otp.clearDeltaBase(); + otp.setReuseAsIs(); + otp.setWeight(nWeight); + } else { + otp.clearDeltaBase(); + otp.clearReuseAsIs(); + } + + otp.select(next); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredObjectRepresentation.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredObjectRepresentation.java new file mode 100644 index 000000000..0eb05f5e0 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/StoredObjectRepresentation.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010, 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.lib; + +/** + * An object representation {@link PackWriter} can consider for packing. + */ +public class StoredObjectRepresentation { + /** Special unknown value for {@link #getWeight()}. */ + public static final int WEIGHT_UNKNOWN = Integer.MAX_VALUE; + + /** Stored in pack format, as a delta to another object. */ + public static final int PACK_DELTA = 0; + + /** Stored in pack format, without delta. */ + public static final int PACK_WHOLE = 1; + + /** Only available after inflating to canonical format. */ + public static final int FORMAT_OTHER = 2; + + /** + * @return relative size of this object's packed form. The special value + * {@link #WEIGHT_UNKNOWN} can be returned to indicate the + * implementation doesn't know, or cannot supply the weight up + * front. + */ + public int getWeight() { + return WEIGHT_UNKNOWN; + } + + /** + * @return true if this is a delta against another object and this is stored + * in pack delta format. + */ + public int getFormat() { + return FORMAT_OTHER; + } + + /** + * @return identity of the object this delta applies to in order to recover + * the original object content. This method should only be called if + * {@link #getFormat()} returned {@link #PACK_DELTA}. + */ + public ObjectId getDeltaBase() { + return null; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/WindowCursor.java index cf5bce73c..e16735492 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/WindowCursor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/WindowCursor.java @@ -45,7 +45,6 @@ package org.eclipse.jgit.lib; import java.io.IOException; -import java.util.Collection; import java.util.zip.DataFormatException; import java.util.zip.Inflater; @@ -53,7 +52,7 @@ import org.eclipse.jgit.revwalk.RevObject; /** Active handle to a ByteWindow. */ -final class WindowCursor extends ObjectReader { +final class WindowCursor extends ObjectReader implements ObjectReuseAsIs { /** Temporary buffer large enough for at least one raw object id. */ final byte[] tempId = new byte[Constants.OBJECT_ID_LENGTH]; @@ -82,14 +81,13 @@ public ObjectLoader openObject(AnyObjectId objectId, int typeHint) return ldr; } - @Override public LocalObjectToPack newObjectToPack(RevObject obj) { return new LocalObjectToPack(obj); } - void openObjectInAllPacks(AnyObjectId otp, - Collection reuseLoaders) throws IOException { - db.openObjectInAllPacks(reuseLoaders, this, otp); + public void selectObjectRepresentation(PackWriter packer, ObjectToPack otp) + throws IOException, MissingObjectException { + db.selectObjectRepresentation(packer, otp, this); } /** @@ -108,8 +106,8 @@ void openObjectInAllPacks(AnyObjectId otp, * bytes remaining in the window starting at offset * pos. * @return number of bytes actually copied; this may be less than - * cnt if cnt exceeded the number of - * bytes available. + * cnt if cnt exceeded the number of bytes + * available. * @throws IOException * this cursor does not match the provider or id and the proper * window could not be acquired through the provider's cache. @@ -161,8 +159,8 @@ int inflate(final PackFile pack, long position, final byte[] dstbuf, } } - void inflateVerify(final PackFile pack, long position) - throws IOException, DataFormatException { + void inflateVerify(final PackFile pack, long position) throws IOException, + DataFormatException { prepareInflater(); for (;;) { pin(pack, position);