packs) {
odb = null;
packNames = null;
- this.packs = packs.toArray(new PackFile[0]);
+ this.packs = packs.toArray(new Pack[0]);
}
/** {@inheritDoc} */
@Override
public long getObjectCount() throws IOException {
long cnt = 0;
- for (PackFile pack : getPacks())
+ for (Pack pack : getPacks())
cnt += pack.getObjectCount();
return cnt;
}
void copyAsIs(PackOutputStream out, WindowCursor wc)
throws IOException {
- for (PackFile pack : getPacks())
+ for (Pack pack : getPacks())
pack.copyPackAsIs(out, wc);
}
@@ -58,7 +58,7 @@ class LocalCachedPack extends CachedPack {
public boolean hasObject(ObjectToPack obj, StoredObjectRepresentation rep) {
try {
LocalObjectRepresentation local = (LocalObjectRepresentation) rep;
- for (PackFile pack : getPacks()) {
+ for (Pack pack : getPacks()) {
if (local.pack == pack)
return true;
}
@@ -68,9 +68,9 @@ class LocalCachedPack extends CachedPack {
}
}
- private PackFile[] getPacks() throws FileNotFoundException {
+ private Pack[] getPacks() throws FileNotFoundException {
if (packs == null) {
- PackFile[] p = new PackFile[packNames.length];
+ Pack[] p = new Pack[packNames.length];
for (int i = 0; i < packNames.length; i++)
p[i] = getPackFile(packNames[i]);
packs = p;
@@ -78,8 +78,8 @@ class LocalCachedPack extends CachedPack {
return packs;
}
- private PackFile getPackFile(String packName) throws FileNotFoundException {
- for (PackFile pack : odb.getPacks()) {
+ private Pack getPackFile(String packName) throws FileNotFoundException {
+ for (Pack pack : odb.getPacks()) {
if (packName.equals(pack.getPackName()))
return pack;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
index 3950dde4a5..559718af3a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectRepresentation.java
@@ -16,40 +16,40 @@ import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation;
import org.eclipse.jgit.lib.ObjectId;
class LocalObjectRepresentation extends StoredObjectRepresentation {
- static LocalObjectRepresentation newWhole(PackFile f, long p, long length) {
+ static LocalObjectRepresentation newWhole(Pack pack, long offset, long length) {
LocalObjectRepresentation r = new LocalObjectRepresentation() {
@Override
public int getFormat() {
return PACK_WHOLE;
}
};
- r.pack = f;
- r.offset = p;
+ r.pack = pack;
+ r.offset = offset;
r.length = length;
return r;
}
- static LocalObjectRepresentation newDelta(PackFile f, long p, long n,
+ static LocalObjectRepresentation newDelta(Pack pack, long offset, long length,
ObjectId base) {
LocalObjectRepresentation r = new Delta();
- r.pack = f;
- r.offset = p;
- r.length = n;
+ r.pack = pack;
+ r.offset = offset;
+ r.length = length;
r.baseId = base;
return r;
}
- static LocalObjectRepresentation newDelta(PackFile f, long p, long n,
+ static LocalObjectRepresentation newDelta(Pack pack, long offset, long length,
long base) {
LocalObjectRepresentation r = new Delta();
- r.pack = f;
- r.offset = p;
- r.length = n;
+ r.pack = pack;
+ r.offset = offset;
+ r.length = length;
r.baseOffset = base;
return r;
}
- PackFile pack;
+ Pack pack;
long offset;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
index 4a0ac1fd84..ac6cd212d5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LocalObjectToPack.java
@@ -17,7 +17,7 @@ import org.eclipse.jgit.lib.AnyObjectId;
/** {@link ObjectToPack} for {@link ObjectDirectory}. */
class LocalObjectToPack extends ObjectToPack {
/** Pack to reuse compressed data from, otherwise null. */
- PackFile pack;
+ Pack pack;
/** Offset of the object's header in {@link #pack}. */
long offset;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 4a40db68dd..e71a960603 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -51,7 +51,7 @@ import org.eclipse.jgit.util.FileUtils;
* This is the classical object database representation for a Git repository,
* where objects are stored loose by hashing them into directories by their
* {@link org.eclipse.jgit.lib.ObjectId}, or are stored in compressed containers
- * known as {@link org.eclipse.jgit.internal.storage.file.PackFile}s.
+ * known as {@link org.eclipse.jgit.internal.storage.file.Pack}s.
*
* Optionally an object database can reference one or more alternates; other
* ObjectDatabase instances that are searched in addition to the current
@@ -206,7 +206,7 @@ public class ObjectDirectory extends FileObjectDatabase {
/** {@inheritDoc} */
@Override
- public Collection getPacks() {
+ public Collection getPacks() {
return packed.getPacks();
}
@@ -216,7 +216,7 @@ public class ObjectDirectory extends FileObjectDatabase {
* Add a single existing pack to the list of available pack files.
*/
@Override
- public PackFile openPack(File pack)
+ public Pack openPack(File pack)
throws IOException {
final String p = pack.getName();
if (p.length() != 50 || !p.startsWith("pack-") || !p.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$
@@ -235,7 +235,7 @@ public class ObjectDirectory extends FileObjectDatabase {
}
}
- PackFile res = new PackFile(pack, extensions);
+ Pack res = new Pack(pack, extensions);
packed.insert(res);
return res;
}
@@ -509,7 +509,7 @@ public class ObjectDirectory extends FileObjectDatabase {
// PackConfig) then make sure we get rid of all handles on the file.
// Windows will not allow for rename otherwise.
if (packFile.exists()) {
- for (PackFile p : packed.getPacks()) {
+ for (Pack p : packed.getPacks()) {
if (packFile.getPath().equals(p.getPackFile().getPath())) {
p.close();
break;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
index e27518690b..04d2ff8ab2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
@@ -88,7 +88,7 @@ public class ObjectDirectoryPackParser extends PackParser {
private Deflater def;
/** The pack that was created, if parsing was successful. */
- private PackFile newPack;
+ private Pack newPack;
private PackConfig pconfig;
@@ -129,14 +129,14 @@ public class ObjectDirectoryPackParser extends PackParser {
}
/**
- * Get the imported {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+ * Get the imported {@link org.eclipse.jgit.internal.storage.file.Pack}.
*
* This method is supplied only to support testing; applications shouldn't
* be using it directly to access the imported data.
*
* @return the imported PackFile, if parsing was successful.
*/
- public PackFile getPackFile() {
+ public Pack getPack() {
return newPack;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
new file mode 100644
index 0000000000..d928633a73
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
@@ -0,0 +1,1208 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * Copyright (C) 2007, Robin Rosenberg
+ * Copyright (C) 2006-2008, Shawn O. Pearce and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
+import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
+import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel.MapMode;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.NoSuchFileException;
+import java.text.MessageFormat;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.zip.CRC32;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.LargeObjectException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.NoPackSignatureException;
+import org.eclipse.jgit.errors.PackInvalidException;
+import org.eclipse.jgit.errors.PackMismatchException;
+import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
+import org.eclipse.jgit.errors.UnpackException;
+import org.eclipse.jgit.errors.UnsupportedPackIndexVersionException;
+import org.eclipse.jgit.errors.UnsupportedPackVersionException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.util.LongList;
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.RawParseUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Git version 2 pack file representation. A pack file contains Git objects in
+ * delta packed format yielding high compression of lots of object where some
+ * objects are similar.
+ */
+public class Pack implements Iterable {
+ private static final Logger LOG = LoggerFactory.getLogger(Pack.class);
+
+ /**
+ * Sorts PackFiles to be most recently created to least recently created.
+ */
+ public static final Comparator SORT = (a, b) -> b.packLastModified
+ .compareTo(a.packLastModified);
+
+ private final File packFile;
+
+ private final int extensions;
+
+ private File keepFile;
+
+ private volatile String packName;
+
+ final int hash;
+
+ private RandomAccessFile fd;
+
+ /** Serializes reads performed against {@link #fd}. */
+ private final Object readLock = new Object();
+
+ long length;
+
+ private int activeWindows;
+
+ private int activeCopyRawData;
+
+ Instant packLastModified;
+
+ private PackFileSnapshot fileSnapshot;
+
+ private volatile boolean invalid;
+
+ private volatile Exception invalidatingCause;
+
+ private boolean invalidBitmap;
+
+ private AtomicInteger transientErrorCount = new AtomicInteger();
+
+ private byte[] packChecksum;
+
+ private volatile PackIndex loadedIdx;
+
+ private PackReverseIndex reverseIdx;
+
+ private PackBitmapIndex bitmapIdx;
+
+ /**
+ * Objects we have tried to read, and discovered to be corrupt.
+ *
+ * The list is allocated after the first corruption is found, and filled in
+ * as more entries are discovered. Typically this list is never used, as
+ * pack files do not usually contain corrupt objects.
+ */
+ private volatile LongList corruptObjects;
+
+ /**
+ * Construct a reader for an existing, pre-indexed packfile.
+ *
+ * @param packFile
+ * path of the .pack
file holding the data.
+ * @param extensions
+ * additional pack file extensions with the same base as the pack
+ */
+ public Pack(File packFile, int extensions) {
+ this.packFile = packFile;
+ this.fileSnapshot = PackFileSnapshot.save(packFile);
+ this.packLastModified = fileSnapshot.lastModifiedInstant();
+ this.extensions = extensions;
+
+ // Multiply by 31 here so we can more directly combine with another
+ // value in WindowCache.hash(), without doing the multiply there.
+ //
+ hash = System.identityHashCode(this) * 31;
+ length = Long.MAX_VALUE;
+ }
+
+ private PackIndex idx() throws IOException {
+ PackIndex idx = loadedIdx;
+ if (idx == null) {
+ synchronized (this) {
+ idx = loadedIdx;
+ if (idx == null) {
+ if (invalid) {
+ throw new PackInvalidException(packFile, invalidatingCause);
+ }
+ try {
+ long start = System.currentTimeMillis();
+ idx = PackIndex.open(extFile(INDEX));
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(String.format(
+ "Opening pack index %s, size %.3f MB took %d ms", //$NON-NLS-1$
+ extFile(INDEX).getAbsolutePath(),
+ Float.valueOf(extFile(INDEX).length()
+ / (1024f * 1024)),
+ Long.valueOf(System.currentTimeMillis()
+ - start)));
+ }
+
+ if (packChecksum == null) {
+ packChecksum = idx.packChecksum;
+ fileSnapshot.setChecksum(
+ ObjectId.fromRaw(packChecksum));
+ } else if (!Arrays.equals(packChecksum,
+ idx.packChecksum)) {
+ throw new PackMismatchException(MessageFormat
+ .format(JGitText.get().packChecksumMismatch,
+ packFile.getPath(),
+ ObjectId.fromRaw(packChecksum)
+ .name(),
+ ObjectId.fromRaw(idx.packChecksum)
+ .name()));
+ }
+ loadedIdx = idx;
+ } catch (InterruptedIOException e) {
+ // don't invalidate the pack, we are interrupted from
+ // another thread
+ throw e;
+ } catch (IOException e) {
+ invalid = true;
+ invalidatingCause = e;
+ throw e;
+ }
+ }
+ }
+ }
+ return idx;
+ }
+ /**
+ * Get the File object which locates this pack on disk.
+ *
+ * @return the File object which locates this pack on disk.
+ */
+ public File getPackFile() {
+ return packFile;
+ }
+
+ /**
+ * Get the index for this pack file.
+ *
+ * @return the index for this pack file.
+ * @throws java.io.IOException
+ */
+ public PackIndex getIndex() throws IOException {
+ return idx();
+ }
+
+ /**
+ * Get name extracted from {@code pack-*.pack} pattern.
+ *
+ * @return name extracted from {@code pack-*.pack} pattern.
+ */
+ public String getPackName() {
+ String name = packName;
+ if (name == null) {
+ name = getPackFile().getName();
+ if (name.startsWith("pack-")) //$NON-NLS-1$
+ name = name.substring("pack-".length()); //$NON-NLS-1$
+ if (name.endsWith(".pack")) //$NON-NLS-1$
+ name = name.substring(0, name.length() - ".pack".length()); //$NON-NLS-1$
+ packName = name;
+ }
+ return name;
+ }
+
+ /**
+ * Determine if an object is contained within the pack file.
+ *
+ * For performance reasons only the index file is searched; the main pack
+ * content is ignored entirely.
+ *
+ *
+ * @param id
+ * the object to look for. Must not be null.
+ * @return true if the object is in this pack; false otherwise.
+ * @throws java.io.IOException
+ * the index file cannot be loaded into memory.
+ */
+ public boolean hasObject(AnyObjectId id) throws IOException {
+ final long offset = idx().findOffset(id);
+ return 0 < offset && !isCorrupt(offset);
+ }
+
+ /**
+ * Determines whether a .keep file exists for this pack file.
+ *
+ * @return true if a .keep file exist.
+ */
+ public boolean shouldBeKept() {
+ if (keepFile == null)
+ keepFile = extFile(KEEP);
+ return keepFile.exists();
+ }
+
+ /**
+ * Get an object from this pack.
+ *
+ * @param curs
+ * temporary working space associated with the calling thread.
+ * @param id
+ * the object to obtain from the pack. Must not be null.
+ * @return the object loader for the requested object if it is contained in
+ * this pack; null if the object was not found.
+ * @throws IOException
+ * the pack file or the index could not be read.
+ */
+ ObjectLoader get(WindowCursor curs, AnyObjectId id)
+ throws IOException {
+ final long offset = idx().findOffset(id);
+ return 0 < offset && !isCorrupt(offset) ? load(curs, offset) : null;
+ }
+
+ void resolve(Set matches, AbbreviatedObjectId id, int matchLimit)
+ throws IOException {
+ idx().resolve(matches, id, matchLimit);
+ }
+
+ /**
+ * Close the resources utilized by this repository
+ */
+ public void close() {
+ WindowCache.purge(this);
+ synchronized (this) {
+ loadedIdx = null;
+ reverseIdx = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Provide iterator over entries in associated pack index, that should also
+ * exist in this pack file. Objects returned by such iterator are mutable
+ * during iteration.
+ *
+ * Iterator returns objects in SHA-1 lexicographical order.
+ *
+ *
+ * @see PackIndex#iterator()
+ */
+ @Override
+ public Iterator iterator() {
+ try {
+ return idx().iterator();
+ } catch (IOException e) {
+ return Collections. emptyList().iterator();
+ }
+ }
+
+ /**
+ * Obtain the total number of objects available in this pack. This method
+ * relies on pack index, giving number of effectively available objects.
+ *
+ * @return number of objects in index of this pack, likewise in this pack
+ * @throws IOException
+ * the index file cannot be loaded into memory.
+ */
+ long getObjectCount() throws IOException {
+ return idx().getObjectCount();
+ }
+
+ /**
+ * Search for object id with the specified start offset in associated pack
+ * (reverse) index.
+ *
+ * @param offset
+ * start offset of object to find
+ * @return object id for this offset, or null if no object was found
+ * @throws IOException
+ * the index file cannot be loaded into memory.
+ */
+ ObjectId findObjectForOffset(long offset) throws IOException {
+ return getReverseIdx().findObject(offset);
+ }
+
+ /**
+ * Return the @{@link FileSnapshot} associated to the underlying packfile
+ * that has been used when the object was created.
+ *
+ * @return the packfile @{@link FileSnapshot} that the object is loaded from.
+ */
+ PackFileSnapshot getFileSnapshot() {
+ return fileSnapshot;
+ }
+
+ AnyObjectId getPackChecksum() {
+ return ObjectId.fromRaw(packChecksum);
+ }
+
+ private final byte[] decompress(final long position, final int sz,
+ final WindowCursor curs) throws IOException, DataFormatException {
+ byte[] dstbuf;
+ try {
+ dstbuf = new byte[sz];
+ } catch (OutOfMemoryError noMemory) {
+ // The size may be larger than our heap allows, return null to
+ // let the caller know allocation isn't possible and it should
+ // use the large object streaming approach instead.
+ //
+ // For example, this can occur when sz is 640 MB, and JRE
+ // maximum heap size is only 256 MB. Even if the JRE has
+ // 200 MB free, it cannot allocate a 640 MB byte array.
+ return null;
+ }
+
+ if (curs.inflate(this, position, dstbuf, false) != sz)
+ throw new EOFException(MessageFormat.format(
+ JGitText.get().shortCompressedStreamAt,
+ Long.valueOf(position)));
+ return dstbuf;
+ }
+
+ void copyPackAsIs(PackOutputStream out, WindowCursor curs)
+ throws IOException {
+ // Pin the first window, this ensures the length is accurate.
+ curs.pin(this, 0);
+ curs.copyPackAsIs(this, length, out);
+ }
+
+ final void copyAsIs(PackOutputStream out, LocalObjectToPack src,
+ boolean validate, WindowCursor curs) throws IOException,
+ StoredObjectRepresentationNotAvailableException {
+ beginCopyAsIs(src);
+ try {
+ copyAsIs2(out, src, validate, curs);
+ } finally {
+ endCopyAsIs();
+ }
+ }
+
+ private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
+ boolean validate, WindowCursor curs) throws IOException,
+ StoredObjectRepresentationNotAvailableException {
+ final CRC32 crc1 = validate ? new CRC32() : null;
+ final CRC32 crc2 = validate ? new CRC32() : null;
+ final byte[] buf = out.getCopyBuffer();
+
+ // Rip apart the header so we can discover the size.
+ //
+ readFully(src.offset, buf, 0, 20, curs);
+ int c = buf[0] & 0xff;
+ final int typeCode = (c >> 4) & 7;
+ long inflatedLength = c & 15;
+ int shift = 4;
+ int headerCnt = 1;
+ while ((c & 0x80) != 0) {
+ c = buf[headerCnt++] & 0xff;
+ inflatedLength += ((long) (c & 0x7f)) << shift;
+ shift += 7;
+ }
+
+ if (typeCode == Constants.OBJ_OFS_DELTA) {
+ do {
+ c = buf[headerCnt++] & 0xff;
+ } while ((c & 128) != 0);
+ if (validate) {
+ assert(crc1 != null && crc2 != null);
+ crc1.update(buf, 0, headerCnt);
+ crc2.update(buf, 0, headerCnt);
+ }
+ } else if (typeCode == Constants.OBJ_REF_DELTA) {
+ if (validate) {
+ assert(crc1 != null && crc2 != null);
+ crc1.update(buf, 0, headerCnt);
+ crc2.update(buf, 0, headerCnt);
+ }
+
+ readFully(src.offset + headerCnt, buf, 0, 20, curs);
+ if (validate) {
+ assert(crc1 != null && crc2 != null);
+ crc1.update(buf, 0, 20);
+ crc2.update(buf, 0, 20);
+ }
+ headerCnt += 20;
+ } else if (validate) {
+ assert(crc1 != null && crc2 != null);
+ crc1.update(buf, 0, headerCnt);
+ crc2.update(buf, 0, headerCnt);
+ }
+
+ final long dataOffset = src.offset + headerCnt;
+ final long dataLength = src.length;
+ final long expectedCRC;
+ final ByteArrayWindow quickCopy;
+
+ // Verify the object isn't corrupt before sending. If it is,
+ // we report it missing instead.
+ //
+ try {
+ quickCopy = curs.quickCopy(this, dataOffset, dataLength);
+
+ if (validate && idx().hasCRC32Support()) {
+ assert(crc1 != null);
+ // Index has the CRC32 code cached, validate the object.
+ //
+ expectedCRC = idx().findCRC32(src);
+ if (quickCopy != null) {
+ quickCopy.crc32(crc1, dataOffset, (int) dataLength);
+ } else {
+ long pos = dataOffset;
+ long cnt = dataLength;
+ while (cnt > 0) {
+ final int n = (int) Math.min(cnt, buf.length);
+ readFully(pos, buf, 0, n, curs);
+ crc1.update(buf, 0, n);
+ pos += n;
+ cnt -= n;
+ }
+ }
+ if (crc1.getValue() != expectedCRC) {
+ setCorrupt(src.offset);
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackFile()));
+ }
+ } else if (validate) {
+ // We don't have a CRC32 code in the index, so compute it
+ // now while inflating the raw data to get zlib to tell us
+ // whether or not the data is safe.
+ //
+ Inflater inf = curs.inflater();
+ byte[] tmp = new byte[1024];
+ if (quickCopy != null) {
+ quickCopy.check(inf, tmp, dataOffset, (int) dataLength);
+ } else {
+ assert(crc1 != null);
+ long pos = dataOffset;
+ long cnt = dataLength;
+ while (cnt > 0) {
+ final int n = (int) Math.min(cnt, buf.length);
+ readFully(pos, buf, 0, n, curs);
+ crc1.update(buf, 0, n);
+ inf.setInput(buf, 0, n);
+ while (inf.inflate(tmp, 0, tmp.length) > 0)
+ continue;
+ pos += n;
+ cnt -= n;
+ }
+ }
+ if (!inf.finished() || inf.getBytesRead() != dataLength) {
+ setCorrupt(src.offset);
+ throw new EOFException(MessageFormat.format(
+ JGitText.get().shortCompressedStreamAt,
+ Long.valueOf(src.offset)));
+ }
+ assert(crc1 != null);
+ expectedCRC = crc1.getValue();
+ } else {
+ expectedCRC = -1;
+ }
+ } catch (DataFormatException dataFormat) {
+ setCorrupt(src.offset);
+
+ CorruptObjectException corruptObject = new CorruptObjectException(
+ MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackFile()),
+ dataFormat);
+
+ throw new StoredObjectRepresentationNotAvailableException(src,
+ corruptObject);
+
+ } catch (IOException ioError) {
+ throw new StoredObjectRepresentationNotAvailableException(src,
+ ioError);
+ }
+
+ if (quickCopy != null) {
+ // The entire object fits into a single byte array window slice,
+ // and we have it pinned. Write this out without copying.
+ //
+ out.writeHeader(src, inflatedLength);
+ quickCopy.write(out, dataOffset, (int) dataLength);
+
+ } else if (dataLength <= buf.length) {
+ // Tiny optimization: Lots of objects are very small deltas or
+ // deflated commits that are likely to fit in the copy buffer.
+ //
+ if (!validate) {
+ long pos = dataOffset;
+ long cnt = dataLength;
+ while (cnt > 0) {
+ final int n = (int) Math.min(cnt, buf.length);
+ readFully(pos, buf, 0, n, curs);
+ pos += n;
+ cnt -= n;
+ }
+ }
+ out.writeHeader(src, inflatedLength);
+ out.write(buf, 0, (int) dataLength);
+ } else {
+ // Now we are committed to sending the object. As we spool it out,
+ // check its CRC32 code to make sure there wasn't corruption between
+ // the verification we did above, and us actually outputting it.
+ //
+ out.writeHeader(src, inflatedLength);
+ long pos = dataOffset;
+ long cnt = dataLength;
+ while (cnt > 0) {
+ final int n = (int) Math.min(cnt, buf.length);
+ readFully(pos, buf, 0, n, curs);
+ if (validate) {
+ assert(crc2 != null);
+ crc2.update(buf, 0, n);
+ }
+ out.write(buf, 0, n);
+ pos += n;
+ cnt -= n;
+ }
+ if (validate) {
+ assert(crc2 != null);
+ if (crc2.getValue() != expectedCRC) {
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackFile()));
+ }
+ }
+ }
+ }
+
+ boolean invalid() {
+ return invalid;
+ }
+
+ void setInvalid() {
+ invalid = true;
+ }
+
+ int incrementTransientErrorCount() {
+ return transientErrorCount.incrementAndGet();
+ }
+
+ void resetTransientErrorCount() {
+ transientErrorCount.set(0);
+ }
+
+ private void readFully(final long position, final byte[] dstbuf,
+ int dstoff, final int cnt, final WindowCursor curs)
+ throws IOException {
+ if (curs.copy(this, position, dstbuf, dstoff, cnt) != cnt)
+ throw new EOFException();
+ }
+
+ private synchronized void beginCopyAsIs(ObjectToPack otp)
+ throws StoredObjectRepresentationNotAvailableException {
+ if (++activeCopyRawData == 1 && activeWindows == 0) {
+ try {
+ doOpen();
+ } catch (IOException thisPackNotValid) {
+ throw new StoredObjectRepresentationNotAvailableException(otp,
+ thisPackNotValid);
+ }
+ }
+ }
+
+ private synchronized void endCopyAsIs() {
+ if (--activeCopyRawData == 0 && activeWindows == 0)
+ doClose();
+ }
+
+ synchronized boolean beginWindowCache() throws IOException {
+ if (++activeWindows == 1) {
+ if (activeCopyRawData == 0)
+ doOpen();
+ return true;
+ }
+ return false;
+ }
+
+ synchronized boolean endWindowCache() {
+ final boolean r = --activeWindows == 0;
+ if (r && activeCopyRawData == 0)
+ doClose();
+ return r;
+ }
+
+ private void doOpen() throws IOException {
+ if (invalid) {
+ openFail(true, invalidatingCause);
+ throw new PackInvalidException(packFile, invalidatingCause);
+ }
+ try {
+ synchronized (readLock) {
+ fd = new RandomAccessFile(packFile, "r"); //$NON-NLS-1$
+ length = fd.length();
+ onOpenPack();
+ }
+ } catch (InterruptedIOException e) {
+ // don't invalidate the pack, we are interrupted from another thread
+ openFail(false, e);
+ throw e;
+ } catch (FileNotFoundException fn) {
+ // don't invalidate the pack if opening an existing file failed
+ // since it may be related to a temporary lack of resources (e.g.
+ // max open files)
+ openFail(!packFile.exists(), fn);
+ throw fn;
+ } catch (EOFException | AccessDeniedException | NoSuchFileException
+ | CorruptObjectException | NoPackSignatureException
+ | PackMismatchException | UnpackException
+ | UnsupportedPackIndexVersionException
+ | UnsupportedPackVersionException pe) {
+ // exceptions signaling permanent problems with a pack
+ openFail(true, pe);
+ throw pe;
+ } catch (IOException | RuntimeException ge) {
+ // generic exceptions could be transient so we should not mark the
+ // pack invalid to avoid false MissingObjectExceptions
+ openFail(false, ge);
+ throw ge;
+ }
+ }
+
+ private void openFail(boolean invalidate, Exception cause) {
+ activeWindows = 0;
+ activeCopyRawData = 0;
+ invalid = invalidate;
+ invalidatingCause = cause;
+ doClose();
+ }
+
+ private void doClose() {
+ synchronized (readLock) {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException err) {
+ // Ignore a close event. We had it open only for reading.
+ // There should not be errors related to network buffers
+ // not flushed, etc.
+ }
+ fd = null;
+ }
+ }
+ }
+
+ ByteArrayWindow read(long pos, int size) throws IOException {
+ synchronized (readLock) {
+ if (invalid || fd == null) {
+ // Due to concurrency between a read and another packfile invalidation thread
+ // one thread could come up to this point and then fail with NPE.
+ // Detect the situation and throw a proper exception so that can be properly
+ // managed by the main packfile search loop and the Git client won't receive
+ // any failures.
+ throw new PackInvalidException(packFile, invalidatingCause);
+ }
+ if (length < pos + size)
+ size = (int) (length - pos);
+ final byte[] buf = new byte[size];
+ fd.seek(pos);
+ fd.readFully(buf, 0, size);
+ return new ByteArrayWindow(this, pos, buf);
+ }
+ }
+
+ ByteWindow mmap(long pos, int size) throws IOException {
+ synchronized (readLock) {
+ if (length < pos + size)
+ size = (int) (length - pos);
+
+ MappedByteBuffer map;
+ try {
+ map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
+ } catch (IOException ioe1) {
+ // The most likely reason this failed is the JVM has run out
+ // of virtual memory. We need to discard quickly, and try to
+ // force the GC to finalize and release any existing mappings.
+ //
+ System.gc();
+ System.runFinalization();
+ map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
+ }
+
+ if (map.hasArray())
+ return new ByteArrayWindow(this, pos, map.array());
+ return new ByteBufferWindow(this, pos, map);
+ }
+ }
+
+ private void onOpenPack() throws IOException {
+ final PackIndex idx = idx();
+ final byte[] buf = new byte[20];
+
+ fd.seek(0);
+ fd.readFully(buf, 0, 12);
+ if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4) {
+ throw new NoPackSignatureException(JGitText.get().notAPACKFile);
+ }
+ final long vers = NB.decodeUInt32(buf, 4);
+ final long packCnt = NB.decodeUInt32(buf, 8);
+ if (vers != 2 && vers != 3) {
+ throw new UnsupportedPackVersionException(vers);
+ }
+
+ if (packCnt != idx.getObjectCount()) {
+ throw new PackMismatchException(MessageFormat.format(
+ JGitText.get().packObjectCountMismatch,
+ Long.valueOf(packCnt), Long.valueOf(idx.getObjectCount()),
+ getPackFile()));
+ }
+
+ fd.seek(length - 20);
+ fd.readFully(buf, 0, 20);
+ if (!Arrays.equals(buf, packChecksum)) {
+ throw new PackMismatchException(MessageFormat.format(
+ JGitText.get().packChecksumMismatch,
+ getPackFile(),
+ ObjectId.fromRaw(buf).name(),
+ ObjectId.fromRaw(idx.packChecksum).name()));
+ }
+ }
+
+ ObjectLoader load(WindowCursor curs, long pos)
+ throws IOException, LargeObjectException {
+ try {
+ final byte[] ib = curs.tempId;
+ Delta delta = null;
+ byte[] data = null;
+ int type = Constants.OBJ_BAD;
+ boolean cached = false;
+
+ SEARCH: for (;;) {
+ readFully(pos, ib, 0, 20, curs);
+ int c = ib[0] & 0xff;
+ final int typeCode = (c >> 4) & 7;
+ long sz = c & 15;
+ int shift = 4;
+ int p = 1;
+ while ((c & 0x80) != 0) {
+ c = ib[p++] & 0xff;
+ sz += ((long) (c & 0x7f)) << shift;
+ shift += 7;
+ }
+
+ switch (typeCode) {
+ case Constants.OBJ_COMMIT:
+ case Constants.OBJ_TREE:
+ case Constants.OBJ_BLOB:
+ case Constants.OBJ_TAG: {
+ if (delta != null || sz < curs.getStreamFileThreshold()) {
+ data = decompress(pos + p, (int) sz, curs);
+ }
+
+ if (delta != null) {
+ type = typeCode;
+ break SEARCH;
+ }
+
+ if (data != null) {
+ return new ObjectLoader.SmallObject(typeCode, data);
+ }
+ return new LargePackedWholeObject(typeCode, sz, pos, p,
+ this, curs.db);
+ }
+
+ case Constants.OBJ_OFS_DELTA: {
+ c = ib[p++] & 0xff;
+ long base = c & 127;
+ while ((c & 128) != 0) {
+ base += 1;
+ c = ib[p++] & 0xff;
+ base <<= 7;
+ base += (c & 127);
+ }
+ base = pos - base;
+ delta = new Delta(delta, pos, (int) sz, p, base);
+ if (sz != delta.deltaSize)
+ break SEARCH;
+
+ DeltaBaseCache.Entry e = curs.getDeltaBaseCache().get(this, base);
+ if (e != null) {
+ type = e.type;
+ data = e.data;
+ cached = true;
+ break SEARCH;
+ }
+ pos = base;
+ continue SEARCH;
+ }
+
+ case Constants.OBJ_REF_DELTA: {
+ readFully(pos + p, ib, 0, 20, curs);
+ long base = findDeltaBase(ObjectId.fromRaw(ib));
+ delta = new Delta(delta, pos, (int) sz, p + 20, base);
+ if (sz != delta.deltaSize)
+ break SEARCH;
+
+ DeltaBaseCache.Entry e = curs.getDeltaBaseCache().get(this, base);
+ if (e != null) {
+ type = e.type;
+ data = e.data;
+ cached = true;
+ break SEARCH;
+ }
+ pos = base;
+ continue SEARCH;
+ }
+
+ default:
+ throw new IOException(MessageFormat.format(
+ JGitText.get().unknownObjectType,
+ Integer.valueOf(typeCode)));
+ }
+ }
+
+ // At this point there is at least one delta to apply to data.
+ // (Whole objects with no deltas to apply return early above.)
+
+ if (data == null)
+ throw new IOException(JGitText.get().inMemoryBufferLimitExceeded);
+
+ assert(delta != null);
+ do {
+ // Cache only the base immediately before desired object.
+ if (cached)
+ cached = false;
+ else if (delta.next == null)
+ curs.getDeltaBaseCache().store(this, delta.basePos, data, type);
+
+ pos = delta.deltaPos;
+
+ final byte[] cmds = decompress(pos + delta.hdrLen,
+ delta.deltaSize, curs);
+ if (cmds == null) {
+ data = null; // Discard base in case of OutOfMemoryError
+ throw new LargeObjectException.OutOfMemory(new OutOfMemoryError());
+ }
+
+ final long sz = BinaryDelta.getResultSize(cmds);
+ if (Integer.MAX_VALUE <= sz)
+ throw new LargeObjectException.ExceedsByteArrayLimit();
+
+ final byte[] result;
+ try {
+ result = new byte[(int) sz];
+ } catch (OutOfMemoryError tooBig) {
+ data = null; // Discard base in case of OutOfMemoryError
+ throw new LargeObjectException.OutOfMemory(tooBig);
+ }
+
+ BinaryDelta.apply(data, cmds, result);
+ data = result;
+ delta = delta.next;
+ } while (delta != null);
+
+ return new ObjectLoader.SmallObject(type, data);
+
+ } catch (DataFormatException dfe) {
+ throw new CorruptObjectException(
+ MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(pos), getPackFile()),
+ dfe);
+ }
+ }
+
+ private long findDeltaBase(ObjectId baseId) throws IOException,
+ MissingObjectException {
+ long ofs = idx().findOffset(baseId);
+ if (ofs < 0)
+ throw new MissingObjectException(baseId,
+ JGitText.get().missingDeltaBase);
+ return ofs;
+ }
+
+ private static class Delta {
+ /** Child that applies onto this object. */
+ final Delta next;
+
+ /** Offset of the delta object. */
+ final long deltaPos;
+
+ /** Size of the inflated delta stream. */
+ final int deltaSize;
+
+ /** Total size of the delta's pack entry header (including base). */
+ final int hdrLen;
+
+ /** Offset of the base object this delta applies onto. */
+ final long basePos;
+
+ Delta(Delta next, long ofs, int sz, int hdrLen, long baseOffset) {
+ this.next = next;
+ this.deltaPos = ofs;
+ this.deltaSize = sz;
+ this.hdrLen = hdrLen;
+ this.basePos = baseOffset;
+ }
+ }
+
+ byte[] getDeltaHeader(WindowCursor wc, long pos)
+ throws IOException, DataFormatException {
+ // The delta stream starts as two variable length integers. If we
+ // assume they are 64 bits each, we need 16 bytes to encode them,
+ // plus 2 extra bytes for the variable length overhead. So 18 is
+ // the longest delta instruction header.
+ //
+ final byte[] hdr = new byte[18];
+ wc.inflate(this, pos, hdr, true /* headerOnly */);
+ return hdr;
+ }
+
+ int getObjectType(WindowCursor curs, long pos) throws IOException {
+ final byte[] ib = curs.tempId;
+ for (;;) {
+ readFully(pos, ib, 0, 20, curs);
+ int c = ib[0] & 0xff;
+ final int type = (c >> 4) & 7;
+
+ switch (type) {
+ case Constants.OBJ_COMMIT:
+ case Constants.OBJ_TREE:
+ case Constants.OBJ_BLOB:
+ case Constants.OBJ_TAG:
+ return type;
+
+ case Constants.OBJ_OFS_DELTA: {
+ int p = 1;
+ while ((c & 0x80) != 0)
+ c = ib[p++] & 0xff;
+ c = ib[p++] & 0xff;
+ long ofs = c & 127;
+ while ((c & 128) != 0) {
+ ofs += 1;
+ c = ib[p++] & 0xff;
+ ofs <<= 7;
+ ofs += (c & 127);
+ }
+ pos = pos - ofs;
+ continue;
+ }
+
+ case Constants.OBJ_REF_DELTA: {
+ int p = 1;
+ while ((c & 0x80) != 0)
+ c = ib[p++] & 0xff;
+ readFully(pos + p, ib, 0, 20, curs);
+ pos = findDeltaBase(ObjectId.fromRaw(ib));
+ continue;
+ }
+
+ default:
+ throw new IOException(
+ MessageFormat.format(JGitText.get().unknownObjectType,
+ Integer.valueOf(type)));
+ }
+ }
+ }
+
+ long getObjectSize(WindowCursor curs, AnyObjectId id)
+ throws IOException {
+ final long offset = idx().findOffset(id);
+ return 0 < offset ? getObjectSize(curs, offset) : -1;
+ }
+
+ long getObjectSize(WindowCursor curs, long pos)
+ throws IOException {
+ final byte[] ib = curs.tempId;
+ readFully(pos, ib, 0, 20, curs);
+ int c = ib[0] & 0xff;
+ final int type = (c >> 4) & 7;
+ long sz = c & 15;
+ int shift = 4;
+ int p = 1;
+ while ((c & 0x80) != 0) {
+ c = ib[p++] & 0xff;
+ sz += ((long) (c & 0x7f)) << shift;
+ shift += 7;
+ }
+
+ long deltaAt;
+ switch (type) {
+ case Constants.OBJ_COMMIT:
+ case Constants.OBJ_TREE:
+ case Constants.OBJ_BLOB:
+ case Constants.OBJ_TAG:
+ return sz;
+
+ case Constants.OBJ_OFS_DELTA:
+ c = ib[p++] & 0xff;
+ while ((c & 128) != 0)
+ c = ib[p++] & 0xff;
+ deltaAt = pos + p;
+ break;
+
+ case Constants.OBJ_REF_DELTA:
+ deltaAt = pos + p + 20;
+ break;
+
+ default:
+ throw new IOException(MessageFormat.format(
+ JGitText.get().unknownObjectType, Integer.valueOf(type)));
+ }
+
+ try {
+ return BinaryDelta.getResultSize(getDeltaHeader(curs, deltaAt));
+ } catch (DataFormatException e) {
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream, Long.valueOf(pos),
+ getPackFile()), e);
+ }
+ }
+
+ LocalObjectRepresentation representation(final WindowCursor curs,
+ final AnyObjectId objectId) throws IOException {
+ final long pos = idx().findOffset(objectId);
+ if (pos < 0)
+ return null;
+
+ final byte[] ib = curs.tempId;
+ readFully(pos, ib, 0, 20, curs);
+ int c = ib[0] & 0xff;
+ int p = 1;
+ final int typeCode = (c >> 4) & 7;
+ while ((c & 0x80) != 0)
+ c = ib[p++] & 0xff;
+
+ long len = (findEndOffset(pos) - pos);
+ switch (typeCode) {
+ case Constants.OBJ_COMMIT:
+ case Constants.OBJ_TREE:
+ case Constants.OBJ_BLOB:
+ case Constants.OBJ_TAG:
+ return LocalObjectRepresentation.newWhole(this, pos, len - p);
+
+ case Constants.OBJ_OFS_DELTA: {
+ c = ib[p++] & 0xff;
+ long ofs = c & 127;
+ while ((c & 128) != 0) {
+ ofs += 1;
+ c = ib[p++] & 0xff;
+ ofs <<= 7;
+ ofs += (c & 127);
+ }
+ ofs = pos - ofs;
+ return LocalObjectRepresentation.newDelta(this, pos, len - p, ofs);
+ }
+
+ case Constants.OBJ_REF_DELTA: {
+ len -= p;
+ len -= Constants.OBJECT_ID_LENGTH;
+ readFully(pos + p, ib, 0, 20, curs);
+ ObjectId id = ObjectId.fromRaw(ib);
+ return LocalObjectRepresentation.newDelta(this, pos, len, id);
+ }
+
+ default:
+ throw new IOException(
+ MessageFormat.format(JGitText.get().unknownObjectType,
+ Integer.valueOf(typeCode)));
+ }
+ }
+
+ private long findEndOffset(long startOffset)
+ throws IOException, CorruptObjectException {
+ final long maxOffset = length - 20;
+ return getReverseIdx().findNextOffset(startOffset, maxOffset);
+ }
+
+ synchronized PackBitmapIndex getBitmapIndex() throws IOException {
+ if (invalid || invalidBitmap)
+ return null;
+ if (bitmapIdx == null && hasExt(BITMAP_INDEX)) {
+ final PackBitmapIndex idx;
+ try {
+ idx = PackBitmapIndex.open(extFile(BITMAP_INDEX), idx(),
+ getReverseIdx());
+ } catch (FileNotFoundException e) {
+ // Once upon a time this bitmap file existed. Now it
+ // has been removed. Most likely an external gc has
+ // removed this packfile and the bitmap
+ invalidBitmap = true;
+ return null;
+ }
+
+ // At this point, idx() will have set packChecksum.
+ if (Arrays.equals(packChecksum, idx.packChecksum))
+ bitmapIdx = idx;
+ else
+ invalidBitmap = true;
+ }
+ return bitmapIdx;
+ }
+
+ private synchronized PackReverseIndex getReverseIdx() throws IOException {
+ if (reverseIdx == null)
+ reverseIdx = new PackReverseIndex(idx());
+ return reverseIdx;
+ }
+
+ private boolean isCorrupt(long offset) {
+ LongList list = corruptObjects;
+ if (list == null)
+ return false;
+ synchronized (list) {
+ return list.contains(offset);
+ }
+ }
+
+ private void setCorrupt(long offset) {
+ LongList list = corruptObjects;
+ if (list == null) {
+ synchronized (readLock) {
+ list = corruptObjects;
+ if (list == null) {
+ list = new LongList();
+ corruptObjects = list;
+ }
+ }
+ }
+ synchronized (list) {
+ list.add(offset);
+ }
+ }
+
+ private File extFile(PackExt ext) {
+ String p = packFile.getName();
+ int dot = p.lastIndexOf('.');
+ String b = (dot < 0) ? p : p.substring(0, dot);
+ return new File(packFile.getParentFile(), b + '.' + ext.getExtension());
+ }
+
+ private boolean hasExt(PackExt ext) {
+ return (extensions & ext.getBit()) != 0;
+ }
+
+ @SuppressWarnings("nls")
+ @Override
+ public String toString() {
+ return "Pack [packFileName=" + packFile.getName() + ", length="
+ + packFile.length() + ", packChecksum="
+ + ObjectId.fromRaw(packChecksum).name() + "]";
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
index fd9da7c6c4..b2ba36bf91 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
@@ -47,16 +47,17 @@ import org.slf4j.LoggerFactory;
/**
* Traditional file system packed objects directory handler.
*
- * This is the {@code PackFile}s object representation for a Git object
- * database, where objects are stored in compressed containers known as
- * {@link org.eclipse.jgit.internal.storage.file.PackFile}s.
+ * This is the {@link org.eclipse.jgit.internal.storage.file.Pack}s object
+ * representation for a Git object database, where objects are stored in
+ * compressed containers known as
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}s.
*/
class PackDirectory {
private final static Logger LOG = LoggerFactory
.getLogger(PackDirectory.class);
private static final PackList NO_PACKS = new PackList(FileSnapshot.DIRTY,
- new PackFile[0]);
+ new Pack[0]);
private final Config config;
@@ -94,18 +95,18 @@ class PackDirectory {
void close() {
PackList packs = packList.get();
if (packs != NO_PACKS && packList.compareAndSet(packs, NO_PACKS)) {
- for (PackFile p : packs.packs) {
+ for (Pack p : packs.packs) {
p.close();
}
}
}
- Collection getPacks() {
+ Collection getPacks() {
PackList list = packList.get();
if (list == NO_PACKS) {
list = scanPacks(list);
}
- PackFile[] packs = list.packs;
+ Pack[] packs = list.packs;
return Collections.unmodifiableCollection(Arrays.asList(packs));
}
@@ -126,7 +127,7 @@ class PackDirectory {
PackList pList;
do {
pList = packList.get();
- for (PackFile p : pList.packs) {
+ for (Pack p : pList.packs) {
try {
if (p.hasObject(objectId)) {
return true;
@@ -167,7 +168,7 @@ class PackDirectory {
PackList pList;
do {
pList = packList.get();
- for (PackFile p : pList.packs) {
+ for (Pack p : pList.packs) {
try {
p.resolve(matches, id, matchLimit);
p.resetTransientErrorCount();
@@ -187,7 +188,7 @@ class PackDirectory {
do {
SEARCH: for (;;) {
pList = packList.get();
- for (PackFile p : pList.packs) {
+ for (Pack p : pList.packs) {
try {
ObjectLoader ldr = p.get(curs, objectId);
p.resetTransientErrorCount();
@@ -213,7 +214,7 @@ class PackDirectory {
do {
SEARCH: for (;;) {
pList = packList.get();
- for (PackFile p : pList.packs) {
+ for (Pack p : pList.packs) {
try {
long len = p.getObjectSize(curs, id);
p.resetTransientErrorCount();
@@ -239,7 +240,7 @@ class PackDirectory {
WindowCursor curs) {
PackList pList = packList.get();
SEARCH: for (;;) {
- for (PackFile p : pList.packs) {
+ for (Pack p : pList.packs) {
try {
LocalObjectRepresentation rep = p.representation(curs, otp);
p.resetTransientErrorCount();
@@ -259,7 +260,7 @@ class PackDirectory {
}
}
- private void handlePackError(IOException e, PackFile p) {
+ private void handlePackError(IOException e, Pack p) {
String warnTmpl = null;
int transientErrorCount = 0;
String errTmpl = JGitText.get().exceptionWhileReadingPack;
@@ -322,7 +323,7 @@ class PackDirectory {
&& old != scanPacks(old);
}
- void insert(PackFile pf) {
+ void insert(Pack pack) {
PackList o, n;
do {
o = packList.get();
@@ -331,33 +332,33 @@ class PackDirectory {
// (picked up by a concurrent thread that did a scan?) we
// do not want to insert it a second time.
//
- final PackFile[] oldList = o.packs;
- final String name = pf.getPackFile().getName();
- for (PackFile p : oldList) {
+ final Pack[] oldList = o.packs;
+ final String name = pack.getPackFile().getName();
+ for (Pack p : oldList) {
if (name.equals(p.getPackFile().getName())) {
return;
}
}
- final PackFile[] newList = new PackFile[1 + oldList.length];
- newList[0] = pf;
+ final Pack[] newList = new Pack[1 + oldList.length];
+ newList[0] = pack;
System.arraycopy(oldList, 0, newList, 1, oldList.length);
n = new PackList(o.snapshot, newList);
} while (!packList.compareAndSet(o, n));
}
- private void remove(PackFile deadPack) {
+ private void remove(Pack deadPack) {
PackList o, n;
do {
o = packList.get();
- final PackFile[] oldList = o.packs;
+ final Pack[] oldList = o.packs;
final int j = indexOf(oldList, deadPack);
if (j < 0) {
break;
}
- final PackFile[] newList = new PackFile[oldList.length - 1];
+ final Pack[] newList = new Pack[oldList.length - 1];
System.arraycopy(oldList, 0, newList, 0, j);
System.arraycopy(oldList, j + 1, newList, j, newList.length - j);
n = new PackList(o.snapshot, newList);
@@ -365,7 +366,7 @@ class PackDirectory {
deadPack.close();
}
- private static int indexOf(PackFile[] list, PackFile pack) {
+ private static int indexOf(Pack[] list, Pack pack) {
for (int i = 0; i < list.length; i++) {
if (list[i] == pack) {
return i;
@@ -395,10 +396,10 @@ class PackDirectory {
}
private PackList scanPacksImpl(PackList old) {
- final Map forReuse = reuseMap(old);
+ final Map forReuse = reuseMap(old);
final FileSnapshot snapshot = FileSnapshot.save(directory);
final Set names = listPackDirectory();
- final List list = new ArrayList<>(names.size() >> 2);
+ final List list = new ArrayList<>(names.size() >> 2);
boolean foundNew = false;
for (String indexName : names) {
// Must match "pack-[0-9a-f]{40}.idx" to be an index.
@@ -425,7 +426,7 @@ class PackDirectory {
final String packName = base + PACK.getExtension();
final File packFile = new File(directory, packName);
- final PackFile oldPack = forReuse.get(packName);
+ final Pack oldPack = forReuse.get(packName);
if (oldPack != null
&& !oldPack.getFileSnapshot().isModified(packFile)) {
forReuse.remove(packName);
@@ -433,7 +434,7 @@ class PackDirectory {
continue;
}
- list.add(new PackFile(packFile, extensions));
+ list.add(new Pack(packFile, extensions));
foundNew = true;
}
@@ -447,7 +448,7 @@ class PackDirectory {
return old;
}
- for (PackFile p : forReuse.values()) {
+ for (Pack p : forReuse.values()) {
p.close();
}
@@ -455,14 +456,14 @@ class PackDirectory {
return new PackList(snapshot, NO_PACKS.packs);
}
- final PackFile[] r = list.toArray(new PackFile[0]);
- Arrays.sort(r, PackFile.SORT);
+ final Pack[] r = list.toArray(new Pack[0]);
+ Arrays.sort(r, Pack.SORT);
return new PackList(snapshot, r);
}
- private static Map reuseMap(PackList old) {
- final Map forReuse = new HashMap<>();
- for (PackFile p : old.packs) {
+ private static Map reuseMap(PackList old) {
+ final Map forReuse = new HashMap<>();
+ for (Pack p : old.packs) {
if (p.invalid()) {
// The pack instance is corrupted, and cannot be safely used
// again. Do not include it in our reuse map.
@@ -471,7 +472,7 @@ class PackDirectory {
continue;
}
- final PackFile prior = forReuse.put(p.getPackFile().getName(), p);
+ final Pack prior = forReuse.put(p.getPackFile().getName(), p);
if (prior != null) {
// This should never occur. It should be impossible for us
// to have two pack files with the same name, as all of them
@@ -504,10 +505,10 @@ class PackDirectory {
/** State just before reading the pack directory. */
final FileSnapshot snapshot;
- /** All known packs, sorted by {@link PackFile#SORT}. */
- final PackFile[] packs;
+ /** All known packs, sorted by {@link Pack#SORT}. */
+ final Pack[] packs;
- PackList(FileSnapshot monitor, PackFile[] packs) {
+ PackList(FileSnapshot monitor, Pack[] packs) {
this.snapshot = monitor;
this.packs = packs;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
deleted file mode 100644
index e112fe7444..0000000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ /dev/null
@@ -1,1208 +0,0 @@
-/*
- * Copyright (C) 2008-2009, Google Inc.
- * Copyright (C) 2007, Robin Rosenberg
- * Copyright (C) 2006-2008, Shawn O. Pearce and others
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Distribution License v. 1.0 which is available at
- * https://www.eclipse.org/org/documents/edl-v10.php.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-package org.eclipse.jgit.internal.storage.file;
-
-import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
-import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
-import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP;
-
-import java.io.EOFException;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.io.RandomAccessFile;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel.MapMode;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.NoSuchFileException;
-import java.text.MessageFormat;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.zip.CRC32;
-import java.util.zip.DataFormatException;
-import java.util.zip.Inflater;
-
-import org.eclipse.jgit.errors.CorruptObjectException;
-import org.eclipse.jgit.errors.LargeObjectException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.errors.NoPackSignatureException;
-import org.eclipse.jgit.errors.PackInvalidException;
-import org.eclipse.jgit.errors.PackMismatchException;
-import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
-import org.eclipse.jgit.errors.UnpackException;
-import org.eclipse.jgit.errors.UnsupportedPackIndexVersionException;
-import org.eclipse.jgit.errors.UnsupportedPackVersionException;
-import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
-import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
-import org.eclipse.jgit.internal.storage.pack.PackExt;
-import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
-import org.eclipse.jgit.lib.AbbreviatedObjectId;
-import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectLoader;
-import org.eclipse.jgit.util.LongList;
-import org.eclipse.jgit.util.NB;
-import org.eclipse.jgit.util.RawParseUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A Git version 2 pack file representation. A pack file contains Git objects in
- * delta packed format yielding high compression of lots of object where some
- * objects are similar.
- */
-public class PackFile implements Iterable {
- private static final Logger LOG = LoggerFactory.getLogger(PackFile.class);
-
- /**
- * Sorts PackFiles to be most recently created to least recently created.
- */
- public static final Comparator SORT = (a, b) -> b.packLastModified
- .compareTo(a.packLastModified);
-
- private final File packFile;
-
- private final int extensions;
-
- private File keepFile;
-
- private volatile String packName;
-
- final int hash;
-
- private RandomAccessFile fd;
-
- /** Serializes reads performed against {@link #fd}. */
- private final Object readLock = new Object();
-
- long length;
-
- private int activeWindows;
-
- private int activeCopyRawData;
-
- Instant packLastModified;
-
- private PackFileSnapshot fileSnapshot;
-
- private volatile boolean invalid;
-
- private volatile Exception invalidatingCause;
-
- private boolean invalidBitmap;
-
- private AtomicInteger transientErrorCount = new AtomicInteger();
-
- private byte[] packChecksum;
-
- private volatile PackIndex loadedIdx;
-
- private PackReverseIndex reverseIdx;
-
- private PackBitmapIndex bitmapIdx;
-
- /**
- * Objects we have tried to read, and discovered to be corrupt.
- *
- * The list is allocated after the first corruption is found, and filled in
- * as more entries are discovered. Typically this list is never used, as
- * pack files do not usually contain corrupt objects.
- */
- private volatile LongList corruptObjects;
-
- /**
- * Construct a reader for an existing, pre-indexed packfile.
- *
- * @param packFile
- * path of the .pack
file holding the data.
- * @param extensions
- * additional pack file extensions with the same base as the pack
- */
- public PackFile(File packFile, int extensions) {
- this.packFile = packFile;
- this.fileSnapshot = PackFileSnapshot.save(packFile);
- this.packLastModified = fileSnapshot.lastModifiedInstant();
- this.extensions = extensions;
-
- // Multiply by 31 here so we can more directly combine with another
- // value in WindowCache.hash(), without doing the multiply there.
- //
- hash = System.identityHashCode(this) * 31;
- length = Long.MAX_VALUE;
- }
-
- private PackIndex idx() throws IOException {
- PackIndex idx = loadedIdx;
- if (idx == null) {
- synchronized (this) {
- idx = loadedIdx;
- if (idx == null) {
- if (invalid) {
- throw new PackInvalidException(packFile, invalidatingCause);
- }
- try {
- long start = System.currentTimeMillis();
- idx = PackIndex.open(extFile(INDEX));
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format(
- "Opening pack index %s, size %.3f MB took %d ms", //$NON-NLS-1$
- extFile(INDEX).getAbsolutePath(),
- Float.valueOf(extFile(INDEX).length()
- / (1024f * 1024)),
- Long.valueOf(System.currentTimeMillis()
- - start)));
- }
-
- if (packChecksum == null) {
- packChecksum = idx.packChecksum;
- fileSnapshot.setChecksum(
- ObjectId.fromRaw(packChecksum));
- } else if (!Arrays.equals(packChecksum,
- idx.packChecksum)) {
- throw new PackMismatchException(MessageFormat
- .format(JGitText.get().packChecksumMismatch,
- packFile.getPath(),
- ObjectId.fromRaw(packChecksum)
- .name(),
- ObjectId.fromRaw(idx.packChecksum)
- .name()));
- }
- loadedIdx = idx;
- } catch (InterruptedIOException e) {
- // don't invalidate the pack, we are interrupted from
- // another thread
- throw e;
- } catch (IOException e) {
- invalid = true;
- invalidatingCause = e;
- throw e;
- }
- }
- }
- }
- return idx;
- }
- /**
- * Get the File object which locates this pack on disk.
- *
- * @return the File object which locates this pack on disk.
- */
- public File getPackFile() {
- return packFile;
- }
-
- /**
- * Get the index for this pack file.
- *
- * @return the index for this pack file.
- * @throws java.io.IOException
- */
- public PackIndex getIndex() throws IOException {
- return idx();
- }
-
- /**
- * Get name extracted from {@code pack-*.pack} pattern.
- *
- * @return name extracted from {@code pack-*.pack} pattern.
- */
- public String getPackName() {
- String name = packName;
- if (name == null) {
- name = getPackFile().getName();
- if (name.startsWith("pack-")) //$NON-NLS-1$
- name = name.substring("pack-".length()); //$NON-NLS-1$
- if (name.endsWith(".pack")) //$NON-NLS-1$
- name = name.substring(0, name.length() - ".pack".length()); //$NON-NLS-1$
- packName = name;
- }
- return name;
- }
-
- /**
- * Determine if an object is contained within the pack file.
- *
- * For performance reasons only the index file is searched; the main pack
- * content is ignored entirely.
- *
- *
- * @param id
- * the object to look for. Must not be null.
- * @return true if the object is in this pack; false otherwise.
- * @throws java.io.IOException
- * the index file cannot be loaded into memory.
- */
- public boolean hasObject(AnyObjectId id) throws IOException {
- final long offset = idx().findOffset(id);
- return 0 < offset && !isCorrupt(offset);
- }
-
- /**
- * Determines whether a .keep file exists for this pack file.
- *
- * @return true if a .keep file exist.
- */
- public boolean shouldBeKept() {
- if (keepFile == null)
- keepFile = extFile(KEEP);
- return keepFile.exists();
- }
-
- /**
- * Get an object from this pack.
- *
- * @param curs
- * temporary working space associated with the calling thread.
- * @param id
- * the object to obtain from the pack. Must not be null.
- * @return the object loader for the requested object if it is contained in
- * this pack; null if the object was not found.
- * @throws IOException
- * the pack file or the index could not be read.
- */
- ObjectLoader get(WindowCursor curs, AnyObjectId id)
- throws IOException {
- final long offset = idx().findOffset(id);
- return 0 < offset && !isCorrupt(offset) ? load(curs, offset) : null;
- }
-
- void resolve(Set matches, AbbreviatedObjectId id, int matchLimit)
- throws IOException {
- idx().resolve(matches, id, matchLimit);
- }
-
- /**
- * Close the resources utilized by this repository
- */
- public void close() {
- WindowCache.purge(this);
- synchronized (this) {
- loadedIdx = null;
- reverseIdx = null;
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * Provide iterator over entries in associated pack index, that should also
- * exist in this pack file. Objects returned by such iterator are mutable
- * during iteration.
- *
- * Iterator returns objects in SHA-1 lexicographical order.
- *
- *
- * @see PackIndex#iterator()
- */
- @Override
- public Iterator iterator() {
- try {
- return idx().iterator();
- } catch (IOException e) {
- return Collections. emptyList().iterator();
- }
- }
-
- /**
- * Obtain the total number of objects available in this pack. This method
- * relies on pack index, giving number of effectively available objects.
- *
- * @return number of objects in index of this pack, likewise in this pack
- * @throws IOException
- * the index file cannot be loaded into memory.
- */
- long getObjectCount() throws IOException {
- return idx().getObjectCount();
- }
-
- /**
- * Search for object id with the specified start offset in associated pack
- * (reverse) index.
- *
- * @param offset
- * start offset of object to find
- * @return object id for this offset, or null if no object was found
- * @throws IOException
- * the index file cannot be loaded into memory.
- */
- ObjectId findObjectForOffset(long offset) throws IOException {
- return getReverseIdx().findObject(offset);
- }
-
- /**
- * Return the @{@link FileSnapshot} associated to the underlying packfile
- * that has been used when the object was created.
- *
- * @return the packfile @{@link FileSnapshot} that the object is loaded from.
- */
- PackFileSnapshot getFileSnapshot() {
- return fileSnapshot;
- }
-
- AnyObjectId getPackChecksum() {
- return ObjectId.fromRaw(packChecksum);
- }
-
- private final byte[] decompress(final long position, final int sz,
- final WindowCursor curs) throws IOException, DataFormatException {
- byte[] dstbuf;
- try {
- dstbuf = new byte[sz];
- } catch (OutOfMemoryError noMemory) {
- // The size may be larger than our heap allows, return null to
- // let the caller know allocation isn't possible and it should
- // use the large object streaming approach instead.
- //
- // For example, this can occur when sz is 640 MB, and JRE
- // maximum heap size is only 256 MB. Even if the JRE has
- // 200 MB free, it cannot allocate a 640 MB byte array.
- return null;
- }
-
- if (curs.inflate(this, position, dstbuf, false) != sz)
- throw new EOFException(MessageFormat.format(
- JGitText.get().shortCompressedStreamAt,
- Long.valueOf(position)));
- return dstbuf;
- }
-
- void copyPackAsIs(PackOutputStream out, WindowCursor curs)
- throws IOException {
- // Pin the first window, this ensures the length is accurate.
- curs.pin(this, 0);
- curs.copyPackAsIs(this, length, out);
- }
-
- final void copyAsIs(PackOutputStream out, LocalObjectToPack src,
- boolean validate, WindowCursor curs) throws IOException,
- StoredObjectRepresentationNotAvailableException {
- beginCopyAsIs(src);
- try {
- copyAsIs2(out, src, validate, curs);
- } finally {
- endCopyAsIs();
- }
- }
-
- private void copyAsIs2(PackOutputStream out, LocalObjectToPack src,
- boolean validate, WindowCursor curs) throws IOException,
- StoredObjectRepresentationNotAvailableException {
- final CRC32 crc1 = validate ? new CRC32() : null;
- final CRC32 crc2 = validate ? new CRC32() : null;
- final byte[] buf = out.getCopyBuffer();
-
- // Rip apart the header so we can discover the size.
- //
- readFully(src.offset, buf, 0, 20, curs);
- int c = buf[0] & 0xff;
- final int typeCode = (c >> 4) & 7;
- long inflatedLength = c & 15;
- int shift = 4;
- int headerCnt = 1;
- while ((c & 0x80) != 0) {
- c = buf[headerCnt++] & 0xff;
- inflatedLength += ((long) (c & 0x7f)) << shift;
- shift += 7;
- }
-
- if (typeCode == Constants.OBJ_OFS_DELTA) {
- do {
- c = buf[headerCnt++] & 0xff;
- } while ((c & 128) != 0);
- if (validate) {
- assert(crc1 != null && crc2 != null);
- crc1.update(buf, 0, headerCnt);
- crc2.update(buf, 0, headerCnt);
- }
- } else if (typeCode == Constants.OBJ_REF_DELTA) {
- if (validate) {
- assert(crc1 != null && crc2 != null);
- crc1.update(buf, 0, headerCnt);
- crc2.update(buf, 0, headerCnt);
- }
-
- readFully(src.offset + headerCnt, buf, 0, 20, curs);
- if (validate) {
- assert(crc1 != null && crc2 != null);
- crc1.update(buf, 0, 20);
- crc2.update(buf, 0, 20);
- }
- headerCnt += 20;
- } else if (validate) {
- assert(crc1 != null && crc2 != null);
- crc1.update(buf, 0, headerCnt);
- crc2.update(buf, 0, headerCnt);
- }
-
- final long dataOffset = src.offset + headerCnt;
- final long dataLength = src.length;
- final long expectedCRC;
- final ByteArrayWindow quickCopy;
-
- // Verify the object isn't corrupt before sending. If it is,
- // we report it missing instead.
- //
- try {
- quickCopy = curs.quickCopy(this, dataOffset, dataLength);
-
- if (validate && idx().hasCRC32Support()) {
- assert(crc1 != null);
- // Index has the CRC32 code cached, validate the object.
- //
- expectedCRC = idx().findCRC32(src);
- if (quickCopy != null) {
- quickCopy.crc32(crc1, dataOffset, (int) dataLength);
- } else {
- long pos = dataOffset;
- long cnt = dataLength;
- while (cnt > 0) {
- final int n = (int) Math.min(cnt, buf.length);
- readFully(pos, buf, 0, n, curs);
- crc1.update(buf, 0, n);
- pos += n;
- cnt -= n;
- }
- }
- if (crc1.getValue() != expectedCRC) {
- setCorrupt(src.offset);
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackFile()));
- }
- } else if (validate) {
- // We don't have a CRC32 code in the index, so compute it
- // now while inflating the raw data to get zlib to tell us
- // whether or not the data is safe.
- //
- Inflater inf = curs.inflater();
- byte[] tmp = new byte[1024];
- if (quickCopy != null) {
- quickCopy.check(inf, tmp, dataOffset, (int) dataLength);
- } else {
- assert(crc1 != null);
- long pos = dataOffset;
- long cnt = dataLength;
- while (cnt > 0) {
- final int n = (int) Math.min(cnt, buf.length);
- readFully(pos, buf, 0, n, curs);
- crc1.update(buf, 0, n);
- inf.setInput(buf, 0, n);
- while (inf.inflate(tmp, 0, tmp.length) > 0)
- continue;
- pos += n;
- cnt -= n;
- }
- }
- if (!inf.finished() || inf.getBytesRead() != dataLength) {
- setCorrupt(src.offset);
- throw new EOFException(MessageFormat.format(
- JGitText.get().shortCompressedStreamAt,
- Long.valueOf(src.offset)));
- }
- assert(crc1 != null);
- expectedCRC = crc1.getValue();
- } else {
- expectedCRC = -1;
- }
- } catch (DataFormatException dataFormat) {
- setCorrupt(src.offset);
-
- CorruptObjectException corruptObject = new CorruptObjectException(
- MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackFile()),
- dataFormat);
-
- throw new StoredObjectRepresentationNotAvailableException(src,
- corruptObject);
-
- } catch (IOException ioError) {
- throw new StoredObjectRepresentationNotAvailableException(src,
- ioError);
- }
-
- if (quickCopy != null) {
- // The entire object fits into a single byte array window slice,
- // and we have it pinned. Write this out without copying.
- //
- out.writeHeader(src, inflatedLength);
- quickCopy.write(out, dataOffset, (int) dataLength);
-
- } else if (dataLength <= buf.length) {
- // Tiny optimization: Lots of objects are very small deltas or
- // deflated commits that are likely to fit in the copy buffer.
- //
- if (!validate) {
- long pos = dataOffset;
- long cnt = dataLength;
- while (cnt > 0) {
- final int n = (int) Math.min(cnt, buf.length);
- readFully(pos, buf, 0, n, curs);
- pos += n;
- cnt -= n;
- }
- }
- out.writeHeader(src, inflatedLength);
- out.write(buf, 0, (int) dataLength);
- } else {
- // Now we are committed to sending the object. As we spool it out,
- // check its CRC32 code to make sure there wasn't corruption between
- // the verification we did above, and us actually outputting it.
- //
- out.writeHeader(src, inflatedLength);
- long pos = dataOffset;
- long cnt = dataLength;
- while (cnt > 0) {
- final int n = (int) Math.min(cnt, buf.length);
- readFully(pos, buf, 0, n, curs);
- if (validate) {
- assert(crc2 != null);
- crc2.update(buf, 0, n);
- }
- out.write(buf, 0, n);
- pos += n;
- cnt -= n;
- }
- if (validate) {
- assert(crc2 != null);
- if (crc2.getValue() != expectedCRC) {
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackFile()));
- }
- }
- }
- }
-
- boolean invalid() {
- return invalid;
- }
-
- void setInvalid() {
- invalid = true;
- }
-
- int incrementTransientErrorCount() {
- return transientErrorCount.incrementAndGet();
- }
-
- void resetTransientErrorCount() {
- transientErrorCount.set(0);
- }
-
- private void readFully(final long position, final byte[] dstbuf,
- int dstoff, final int cnt, final WindowCursor curs)
- throws IOException {
- if (curs.copy(this, position, dstbuf, dstoff, cnt) != cnt)
- throw new EOFException();
- }
-
- private synchronized void beginCopyAsIs(ObjectToPack otp)
- throws StoredObjectRepresentationNotAvailableException {
- if (++activeCopyRawData == 1 && activeWindows == 0) {
- try {
- doOpen();
- } catch (IOException thisPackNotValid) {
- throw new StoredObjectRepresentationNotAvailableException(otp,
- thisPackNotValid);
- }
- }
- }
-
- private synchronized void endCopyAsIs() {
- if (--activeCopyRawData == 0 && activeWindows == 0)
- doClose();
- }
-
- synchronized boolean beginWindowCache() throws IOException {
- if (++activeWindows == 1) {
- if (activeCopyRawData == 0)
- doOpen();
- return true;
- }
- return false;
- }
-
- synchronized boolean endWindowCache() {
- final boolean r = --activeWindows == 0;
- if (r && activeCopyRawData == 0)
- doClose();
- return r;
- }
-
- private void doOpen() throws IOException {
- if (invalid) {
- openFail(true, invalidatingCause);
- throw new PackInvalidException(packFile, invalidatingCause);
- }
- try {
- synchronized (readLock) {
- fd = new RandomAccessFile(packFile, "r"); //$NON-NLS-1$
- length = fd.length();
- onOpenPack();
- }
- } catch (InterruptedIOException e) {
- // don't invalidate the pack, we are interrupted from another thread
- openFail(false, e);
- throw e;
- } catch (FileNotFoundException fn) {
- // don't invalidate the pack if opening an existing file failed
- // since it may be related to a temporary lack of resources (e.g.
- // max open files)
- openFail(!packFile.exists(), fn);
- throw fn;
- } catch (EOFException | AccessDeniedException | NoSuchFileException
- | CorruptObjectException | NoPackSignatureException
- | PackMismatchException | UnpackException
- | UnsupportedPackIndexVersionException
- | UnsupportedPackVersionException pe) {
- // exceptions signaling permanent problems with a pack
- openFail(true, pe);
- throw pe;
- } catch (IOException | RuntimeException ge) {
- // generic exceptions could be transient so we should not mark the
- // pack invalid to avoid false MissingObjectExceptions
- openFail(false, ge);
- throw ge;
- }
- }
-
- private void openFail(boolean invalidate, Exception cause) {
- activeWindows = 0;
- activeCopyRawData = 0;
- invalid = invalidate;
- invalidatingCause = cause;
- doClose();
- }
-
- private void doClose() {
- synchronized (readLock) {
- if (fd != null) {
- try {
- fd.close();
- } catch (IOException err) {
- // Ignore a close event. We had it open only for reading.
- // There should not be errors related to network buffers
- // not flushed, etc.
- }
- fd = null;
- }
- }
- }
-
- ByteArrayWindow read(long pos, int size) throws IOException {
- synchronized (readLock) {
- if (invalid || fd == null) {
- // Due to concurrency between a read and another packfile invalidation thread
- // one thread could come up to this point and then fail with NPE.
- // Detect the situation and throw a proper exception so that can be properly
- // managed by the main packfile search loop and the Git client won't receive
- // any failures.
- throw new PackInvalidException(packFile, invalidatingCause);
- }
- if (length < pos + size)
- size = (int) (length - pos);
- final byte[] buf = new byte[size];
- fd.seek(pos);
- fd.readFully(buf, 0, size);
- return new ByteArrayWindow(this, pos, buf);
- }
- }
-
- ByteWindow mmap(long pos, int size) throws IOException {
- synchronized (readLock) {
- if (length < pos + size)
- size = (int) (length - pos);
-
- MappedByteBuffer map;
- try {
- map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
- } catch (IOException ioe1) {
- // The most likely reason this failed is the JVM has run out
- // of virtual memory. We need to discard quickly, and try to
- // force the GC to finalize and release any existing mappings.
- //
- System.gc();
- System.runFinalization();
- map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
- }
-
- if (map.hasArray())
- return new ByteArrayWindow(this, pos, map.array());
- return new ByteBufferWindow(this, pos, map);
- }
- }
-
- private void onOpenPack() throws IOException {
- final PackIndex idx = idx();
- final byte[] buf = new byte[20];
-
- fd.seek(0);
- fd.readFully(buf, 0, 12);
- if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4) {
- throw new NoPackSignatureException(JGitText.get().notAPACKFile);
- }
- final long vers = NB.decodeUInt32(buf, 4);
- final long packCnt = NB.decodeUInt32(buf, 8);
- if (vers != 2 && vers != 3) {
- throw new UnsupportedPackVersionException(vers);
- }
-
- if (packCnt != idx.getObjectCount()) {
- throw new PackMismatchException(MessageFormat.format(
- JGitText.get().packObjectCountMismatch,
- Long.valueOf(packCnt), Long.valueOf(idx.getObjectCount()),
- getPackFile()));
- }
-
- fd.seek(length - 20);
- fd.readFully(buf, 0, 20);
- if (!Arrays.equals(buf, packChecksum)) {
- throw new PackMismatchException(MessageFormat.format(
- JGitText.get().packChecksumMismatch,
- getPackFile(),
- ObjectId.fromRaw(buf).name(),
- ObjectId.fromRaw(idx.packChecksum).name()));
- }
- }
-
- ObjectLoader load(WindowCursor curs, long pos)
- throws IOException, LargeObjectException {
- try {
- final byte[] ib = curs.tempId;
- Delta delta = null;
- byte[] data = null;
- int type = Constants.OBJ_BAD;
- boolean cached = false;
-
- SEARCH: for (;;) {
- readFully(pos, ib, 0, 20, curs);
- int c = ib[0] & 0xff;
- final int typeCode = (c >> 4) & 7;
- long sz = c & 15;
- int shift = 4;
- int p = 1;
- while ((c & 0x80) != 0) {
- c = ib[p++] & 0xff;
- sz += ((long) (c & 0x7f)) << shift;
- shift += 7;
- }
-
- switch (typeCode) {
- case Constants.OBJ_COMMIT:
- case Constants.OBJ_TREE:
- case Constants.OBJ_BLOB:
- case Constants.OBJ_TAG: {
- if (delta != null || sz < curs.getStreamFileThreshold()) {
- data = decompress(pos + p, (int) sz, curs);
- }
-
- if (delta != null) {
- type = typeCode;
- break SEARCH;
- }
-
- if (data != null) {
- return new ObjectLoader.SmallObject(typeCode, data);
- }
- return new LargePackedWholeObject(typeCode, sz, pos, p,
- this, curs.db);
- }
-
- case Constants.OBJ_OFS_DELTA: {
- c = ib[p++] & 0xff;
- long base = c & 127;
- while ((c & 128) != 0) {
- base += 1;
- c = ib[p++] & 0xff;
- base <<= 7;
- base += (c & 127);
- }
- base = pos - base;
- delta = new Delta(delta, pos, (int) sz, p, base);
- if (sz != delta.deltaSize)
- break SEARCH;
-
- DeltaBaseCache.Entry e = curs.getDeltaBaseCache().get(this, base);
- if (e != null) {
- type = e.type;
- data = e.data;
- cached = true;
- break SEARCH;
- }
- pos = base;
- continue SEARCH;
- }
-
- case Constants.OBJ_REF_DELTA: {
- readFully(pos + p, ib, 0, 20, curs);
- long base = findDeltaBase(ObjectId.fromRaw(ib));
- delta = new Delta(delta, pos, (int) sz, p + 20, base);
- if (sz != delta.deltaSize)
- break SEARCH;
-
- DeltaBaseCache.Entry e = curs.getDeltaBaseCache().get(this, base);
- if (e != null) {
- type = e.type;
- data = e.data;
- cached = true;
- break SEARCH;
- }
- pos = base;
- continue SEARCH;
- }
-
- default:
- throw new IOException(MessageFormat.format(
- JGitText.get().unknownObjectType,
- Integer.valueOf(typeCode)));
- }
- }
-
- // At this point there is at least one delta to apply to data.
- // (Whole objects with no deltas to apply return early above.)
-
- if (data == null)
- throw new IOException(JGitText.get().inMemoryBufferLimitExceeded);
-
- assert(delta != null);
- do {
- // Cache only the base immediately before desired object.
- if (cached)
- cached = false;
- else if (delta.next == null)
- curs.getDeltaBaseCache().store(this, delta.basePos, data, type);
-
- pos = delta.deltaPos;
-
- final byte[] cmds = decompress(pos + delta.hdrLen,
- delta.deltaSize, curs);
- if (cmds == null) {
- data = null; // Discard base in case of OutOfMemoryError
- throw new LargeObjectException.OutOfMemory(new OutOfMemoryError());
- }
-
- final long sz = BinaryDelta.getResultSize(cmds);
- if (Integer.MAX_VALUE <= sz)
- throw new LargeObjectException.ExceedsByteArrayLimit();
-
- final byte[] result;
- try {
- result = new byte[(int) sz];
- } catch (OutOfMemoryError tooBig) {
- data = null; // Discard base in case of OutOfMemoryError
- throw new LargeObjectException.OutOfMemory(tooBig);
- }
-
- BinaryDelta.apply(data, cmds, result);
- data = result;
- delta = delta.next;
- } while (delta != null);
-
- return new ObjectLoader.SmallObject(type, data);
-
- } catch (DataFormatException dfe) {
- throw new CorruptObjectException(
- MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(pos), getPackFile()),
- dfe);
- }
- }
-
- private long findDeltaBase(ObjectId baseId) throws IOException,
- MissingObjectException {
- long ofs = idx().findOffset(baseId);
- if (ofs < 0)
- throw new MissingObjectException(baseId,
- JGitText.get().missingDeltaBase);
- return ofs;
- }
-
- private static class Delta {
- /** Child that applies onto this object. */
- final Delta next;
-
- /** Offset of the delta object. */
- final long deltaPos;
-
- /** Size of the inflated delta stream. */
- final int deltaSize;
-
- /** Total size of the delta's pack entry header (including base). */
- final int hdrLen;
-
- /** Offset of the base object this delta applies onto. */
- final long basePos;
-
- Delta(Delta next, long ofs, int sz, int hdrLen, long baseOffset) {
- this.next = next;
- this.deltaPos = ofs;
- this.deltaSize = sz;
- this.hdrLen = hdrLen;
- this.basePos = baseOffset;
- }
- }
-
- byte[] getDeltaHeader(WindowCursor wc, long pos)
- throws IOException, DataFormatException {
- // The delta stream starts as two variable length integers. If we
- // assume they are 64 bits each, we need 16 bytes to encode them,
- // plus 2 extra bytes for the variable length overhead. So 18 is
- // the longest delta instruction header.
- //
- final byte[] hdr = new byte[18];
- wc.inflate(this, pos, hdr, true /* headerOnly */);
- return hdr;
- }
-
- int getObjectType(WindowCursor curs, long pos) throws IOException {
- final byte[] ib = curs.tempId;
- for (;;) {
- readFully(pos, ib, 0, 20, curs);
- int c = ib[0] & 0xff;
- final int type = (c >> 4) & 7;
-
- switch (type) {
- case Constants.OBJ_COMMIT:
- case Constants.OBJ_TREE:
- case Constants.OBJ_BLOB:
- case Constants.OBJ_TAG:
- return type;
-
- case Constants.OBJ_OFS_DELTA: {
- int p = 1;
- while ((c & 0x80) != 0)
- c = ib[p++] & 0xff;
- c = ib[p++] & 0xff;
- long ofs = c & 127;
- while ((c & 128) != 0) {
- ofs += 1;
- c = ib[p++] & 0xff;
- ofs <<= 7;
- ofs += (c & 127);
- }
- pos = pos - ofs;
- continue;
- }
-
- case Constants.OBJ_REF_DELTA: {
- int p = 1;
- while ((c & 0x80) != 0)
- c = ib[p++] & 0xff;
- readFully(pos + p, ib, 0, 20, curs);
- pos = findDeltaBase(ObjectId.fromRaw(ib));
- continue;
- }
-
- default:
- throw new IOException(
- MessageFormat.format(JGitText.get().unknownObjectType,
- Integer.valueOf(type)));
- }
- }
- }
-
- long getObjectSize(WindowCursor curs, AnyObjectId id)
- throws IOException {
- final long offset = idx().findOffset(id);
- return 0 < offset ? getObjectSize(curs, offset) : -1;
- }
-
- long getObjectSize(WindowCursor curs, long pos)
- throws IOException {
- final byte[] ib = curs.tempId;
- readFully(pos, ib, 0, 20, curs);
- int c = ib[0] & 0xff;
- final int type = (c >> 4) & 7;
- long sz = c & 15;
- int shift = 4;
- int p = 1;
- while ((c & 0x80) != 0) {
- c = ib[p++] & 0xff;
- sz += ((long) (c & 0x7f)) << shift;
- shift += 7;
- }
-
- long deltaAt;
- switch (type) {
- case Constants.OBJ_COMMIT:
- case Constants.OBJ_TREE:
- case Constants.OBJ_BLOB:
- case Constants.OBJ_TAG:
- return sz;
-
- case Constants.OBJ_OFS_DELTA:
- c = ib[p++] & 0xff;
- while ((c & 128) != 0)
- c = ib[p++] & 0xff;
- deltaAt = pos + p;
- break;
-
- case Constants.OBJ_REF_DELTA:
- deltaAt = pos + p + 20;
- break;
-
- default:
- throw new IOException(MessageFormat.format(
- JGitText.get().unknownObjectType, Integer.valueOf(type)));
- }
-
- try {
- return BinaryDelta.getResultSize(getDeltaHeader(curs, deltaAt));
- } catch (DataFormatException e) {
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream, Long.valueOf(pos),
- getPackFile()), e);
- }
- }
-
- LocalObjectRepresentation representation(final WindowCursor curs,
- final AnyObjectId objectId) throws IOException {
- final long pos = idx().findOffset(objectId);
- if (pos < 0)
- return null;
-
- final byte[] ib = curs.tempId;
- readFully(pos, ib, 0, 20, curs);
- int c = ib[0] & 0xff;
- int p = 1;
- final int typeCode = (c >> 4) & 7;
- while ((c & 0x80) != 0)
- c = ib[p++] & 0xff;
-
- long len = (findEndOffset(pos) - pos);
- switch (typeCode) {
- case Constants.OBJ_COMMIT:
- case Constants.OBJ_TREE:
- case Constants.OBJ_BLOB:
- case Constants.OBJ_TAG:
- return LocalObjectRepresentation.newWhole(this, pos, len - p);
-
- case Constants.OBJ_OFS_DELTA: {
- c = ib[p++] & 0xff;
- long ofs = c & 127;
- while ((c & 128) != 0) {
- ofs += 1;
- c = ib[p++] & 0xff;
- ofs <<= 7;
- ofs += (c & 127);
- }
- ofs = pos - ofs;
- return LocalObjectRepresentation.newDelta(this, pos, len - p, ofs);
- }
-
- case Constants.OBJ_REF_DELTA: {
- len -= p;
- len -= Constants.OBJECT_ID_LENGTH;
- readFully(pos + p, ib, 0, 20, curs);
- ObjectId id = ObjectId.fromRaw(ib);
- return LocalObjectRepresentation.newDelta(this, pos, len, id);
- }
-
- default:
- throw new IOException(
- MessageFormat.format(JGitText.get().unknownObjectType,
- Integer.valueOf(typeCode)));
- }
- }
-
- private long findEndOffset(long startOffset)
- throws IOException, CorruptObjectException {
- final long maxOffset = length - 20;
- return getReverseIdx().findNextOffset(startOffset, maxOffset);
- }
-
- synchronized PackBitmapIndex getBitmapIndex() throws IOException {
- if (invalid || invalidBitmap)
- return null;
- if (bitmapIdx == null && hasExt(BITMAP_INDEX)) {
- final PackBitmapIndex idx;
- try {
- idx = PackBitmapIndex.open(extFile(BITMAP_INDEX), idx(),
- getReverseIdx());
- } catch (FileNotFoundException e) {
- // Once upon a time this bitmap file existed. Now it
- // has been removed. Most likely an external gc has
- // removed this packfile and the bitmap
- invalidBitmap = true;
- return null;
- }
-
- // At this point, idx() will have set packChecksum.
- if (Arrays.equals(packChecksum, idx.packChecksum))
- bitmapIdx = idx;
- else
- invalidBitmap = true;
- }
- return bitmapIdx;
- }
-
- private synchronized PackReverseIndex getReverseIdx() throws IOException {
- if (reverseIdx == null)
- reverseIdx = new PackReverseIndex(idx());
- return reverseIdx;
- }
-
- private boolean isCorrupt(long offset) {
- LongList list = corruptObjects;
- if (list == null)
- return false;
- synchronized (list) {
- return list.contains(offset);
- }
- }
-
- private void setCorrupt(long offset) {
- LongList list = corruptObjects;
- if (list == null) {
- synchronized (readLock) {
- list = corruptObjects;
- if (list == null) {
- list = new LongList();
- corruptObjects = list;
- }
- }
- }
- synchronized (list) {
- list.add(offset);
- }
- }
-
- private File extFile(PackExt ext) {
- String p = packFile.getName();
- int dot = p.lastIndexOf('.');
- String b = (dot < 0) ? p : p.substring(0, dot);
- return new File(packFile.getParentFile(), b + '.' + ext.getExtension());
- }
-
- private boolean hasExt(PackExt ext) {
- return (extensions & ext.getBit()) != 0;
- }
-
- @SuppressWarnings("nls")
- @Override
- public String toString() {
- return "PackFile [packFileName=" + packFile.getName() + ", length="
- + packFile.length() + ", packChecksum="
- + ObjectId.fromRaw(packChecksum).name() + "]";
- }
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
index 31686befc9..942cc96745 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -34,7 +34,7 @@ import org.eclipse.jgit.util.io.SilentFileInputStream;
/**
* Access path to locate objects by {@link org.eclipse.jgit.lib.ObjectId} in a
- * {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}.
*
* Indexes are strictly redundant information in that we can rebuild all of the
* data held in the index file from the on disk representation of the pack file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
index 612b12366c..87e0b44d46 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java
@@ -25,7 +25,7 @@ import org.eclipse.jgit.util.NB;
/**
* Creates a table of contents to support random access by
- * {@link org.eclipse.jgit.internal.storage.file.PackFile}.
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}.
*
* Pack index files (the .idx
suffix in a pack file pair) provides
* random access to any object in the pack by associating an ObjectId to the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
index a9e0588885..0bceca72ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInputStream.java
@@ -16,11 +16,11 @@ import java.io.InputStream;
class PackInputStream extends InputStream {
private final WindowCursor wc;
- private final PackFile pack;
+ private final Pack pack;
private long pos;
- PackInputStream(PackFile pack, long pos, WindowCursor wc)
+ PackInputStream(Pack pack, long pos, WindowCursor wc)
throws IOException {
this.pack = pack;
this.pos = pos;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
index 2c2f7911aa..482b143e33 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
@@ -18,7 +18,7 @@ import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
/**
- * Keeps track of a {@link org.eclipse.jgit.internal.storage.file.PackFile}'s
+ * Keeps track of a {@link org.eclipse.jgit.internal.storage.file.Pack}'s
* associated .keep
file.
*/
public class PackLock {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
index 4d80a0312a..ee458e27ba 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
@@ -25,7 +25,7 @@ import org.eclipse.jgit.lib.ObjectId;
*
*
* @see PackIndex
- * @see PackFile
+ * @see Pack
*/
public class PackReverseIndex {
/** Index we were created from, and that has our ObjectId data. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
index 3e8cb3a3f2..25653b3ce3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
@@ -33,7 +33,7 @@ import org.eclipse.jgit.storage.file.WindowCacheStats;
import org.eclipse.jgit.util.Monitoring;
/**
- * Caches slices of a {@link org.eclipse.jgit.internal.storage.file.PackFile} in
+ * Caches slices of a {@link org.eclipse.jgit.internal.storage.file.Pack} in
* memory for faster read access.
*
* The WindowCache serves as a Java based "buffer cache", loading segments of a
@@ -41,7 +41,7 @@ import org.eclipse.jgit.util.Monitoring;
* only tiny slices of a file, the WindowCache tries to smooth out these tiny
* reads into larger block-sized IO operations.
*
- * Whenever a cache miss occurs, {@link #load(PackFile, long)} is invoked by
+ * Whenever a cache miss occurs, {@link #load(Pack, long)} is invoked by
* exactly one thread for the given (PackFile,position)
key tuple.
* This is ensured by an array of locks, with the tuple hashed to a lock
* instance.
@@ -80,10 +80,10 @@ import org.eclipse.jgit.util.Monitoring;
*
* This cache has an implementation rule such that:
*
- * - {@link #load(PackFile, long)} is invoked by at most one thread at a time
+ *
- {@link #load(Pack, long)} is invoked by at most one thread at a time
* for a given
(PackFile,position)
tuple.
* - For every
load()
invocation there is exactly one
- * {@link #createRef(PackFile, long, ByteWindow)} invocation to wrap a
+ * {@link #createRef(Pack, long, ByteWindow)} invocation to wrap a
* SoftReference or a StrongReference around the cached entity.
* - For every Reference created by
createRef()
there will be
* exactly one call to {@link #clear(PageRef)} to cleanup any resources associated
@@ -91,10 +91,10 @@ import org.eclipse.jgit.util.Monitoring;
*
*
* Therefore, it is safe to perform resource accounting increments during the
- * {@link #load(PackFile, long)} or
- * {@link #createRef(PackFile, long, ByteWindow)} methods, and matching
+ * {@link #load(Pack, long)} or
+ * {@link #createRef(Pack, long, ByteWindow)} methods, and matching
* decrements during {@link #clear(PageRef)}. Implementors may need to override
- * {@link #createRef(PackFile, long, ByteWindow)} in order to embed additional
+ * {@link #createRef(Pack, long, ByteWindow)} in order to embed additional
* accounting information into an implementation specific
* {@link org.eclipse.jgit.internal.storage.file.WindowCache.PageRef} subclass, as
* the cached entity may have already been evicted by the JRE's garbage
@@ -170,7 +170,7 @@ public class WindowCache {
* @param delta
* delta of cached bytes
*/
- void recordOpenBytes(PackFile pack, int delta);
+ void recordOpenBytes(Pack pack, int delta);
/**
* Returns a snapshot of this recorder's stats. Note that this may be an
@@ -242,7 +242,7 @@ public class WindowCache {
}
@Override
- public void recordOpenBytes(PackFile pack, int delta) {
+ public void recordOpenBytes(Pack pack, int delta) {
openByteCount.add(delta);
String repositoryId = repositoryId(pack);
LongAdder la = openByteCountPerRepository
@@ -254,9 +254,8 @@ public class WindowCache {
}
}
- private static String repositoryId(PackFile pack) {
- // use repository's gitdir since packfile doesn't know its
- // repository
+ private static String repositoryId(Pack pack) {
+ // use repository's gitdir since Pack doesn't know its repository
return pack.getPackFile().getParentFile().getParentFile()
.getParent();
}
@@ -380,7 +379,7 @@ public class WindowCache {
return cache.publishMBeanIfNeeded();
}
- static final ByteWindow get(PackFile pack, long offset)
+ static final ByteWindow get(Pack pack, long offset)
throws IOException {
final WindowCache c = cache;
final ByteWindow r = c.getOrLoad(pack, c.toStart(offset));
@@ -395,7 +394,7 @@ public class WindowCache {
return r;
}
- static final void purge(PackFile pack) {
+ static final void purge(Pack pack) {
cache.removeAll(pack);
}
@@ -506,7 +505,7 @@ public class WindowCache {
return packHash + (int) (off >>> windowSizeShift);
}
- private ByteWindow load(PackFile pack, long offset) throws IOException {
+ private ByteWindow load(Pack pack, long offset) throws IOException {
long startTime = System.nanoTime();
if (pack.beginWindowCache())
statsRecorder.recordOpenFiles(1);
@@ -525,7 +524,7 @@ public class WindowCache {
}
}
- private PageRef createRef(PackFile p, long o, ByteWindow v) {
+ private PageRef createRef(Pack p, long o, ByteWindow v) {
final PageRef ref = useStrongRefs
? new StrongRef(p, o, v, queue)
: new SoftRef(p, o, v, (SoftCleanupQueue) queue);
@@ -539,7 +538,7 @@ public class WindowCache {
close(ref.getPack());
}
- private void close(PackFile pack) {
+ private void close(Pack pack) {
if (pack.endWindowCache()) {
statsRecorder.recordOpenFiles(-1);
}
@@ -578,9 +577,9 @@ public class WindowCache {
* @return the object reference.
* @throws IOException
* the object reference was not in the cache and could not be
- * obtained by {@link #load(PackFile, long)}.
+ * obtained by {@link #load(Pack, long)}.
*/
- private ByteWindow getOrLoad(PackFile pack, long position)
+ private ByteWindow getOrLoad(Pack pack, long position)
throws IOException {
final int slot = slot(pack, position);
final Entry e1 = table.get(slot);
@@ -623,7 +622,7 @@ public class WindowCache {
return v;
}
- private ByteWindow scan(Entry n, PackFile pack, long position) {
+ private ByteWindow scan(Entry n, Pack pack, long position) {
for (; n != null; n = n.next) {
final PageRef r = n.ref;
if (r.getPack() == pack && r.getPosition() == position) {
@@ -704,7 +703,7 @@ public class WindowCache {
/**
* Clear all entries related to a single file.
*
- * Typically this method is invoked during {@link PackFile#close()}, when we
+ * Typically this method is invoked during {@link Pack#close()}, when we
* know the pack is never going to be useful to us again (for example, it no
* longer exists on disk). A concurrent reader loading an entry from this
* same pack may cause the pack to become stuck in the cache anyway.
@@ -712,7 +711,7 @@ public class WindowCache {
* @param pack
* the file to purge all entries of.
*/
- private void removeAll(PackFile pack) {
+ private void removeAll(Pack pack) {
for (int s = 0; s < tableSize; s++) {
final Entry e1 = table.get(s);
boolean hasDead = false;
@@ -733,11 +732,11 @@ public class WindowCache {
queue.gc();
}
- private int slot(PackFile pack, long position) {
+ private int slot(Pack pack, long position) {
return (hash(pack.hash, position) >>> 1) % tableSize;
}
- private Lock lock(PackFile pack, long position) {
+ private Lock lock(Pack pack, long position) {
return locks[(hash(pack.hash, position) >>> 1) % locks.length];
}
@@ -799,16 +798,20 @@ public class WindowCache {
boolean kill();
/**
- * Get the packfile the referenced cache page is allocated for
+ * Get the {@link org.eclipse.jgit.internal.storage.file.Pack} the
+ * referenced cache page is allocated for
*
- * @return the packfile the referenced cache page is allocated for
+ * @return the {@link org.eclipse.jgit.internal.storage.file.Pack} the
+ * referenced cache page is allocated for
*/
- PackFile getPack();
+ Pack getPack();
/**
- * Get the position of the referenced cache page in the packfile
+ * Get the position of the referenced cache page in the
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}
*
- * @return the position of the referenced cache page in the packfile
+ * @return the position of the referenced cache page in the
+ * {@link org.eclipse.jgit.internal.storage.file.Pack}
*/
long getPosition();
@@ -844,7 +847,7 @@ public class WindowCache {
/** A soft reference wrapped around a cached object. */
private static class SoftRef extends SoftReference
implements PageRef {
- private final PackFile pack;
+ private final Pack pack;
private final long position;
@@ -852,7 +855,7 @@ public class WindowCache {
private long lastAccess;
- protected SoftRef(final PackFile pack, final long position,
+ protected SoftRef(final Pack pack, final long position,
final ByteWindow v, final SoftCleanupQueue queue) {
super(v, queue);
this.pack = pack;
@@ -861,7 +864,7 @@ public class WindowCache {
}
@Override
- public PackFile getPack() {
+ public Pack getPack() {
return pack;
}
@@ -900,7 +903,7 @@ public class WindowCache {
private static class StrongRef implements PageRef {
private ByteWindow referent;
- private final PackFile pack;
+ private final Pack pack;
private final long position;
@@ -910,7 +913,7 @@ public class WindowCache {
private CleanupQueue queue;
- protected StrongRef(final PackFile pack, final long position,
+ protected StrongRef(final Pack pack, final long position,
final ByteWindow v, final CleanupQueue queue) {
this.pack = pack;
this.position = position;
@@ -920,7 +923,7 @@ public class WindowCache {
}
@Override
- public PackFile getPack() {
+ public Pack getPack() {
return pack;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
index 6c975708a3..e7fd7b9e76 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -86,7 +86,7 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
/** {@inheritDoc} */
@Override
public BitmapIndex getBitmapIndex() throws IOException {
- for (PackFile pack : db.getPacks()) {
+ for (Pack pack : db.getPacks()) {
PackBitmapIndex index = pack.getBitmapIndex();
if (index != null)
return new BitmapIndexImpl(index);
@@ -98,7 +98,7 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
@Override
public Collection getCachedPacksAndUpdate(
BitmapBuilder needBitmap) throws IOException {
- for (PackFile pack : db.getPacks()) {
+ for (Pack pack : db.getPacks()) {
PackBitmapIndex index = pack.getBitmapIndex();
if (needBitmap.removeAllOrNone(index))
return Collections. singletonList(
@@ -218,7 +218,7 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
* this cursor does not match the provider or id and the proper
* window could not be acquired through the provider's cache.
*/
- int copy(final PackFile pack, long position, final byte[] dstbuf,
+ int copy(final Pack pack, long position, final byte[] dstbuf,
int dstoff, final int cnt) throws IOException {
final long length = pack.length;
int need = cnt;
@@ -239,7 +239,7 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
((LocalCachedPack) pack).copyAsIs(out, this);
}
- void copyPackAsIs(final PackFile pack, final long length,
+ void copyPackAsIs(final Pack pack, final long length,
final PackOutputStream out) throws IOException {
long position = 12;
long remaining = length - (12 + 20);
@@ -275,7 +275,7 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
* the inflater encountered an invalid chunk of data. Data
* stream corruption is likely.
*/
- int inflate(final PackFile pack, long position, final byte[] dstbuf,
+ int inflate(final Pack pack, long position, final byte[] dstbuf,
boolean headerOnly) throws IOException, DataFormatException {
prepareInflater();
pin(pack, position);
@@ -293,7 +293,7 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
}
}
- ByteArrayWindow quickCopy(PackFile p, long pos, long cnt)
+ ByteArrayWindow quickCopy(Pack p, long pos, long cnt)
throws IOException {
pin(p, pos);
if (window instanceof ByteArrayWindow
@@ -314,7 +314,7 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
inf.reset();
}
- void pin(PackFile pack, long position)
+ void pin(Pack pack, long position)
throws IOException {
final ByteWindow w = window;
if (w == null || !w.contains(pack, position)) {
--
cgit v1.2.3