Merge branch 'master' into stable-5.13

* master:
  Revert "DFS block cache: Refactor to enable parallel index loading"

Change-Id: Ifd7cf7a366bf682da6e92ac9dd416bd88e9f1654
This commit is contained in:
Matthias Sohn 2021-09-04 11:45:33 +02:00
commit e296af1697
3 changed files with 40 additions and 144 deletions

View File

@ -59,8 +59,12 @@ public final class DfsPackFile extends BlockBasedFile {
private static final int REC_SIZE = Constants.OBJECT_ID_LENGTH + 8; private static final int REC_SIZE = Constants.OBJECT_ID_LENGTH + 8;
private static final long REF_POSITION = 0; private static final long REF_POSITION = 0;
/** Lock for initialization of {@link #index} and {@link #reverseIndex}. */ /**
private final Object indexLock = new Object(); * Lock for initialization of {@link #index} and {@link #corruptObjects}.
* <p>
* This lock ensures only one thread can perform the initialization work.
*/
private final Object initLock = new Object();
/** Index mapping {@link ObjectId} to position within the pack stream. */ /** Index mapping {@link ObjectId} to position within the pack stream. */
private volatile PackIndex index; private volatile PackIndex index;
@ -68,15 +72,9 @@ public final class DfsPackFile extends BlockBasedFile {
/** Reverse version of {@link #index} mapping position to {@link ObjectId}. */ /** Reverse version of {@link #index} mapping position to {@link ObjectId}. */
private volatile PackReverseIndex reverseIndex; private volatile PackReverseIndex reverseIndex;
/** Lock for initialization of {@link #bitmapIndex}. */
private final Object bitmapIndexLock = new Object();
/** Index of compressed bitmap mapping entire object graph. */ /** Index of compressed bitmap mapping entire object graph. */
private volatile PackBitmapIndex bitmapIndex; private volatile PackBitmapIndex bitmapIndex;
/** Lock for {@link #corruptObjects}. */
private final Object corruptObjectsLock = new Object();
/** /**
* Objects we have tried to read, and discovered to be corrupt. * Objects we have tried to read, and discovered to be corrupt.
* <p> * <p>
@ -158,7 +156,7 @@ private PackIndex idx(DfsReader ctx) throws IOException {
Repository.getGlobalListenerList() Repository.getGlobalListenerList()
.dispatch(new BeforeDfsPackIndexLoadedEvent(this)); .dispatch(new BeforeDfsPackIndexLoadedEvent(this));
synchronized (indexLock) { synchronized (initLock) {
if (index != null) { if (index != null) {
return index; return index;
} }
@ -193,17 +191,7 @@ final boolean isGarbage() {
return desc.getPackSource() == UNREACHABLE_GARBAGE; return desc.getPackSource() == UNREACHABLE_GARBAGE;
} }
/** PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
* Get the BitmapIndex for this PackFile.
*
* @param ctx
* reader context to support reading from the backing store if
* the index is not already loaded in memory.
* @return the BitmapIndex.
* @throws java.io.IOException
* the bitmap index is not available, or is corrupt.
*/
public PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
if (invalid || isGarbage() || !desc.hasFileExt(BITMAP_INDEX)) { if (invalid || isGarbage() || !desc.hasFileExt(BITMAP_INDEX)) {
return null; return null;
} }
@ -212,11 +200,13 @@ public PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
return bitmapIndex; return bitmapIndex;
} }
synchronized (bitmapIndexLock) { synchronized (initLock) {
if (bitmapIndex != null) { if (bitmapIndex != null) {
return bitmapIndex; return bitmapIndex;
} }
PackIndex idx = idx(ctx);
PackReverseIndex revidx = getReverseIdx(ctx);
DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX); DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX);
AtomicBoolean cacheHit = new AtomicBoolean(true); AtomicBoolean cacheHit = new AtomicBoolean(true);
DfsBlockCache.Ref<PackBitmapIndex> idxref = cache.getOrLoadRef( DfsBlockCache.Ref<PackBitmapIndex> idxref = cache.getOrLoadRef(
@ -224,7 +214,7 @@ public PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
REF_POSITION, REF_POSITION,
() -> { () -> {
cacheHit.set(false); cacheHit.set(false);
return loadBitmapIndex(ctx, bitmapKey); return loadBitmapIndex(ctx, bitmapKey, idx, revidx);
}); });
if (cacheHit.get()) { if (cacheHit.get()) {
ctx.stats.bitmapCacheHit++; ctx.stats.bitmapCacheHit++;
@ -242,7 +232,7 @@ PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
return reverseIndex; return reverseIndex;
} }
synchronized (indexLock) { synchronized (initLock) {
if (reverseIndex != null) { if (reverseIndex != null) {
return reverseIndex; return reverseIndex;
} }
@ -1013,7 +1003,7 @@ boolean isCorrupt(long offset) {
private void setCorrupt(long offset) { private void setCorrupt(long offset) {
LongList list = corruptObjects; LongList list = corruptObjects;
if (list == null) { if (list == null) {
synchronized (corruptObjectsLock) { synchronized (initLock) {
list = corruptObjects; list = corruptObjects;
if (list == null) { if (list == null) {
list = new LongList(); list = new LongList();
@ -1076,8 +1066,11 @@ private DfsBlockCache.Ref<PackReverseIndex> loadReverseIdx(
revidx); revidx);
} }
private DfsBlockCache.Ref<PackBitmapIndex> loadBitmapIndex(DfsReader ctx, private DfsBlockCache.Ref<PackBitmapIndex> loadBitmapIndex(
DfsStreamKey bitmapKey) throws IOException { DfsReader ctx,
DfsStreamKey bitmapKey,
PackIndex idx,
PackReverseIndex revidx) throws IOException {
ctx.stats.readBitmap++; ctx.stats.readBitmap++;
long start = System.nanoTime(); long start = System.nanoTime();
try (ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX)) { try (ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX)) {
@ -1093,8 +1086,7 @@ private DfsBlockCache.Ref<PackBitmapIndex> loadBitmapIndex(DfsReader ctx,
bs = wantSize; bs = wantSize;
} }
in = new BufferedInputStream(in, bs); in = new BufferedInputStream(in, bs);
bmidx = PackBitmapIndex.read(in, () -> idx(ctx), bmidx = PackBitmapIndex.read(in, idx, revidx);
() -> getReverseIdx(ctx));
} finally { } finally {
size = rc.position(); size = rc.position();
ctx.stats.readBitmapIdxBytes += size; ctx.stats.readBitmapIdxBytes += size;

View File

@ -97,37 +97,7 @@ public static PackBitmapIndex open(
public static PackBitmapIndex read( public static PackBitmapIndex read(
InputStream fd, PackIndex packIndex, PackReverseIndex reverseIndex) InputStream fd, PackIndex packIndex, PackReverseIndex reverseIndex)
throws IOException { throws IOException {
return new PackBitmapIndexV1(fd, () -> packIndex, () -> reverseIndex); return new PackBitmapIndexV1(fd, packIndex, reverseIndex);
}
/**
* Read an existing pack bitmap index file from a buffered stream.
* <p>
* The format of the file will be automatically detected and a proper access
* implementation for that format will be constructed and returned to the
* caller. The file may or may not be held open by the returned instance.
*
* @param fd
* stream to read the bitmap index file from. The stream must be
* buffered as some small IOs are performed against the stream.
* The caller is responsible for closing the stream.
* @param packIndexSupplier
* the supplier for pack index for the corresponding pack file.
* @param reverseIndexSupplier
* the supplier for pack reverse index for the corresponding pack
* file.
* @return a copy of the index in-memory.
* @throws java.io.IOException
* the stream cannot be read.
* @throws CorruptObjectException
* the stream does not contain a valid pack bitmap index.
*/
public static PackBitmapIndex read(InputStream fd,
SupplierWithIOException<PackIndex> packIndexSupplier,
SupplierWithIOException<PackReverseIndex> reverseIndexSupplier)
throws IOException {
return new PackBitmapIndexV1(fd, packIndexSupplier,
reverseIndexSupplier);
} }
/** Footer checksum applied on the bottom of the pack file. */ /** Footer checksum applied on the bottom of the pack file. */
@ -191,19 +161,4 @@ public abstract EWAHCompressedBitmap ofObjectType(
* @return the number of bitmaps in this bitmap index. * @return the number of bitmaps in this bitmap index.
*/ */
public abstract int getBitmapCount(); public abstract int getBitmapCount();
/**
* Supplier that propagates IOException.
*
* @param <T>
* the return type which is expected from {@link #get()}
*/
@FunctionalInterface
public interface SupplierWithIOException<T> {
/**
* @return result
* @throws IOException
*/
T get() throws IOException;
}
} }

View File

@ -14,11 +14,8 @@
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@ -49,13 +46,11 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
private final ObjectIdOwnerMap<StoredBitmap> bitmaps; private final ObjectIdOwnerMap<StoredBitmap> bitmaps;
PackBitmapIndexV1(final InputStream fd, PackBitmapIndexV1(final InputStream fd, PackIndex packIndex,
SupplierWithIOException<PackIndex> packIndexSupplier, PackReverseIndex reverseIndex) throws IOException {
SupplierWithIOException<PackReverseIndex> reverseIndexSupplier)
throws IOException {
// An entry is object id, xor offset, flag byte, and a length encoded
// bitmap. The object id is an int32 of the nth position sorted by name.
super(new ObjectIdOwnerMap<StoredBitmap>()); super(new ObjectIdOwnerMap<StoredBitmap>());
this.packIndex = packIndex;
this.reverseIndex = reverseIndex;
this.bitmaps = getBitmaps(); this.bitmaps = getBitmaps();
final byte[] scratch = new byte[32]; final byte[] scratch = new byte[32];
@ -102,10 +97,10 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
this.blobs = readBitmap(dataInput); this.blobs = readBitmap(dataInput);
this.tags = readBitmap(dataInput); this.tags = readBitmap(dataInput);
// Read full bitmap from storage first. // An entry is object id, xor offset, flag byte, and a length encoded
List<IdxPositionBitmap> idxPositionBitmapList = new ArrayList<>(); // bitmap. The object id is an int32 of the nth position sorted by name.
// The xor offset is a single byte offset back in the list of entries. // The xor offset is a single byte offset back in the list of entries.
IdxPositionBitmap[] recentBitmaps = new IdxPositionBitmap[MAX_XOR_OFFSET]; StoredBitmap[] recentBitmaps = new StoredBitmap[MAX_XOR_OFFSET];
for (int i = 0; i < (int) numEntries; i++) { for (int i = 0; i < (int) numEntries; i++) {
IO.readFully(fd, scratch, 0, 6); IO.readFully(fd, scratch, 0, 6);
int nthObjectId = NB.decodeInt32(scratch, 0); int nthObjectId = NB.decodeInt32(scratch, 0);
@ -113,58 +108,38 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
int flags = scratch[5]; int flags = scratch[5];
EWAHCompressedBitmap bitmap = readBitmap(dataInput); EWAHCompressedBitmap bitmap = readBitmap(dataInput);
if (nthObjectId < 0) { if (nthObjectId < 0)
throw new IOException(MessageFormat.format( throw new IOException(MessageFormat.format(
JGitText.get().invalidId, String.valueOf(nthObjectId))); JGitText.get().invalidId, String.valueOf(nthObjectId)));
} if (xorOffset < 0)
if (xorOffset < 0) {
throw new IOException(MessageFormat.format( throw new IOException(MessageFormat.format(
JGitText.get().invalidId, String.valueOf(xorOffset))); JGitText.get().invalidId, String.valueOf(xorOffset)));
} if (xorOffset > MAX_XOR_OFFSET)
if (xorOffset > MAX_XOR_OFFSET) {
throw new IOException(MessageFormat.format( throw new IOException(MessageFormat.format(
JGitText.get().expectedLessThanGot, JGitText.get().expectedLessThanGot,
String.valueOf(MAX_XOR_OFFSET), String.valueOf(MAX_XOR_OFFSET),
String.valueOf(xorOffset))); String.valueOf(xorOffset)));
} if (xorOffset > i)
if (xorOffset > i) {
throw new IOException(MessageFormat.format( throw new IOException(MessageFormat.format(
JGitText.get().expectedLessThanGot, String.valueOf(i), JGitText.get().expectedLessThanGot, String.valueOf(i),
String.valueOf(xorOffset))); String.valueOf(xorOffset)));
}
IdxPositionBitmap xorIdxPositionBitmap = null; ObjectId objectId = packIndex.getObjectId(nthObjectId);
StoredBitmap xorBitmap = null;
if (xorOffset > 0) { if (xorOffset > 0) {
int index = (i - xorOffset); int index = (i - xorOffset);
xorIdxPositionBitmap = recentBitmaps[index xorBitmap = recentBitmaps[index % recentBitmaps.length];
% recentBitmaps.length]; if (xorBitmap == null)
if (xorIdxPositionBitmap == null) {
throw new IOException(MessageFormat.format( throw new IOException(MessageFormat.format(
JGitText.get().invalidId, JGitText.get().invalidId,
String.valueOf(xorOffset))); String.valueOf(xorOffset)));
}
} }
IdxPositionBitmap idxPositionBitmap = new IdxPositionBitmap(
nthObjectId, xorIdxPositionBitmap, bitmap, flags);
idxPositionBitmapList.add(idxPositionBitmap);
recentBitmaps[i % recentBitmaps.length] = idxPositionBitmap;
}
this.packIndex = packIndexSupplier.get(); StoredBitmap sb = new StoredBitmap(
for (int i = 0; i < idxPositionBitmapList.size(); ++i) { objectId, bitmap, xorBitmap, flags);
IdxPositionBitmap idxPositionBitmap = idxPositionBitmapList.get(i);
ObjectId objectId = packIndex
.getObjectId(idxPositionBitmap.nthObjectId);
StoredBitmap sb = new StoredBitmap(objectId,
idxPositionBitmap.bitmap,
idxPositionBitmap.getXorStoredBitmap(),
idxPositionBitmap.flags);
// Save the StoredBitmap for a possible future XorStoredBitmap
// reference.
idxPositionBitmap.sb = sb;
bitmaps.add(sb); bitmaps.add(sb);
recentBitmaps[i % recentBitmaps.length] = sb;
} }
this.reverseIndex = reverseIndexSupplier.get();
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -239,30 +214,4 @@ private static EWAHCompressedBitmap readBitmap(DataInput dataInput)
bitmap.deserialize(dataInput); bitmap.deserialize(dataInput);
return bitmap; return bitmap;
} }
/**
* Temporary holder of object position in pack index and other metadata for
* {@code StoredBitmap}.
*/
private static final class IdxPositionBitmap {
int nthObjectId;
IdxPositionBitmap xorIdxPositionBitmap;
EWAHCompressedBitmap bitmap;
int flags;
StoredBitmap sb;
IdxPositionBitmap(int nthObjectId, @Nullable
IdxPositionBitmap xorIdxPositionBitmap, EWAHCompressedBitmap bitmap,
int flags) {
this.nthObjectId = nthObjectId;
this.xorIdxPositionBitmap = xorIdxPositionBitmap;
this.bitmap = bitmap;
this.flags = flags;
}
StoredBitmap getXorStoredBitmap() {
return xorIdxPositionBitmap == null ? null
: xorIdxPositionBitmap.sb;
}
}
} }