From c70dd55616c00932c6086062655178014d58961f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 22 Dec 2008 16:27:13 -0800 Subject: [PATCH] Cache an Inflater inside a WindowCursor and reuse it as much as possible By caching the Inflater within the WindowCursor we can improve performance associated with reading objects from the pack files. Each read can use the cached Inflater, especially when chasing down a delta chain. This avoids locking on the global cache. Signed-off-by: Shawn O. Pearce Signed-off-by: Robin Rosenberg --- .../jgit/lib/DeltaRefPackedObjectLoader.java | 2 +- .../src/org/spearce/jgit/lib/PackFile.java | 7 ++++- .../src/org/spearce/jgit/lib/Repository.java | 7 ++++- .../src/org/spearce/jgit/lib/WindowCursor.java | 33 +++++++++++++++------- .../src/org/spearce/jgit/lib/WindowedFile.java | 10 ++----- .../src/org/spearce/jgit/revwalk/RevWalk.java | 4 +-- .../src/org/spearce/jgit/transport/IndexPack.java | 9 ++++-- 7 files changed, 47 insertions(+), 25 deletions(-) diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/DeltaRefPackedObjectLoader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/DeltaRefPackedObjectLoader.java index 042d3a8d..b126bbd2 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/DeltaRefPackedObjectLoader.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/DeltaRefPackedObjectLoader.java @@ -54,7 +54,7 @@ class DeltaRefPackedObjectLoader extends DeltaPackedObjectLoader { } protected PackedObjectLoader getBaseLoader() throws IOException { - final PackedObjectLoader or = pack.get(deltaBase); + final PackedObjectLoader or = pack.get(curs, deltaBase); if (or == null) throw new MissingObjectException(deltaBase, "delta base"); return or; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java index 8ebd440e..6cd85b1c 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java @@ -120,7 +120,12 @@ public class PackFile implements Iterable { * the pack file or the index could not be read. */ public PackedObjectLoader get(final AnyObjectId id) throws IOException { - return get(new WindowCursor(), id); + final WindowCursor wc = new WindowCursor(); + try { + return get(wc, id); + } finally { + wc.release(); + } } /** diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java index a319c00a..ff36a3d1 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java @@ -251,7 +251,12 @@ public class Repository { */ public ObjectLoader openObject(final AnyObjectId id) throws IOException { - return openObject(new WindowCursor(),id); + final WindowCursor wc = new WindowCursor(); + try { + return openObject(wc, id); + } finally { + wc.release(); + } } /** diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/WindowCursor.java b/org.spearce.jgit/src/org/spearce/jgit/lib/WindowCursor.java index 0f4dab99..9eba2817 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/WindowCursor.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/WindowCursor.java @@ -46,6 +46,8 @@ public final class WindowCursor { /** Temporary buffer large enough for at least one raw object id. */ final byte[] tempId = new byte[Constants.OBJECT_ID_LENGTH]; + private Inflater inf; + ByteWindow window; Object handle; @@ -98,16 +100,8 @@ public final class WindowCursor { * data to. * @param dstoff * current offset within dstbuf to inflate into. - * @param inf - * the inflater to feed input to. The caller is responsible for - * initializing the inflater as multiple windows may need to - * supply data to the same inflater to completely decompress - * something. * @return updated dstoff based on the number of bytes - * successfully copied into dstbuf by - * inf. If the inflater is not yet finished then - * another window's data must still be supplied as input to finish - * decompression. + * successfully inflated into dstbuf. * @throws IOException * this cursor does not match the provider or id and the proper * window could not be acquired through the provider's cache. @@ -116,8 +110,12 @@ public final class WindowCursor { * stream corruption is likely. */ int inflate(final WindowedFile provider, long position, - final byte[] dstbuf, int dstoff, final Inflater inf) + final byte[] dstbuf, int dstoff) throws IOException, DataFormatException { + if (inf == null) + inf = InflaterCache.get(); + else + inf.reset(); for (;;) { pin(provider, position); dstoff = window.inflate(handle, position, dstbuf, dstoff, inf); @@ -138,5 +136,20 @@ public final class WindowCursor { public void release() { window = null; handle = null; + try { + InflaterCache.release(inf); + } finally { + inf = null; + } + } + + /** + * @param curs cursor to release; may be null. + * @return always null. + */ + public static WindowCursor release(final WindowCursor curs) { + if (curs != null) + curs.release(); + return null; } } diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java b/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java index f28524f1..454f98b8 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java @@ -45,7 +45,6 @@ import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel.MapMode; import java.util.zip.DataFormatException; -import java.util.zip.Inflater; /** * Read-only cached file access. @@ -240,13 +239,8 @@ public class WindowedFile { void readCompressed(final long position, final byte[] dstbuf, final WindowCursor curs) throws IOException, DataFormatException { - final Inflater inf = InflaterCache.get(); - try { - if (curs.inflate(this, position, dstbuf, 0, inf) != dstbuf.length) - throw new EOFException("Short compressed stream at " + position); - } finally { - InflaterCache.release(inf); - } + if (curs.inflate(this, position, dstbuf, 0) != dstbuf.length) + throw new EOFException("Short compressed stream at " + position); } /** diff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java index d7e4c587..b1571ab9 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java +++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java @@ -651,7 +651,7 @@ public class RevWalk implements Iterable { if ((t.flags & PARSED) != 0) return t; - final ObjectLoader ldr = db.openObject(t); + final ObjectLoader ldr = db.openObject(curs, t); if (ldr == null) throw new MissingObjectException(t, Constants.TYPE_TREE); if (ldr.getType() != Constants.OBJ_TREE) @@ -680,7 +680,7 @@ public class RevWalk implements Iterable { throws MissingObjectException, IOException { RevObject r = objects.get(id); if (r == null) { - final ObjectLoader ldr = db.openObject(id); + final ObjectLoader ldr = db.openObject(curs, id); if (ldr == null) throw new MissingObjectException(id.toObjectId(), "unknown"); final byte[] data = ldr.getCachedBytes(); diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java index 3e2187c6..82cd6155 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java +++ b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java @@ -68,6 +68,7 @@ import org.spearce.jgit.lib.ObjectLoader; import org.spearce.jgit.lib.PackIndexWriter; import org.spearce.jgit.lib.ProgressMonitor; import org.spearce.jgit.lib.Repository; +import org.spearce.jgit.lib.WindowCursor; import org.spearce.jgit.util.NB; /** Indexes Git pack files for local use. */ @@ -173,6 +174,8 @@ public class IndexPack { /** If {@link #fixThin} this is the last byte of the original checksum. */ private long originalEOF; + private WindowCursor readCurs; + /** * Create a new pack indexer utility. * @@ -189,6 +192,7 @@ public class IndexPack { repo = db; in = src; inflater = InflaterCache.get(); + readCurs = new WindowCursor(); buf = new byte[BUFFER_SIZE]; objectData = new byte[BUFFER_SIZE]; objectDigest = Constants.newMessageDigest(); @@ -325,6 +329,7 @@ public class IndexPack { } finally { inflater = null; } + readCurs = WindowCursor.release(readCurs); progress.endTask(); if (packOut != null) @@ -461,7 +466,7 @@ public class IndexPack { final Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION, false); long end = originalEOF; for (final ObjectId baseId : new ArrayList(baseById.keySet())) { - final ObjectLoader ldr = repo.openObject(baseId); + final ObjectLoader ldr = repo.openObject(readCurs, baseId); if (ldr == null) continue; final byte[] data = ldr.getBytes(); @@ -715,7 +720,7 @@ public class IndexPack { } } - final ObjectLoader ldr = repo.openObject(id); + final ObjectLoader ldr = repo.openObject(readCurs, id); if (ldr != null) { final byte[] existingData = ldr.getCachedBytes(); if (ldr.getType() != type || !Arrays.equals(data, existingData)) { -- 2.11.4.GIT