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 <spearce@spearce.org>
This commit is contained in:
parent
e0c9368f3e
commit
bf4ffff07f
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PackedObjectLoader> reuseLoaders,
|
||||
WindowCursor windowCursor, AnyObjectId otp) throws IOException {
|
||||
}
|
||||
abstract void selectObjectRepresentation(PackWriter packer,
|
||||
ObjectToPack otp, WindowCursor curs) throws IOException;
|
||||
|
||||
abstract File getDirectory();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -283,17 +283,16 @@ ObjectLoader openObject1(final WindowCursor curs,
|
|||
}
|
||||
}
|
||||
|
||||
void openObjectInAllPacks(final Collection<PackedObjectLoader> 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<PackedObjectLoader> out,
|
|||
}
|
||||
|
||||
for (AlternateHandle h : myAlternates())
|
||||
h.db.openObjectInAllPacks(out, curs, objectId);
|
||||
h.db.selectObjectRepresentation(packer, otp, curs);
|
||||
}
|
||||
|
||||
boolean hasObject2(final String objectName) {
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* {@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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* {@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.
|
||||
* <p>
|
||||
* {@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.
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
|
@ -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:
|
||||
* <ul>
|
||||
* <li>1 bit: wantWrite</li>
|
||||
* <li>4 bits: unused</li>
|
||||
* <li>1 bit: canReuseAsIs</li>
|
||||
* <li>3 bits: unused</li>
|
||||
* <li>3 bits: type</li>
|
||||
* <li>--</li>
|
||||
* <li>24 bits: deltaDepth</li>
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PackedObjectLoader> reuseLoaders = new ArrayList<PackedObjectLoader>();
|
||||
for (List<LocalObjectToPack> 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<PackedObjectLoader> 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<PackedObjectLoader> 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<PackedObjectLoader> 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<PackedObjectLoader>(), 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.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<PackedObjectLoader> 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
|
||||
* <code>pos</code>.
|
||||
* @return number of bytes actually copied; this may be less than
|
||||
* <code>cnt</code> if <code>cnt</code> exceeded the number of
|
||||
* bytes available.
|
||||
* <code>cnt</code> if <code>cnt</code> 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);
|
||||
|
|
Loading…
Reference in New Issue