Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Sohn2023-03-27 20:23:11 +0000
committerMatthias Sohn2023-03-28 21:16:08 +0000
commit23b9693a75b899c97da8a04c0b531874b225d236 (patch)
treea710a29fe5dd8792cb530910376b7ced2e45f770
parent3212c8fa387995cecbb95de50508ba142f772203 (diff)
downloadjgit-23b9693a75b899c97da8a04c0b531874b225d236.tar.gz
jgit-23b9693a75b899c97da8a04c0b531874b225d236.tar.xz
jgit-23b9693a75b899c97da8a04c0b531874b225d236.zip
DirCache: support option index.skipHash
Support the new option index.skipHash which was introduced in git 2.40 [1]. If it is set to true skip computing the git index checksum. This accelerates Git commands that manipulate the index, such as git add, git commit, or git status. Instead of storing the checksum, write a trailing set of bytes with value zero, indicating that the computation was skipped. Accept a skipped checksum consisting of 20 null bytes when reading the index since the option could have been set to true at the time when the index was written. [1] https://git-scm.com/docs/git-config#Documentation/git-config.txt-indexskipHash Bug: 581723 Change-Id: I28ebe44c5ca1cbcb882438665d686452a0c111b2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java29
-rw-r--r--org.eclipse.jgit/.settings/.api_filters6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java50
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/NullMessageDigest.java58
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java6
5 files changed, 137 insertions, 12 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
index 0fca652906..618ccc0a0c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
@@ -17,19 +17,48 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
+import java.io.IOException;
import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Collection;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.SystemReader;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class DirCacheBasicTest extends RepositoryTestCase {
+ @Parameter(0)
+ public boolean skipHash;
+
+ @Parameters(name = "skipHash: {0}")
+ public static Collection<Boolean[]> getSkipHashValues() {
+ return Arrays
+ .asList(new Boolean[][] { { Boolean.TRUE },
+ { Boolean.FALSE } });
+ }
+
+ @Before
+ public void setup() throws IOException {
+ FileBasedConfig cfg = db.getConfig();
+ cfg.setBoolean(ConfigConstants.CONFIG_INDEX_SECTION, null,
+ ConfigConstants.CONFIG_KEY_SKIPHASH, skipHash);
+ cfg.save();
+ }
+
@Test
public void testReadMissing_RealIndex() throws Exception {
final File idx = new File(db.getDirectory(), "index");
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 01366d259a..e12ec17f34 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -22,6 +22,12 @@
<filter id="1142947843">
<message_arguments>
<message_argument value="5.13.2"/>
+ <message_argument value="CONFIG_KEY_SKIPHASH"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
<message_argument value="SHA1_IMPLEMENTATION"/>
</message_arguments>
</filter>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index 03da61583d..e56061223c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -40,6 +40,7 @@ import org.eclipse.jgit.events.IndexChangedListener;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
import org.eclipse.jgit.internal.storage.file.LockFile;
+import org.eclipse.jgit.internal.storage.io.NullMessageDigest;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Config.ConfigEnum;
@@ -327,6 +328,9 @@ public class DirCache {
/** If we read this index from disk, the original format. */
private DirCacheVersion version;
+ /** Whether to skip computing and checking the index checksum */
+ private boolean skipHash;
+
/**
* Create a new in-core index representation.
* <p>
@@ -446,7 +450,8 @@ public class DirCache {
private void readFrom(InputStream inStream) throws IOException,
CorruptObjectException {
final BufferedInputStream in = new BufferedInputStream(inStream);
- final MessageDigest md = Constants.newMessageDigest();
+ readConfig();
+ MessageDigest md = newMessageDigest();
// Read the index header and verify we understand it.
//
@@ -543,8 +548,12 @@ public class DirCache {
}
readIndexChecksum = md.digest();
- if (!Arrays.equals(readIndexChecksum, hdr)) {
- throw new CorruptObjectException(JGitText.get().DIRCChecksumMismatch);
+ if (!(skipHash
+ || Arrays.equals(readIndexChecksum, hdr)
+ || Arrays.equals(NullMessageDigest.getInstance().digest(),
+ hdr))) {
+ throw new CorruptObjectException(
+ JGitText.get().DIRCChecksumMismatch);
}
}
@@ -627,15 +636,9 @@ public class DirCache {
}
void writeTo(File dir, OutputStream os) throws IOException {
- final MessageDigest foot = Constants.newMessageDigest();
- final DigestOutputStream dos = new DigestOutputStream(os, foot);
-
- if (version == null && this.repository != null) {
- // A new DirCache is being written.
- DirCacheConfig config = repository.getConfig()
- .get(DirCacheConfig::new);
- version = config.getIndexVersion();
- }
+ readConfig();
+ MessageDigest foot = newMessageDigest();
+ DigestOutputStream dos = new DigestOutputStream(os, foot);
if (version == null
|| version == DirCacheVersion.DIRC_VERSION_MINIMUM) {
version = DirCacheVersion.DIRC_VERSION_MINIMUM;
@@ -707,6 +710,22 @@ public class DirCache {
os.close();
}
+ private void readConfig() {
+ if (version == null && this.repository != null) {
+ DirCacheConfig config = repository.getConfig()
+ .get(DirCacheConfig::new);
+ version = config.getIndexVersion();
+ skipHash = config.isSkipHash();
+ }
+ }
+
+ private MessageDigest newMessageDigest() {
+ if (skipHash) {
+ return NullMessageDigest.getInstance();
+ }
+ return Constants.newMessageDigest();
+ }
+
/**
* Commit this change and release the lock.
* <p>
@@ -1071,6 +1090,8 @@ public class DirCache {
private final DirCacheVersion indexVersion;
+ private final boolean skipHash;
+
public DirCacheConfig(Config cfg) {
boolean manyFiles = cfg.getBoolean(
ConfigConstants.CONFIG_FEATURE_SECTION,
@@ -1080,11 +1101,16 @@ public class DirCache {
ConfigConstants.CONFIG_KEY_VERSION,
manyFiles ? DirCacheVersion.DIRC_VERSION_PATHCOMPRESS
: DirCacheVersion.DIRC_VERSION_EXTENDED);
+ skipHash = cfg.getBoolean(ConfigConstants.CONFIG_INDEX_SECTION,
+ ConfigConstants.CONFIG_KEY_SKIPHASH, false);
}
public DirCacheVersion getIndexVersion() {
return indexVersion;
}
+ public boolean isSkipHash() {
+ return skipHash;
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/NullMessageDigest.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/NullMessageDigest.java
new file mode 100644
index 0000000000..ea5877ffff
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/NullMessageDigest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023, SAP SE 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.io;
+
+import java.security.MessageDigest;
+
+import org.eclipse.jgit.lib.Constants;
+
+/**
+ * Dummy message digest consisting of only null bytes with the length of an
+ * ObjectId. This class can be used to skip computing a real digest.
+ */
+public final class NullMessageDigest extends MessageDigest {
+ private static final byte[] digest = new byte[Constants.OBJECT_ID_LENGTH];
+
+ private static final NullMessageDigest INSTANCE = new NullMessageDigest();
+
+ /**
+ * Get the only instance of NullMessageDigest
+ *
+ * @return the only instance of NullMessageDigest
+ */
+ public static MessageDigest getInstance() {
+ return INSTANCE;
+ }
+
+ private NullMessageDigest() {
+ super("null"); //$NON-NLS-1$
+ }
+
+ @Override
+ protected void engineUpdate(byte input) {
+ // empty
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ // empty
+ }
+
+ @Override
+ protected byte[] engineDigest() {
+ return digest;
+ }
+
+ @Override
+ protected void engineReset() {
+ // empty
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 7d3430ffc5..634e3f7f86 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -349,6 +349,12 @@ public final class ConfigConstants {
public static final String CONFIG_KEY_INDEXVERSION = "indexversion";
/**
+ * The "skiphash" key
+ * @since 5.13.2
+ */
+ public static final String CONFIG_KEY_SKIPHASH = "skiphash";
+
+ /**
* The "hidedotfiles" key
* @since 3.5
*/

Back to the top