Rewrite WindowCache to be easier to follow and maintain
commit2d77d30b5f5eca2b3087f1bab47fa9df2e64cd71
authorShawn O. Pearce <spearce@spearce.org>
Wed, 29 Apr 2009 18:54:46 +0000 (29 11:54 -0700)
committerRobin Rosenberg <robin.rosenberg@dewire.com>
Wed, 29 Apr 2009 23:49:07 +0000 (30 01:49 +0200)
tree72fd9f49f52eb41df9b2ce8c26456a43e467ca64
parent65cf2f453ff227765df6cf3758cb1d3126222cd6
Rewrite WindowCache to be easier to follow and maintain

The integration of WindowCache, ByteWindow, PackFile and WindowCursor
was a spaghetti of code that was impossible for even the original
author (me) to follow.  Due to the way the responsibility for the
PackFile's open RandomAccessFile "fd" was distributed between these
four classes I could no longer prove to myself that the fd wouldn't
be closed while it was being accessed by another thread.

This rewrite generalizes most of the cache logic into a new class,
OffsetCache.  The hope is that we can later reuse this code to make
a rewrite of UnpackedObjectCache, which uses similiar caching rules
as WindowCache, but applies a different hash function.  That rewrite
is deferred to another change, but is anticipated by this one.

The new OffsetCache class uses the Java 5 atomic APIs to create a
much more concurrent hash table than we had before.  We can now
perform no-miss reads without taking any locks.  Reads that do
miss acquire a lock in order to prevent concurrent threads from
performing duplicate work loading the same window from disk,
however concurrent reads of different windows is still permitted.

Due to the more concurrent nature of the OffsetCache, it is now
possible for the cache to temporarily overshoot its resource limits.
This is a small temporary overshoot that is roughly bounded by the
number of concurrent threads operating against the same cache.

The API of the ByteWindow subclasses is now simplified by removing
the base class of SoftReference.  It was a horrible idea to pass
the byte[] or MappedByteBuffer down through the call stack when the
implementation knew what type it should be operating on.  We now
instead use a more traditional OO pattern of allowing the subclass
to directly specify its referent.

Responsibility for the RandomAccessFile "fd" within PackFile is now
strictly within PackFile.  Two open reference counts track how the
callers are using the fd, ensuring that the fd remains open, so long
as the caller has made the appropriate begin*() invocation prior
to data access.  One counter, beginWindowCache() is exclusively
for the ByteWindows created by WindowCache.  Another counter,
beginCopyRawData(), is exclusively for PackWriter's need to lock
the PackFile open while it performs object reuse.

To keep the code simple a WindowCache.reconfigure() now discards the
entire current cache, and creates a new one.  That invalidates every
open file, and every open ByteWindow, and forces them to load again.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
org.spearce.jgit.test/tst/org/spearce/jgit/lib/ConcurrentRepackTest.java
org.spearce.jgit/src/org/spearce/jgit/lib/ByteArrayWindow.java
org.spearce.jgit/src/org/spearce/jgit/lib/ByteBufferWindow.java
org.spearce.jgit/src/org/spearce/jgit/lib/ByteWindow.java
org.spearce.jgit/src/org/spearce/jgit/lib/OffsetCache.java [new file with mode: 0644]
org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java
org.spearce.jgit/src/org/spearce/jgit/lib/PackedObjectLoader.java
org.spearce.jgit/src/org/spearce/jgit/lib/WindowCache.java
org.spearce.jgit/src/org/spearce/jgit/lib/WindowCursor.java