From 23b9693a75b899c97da8a04c0b531874b225d236 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Mon, 27 Mar 2023 22:23:11 +0200 Subject: [PATCH 1/2] 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 --- .../jgit/dircache/DirCacheBasicTest.java | 29 ++++++++++ org.eclipse.jgit/.settings/.api_filters | 6 ++ .../org/eclipse/jgit/dircache/DirCache.java | 50 ++++++++++++---- .../storage/io/NullMessageDigest.java | 58 +++++++++++++++++++ .../org/eclipse/jgit/lib/ConfigConstants.java | 6 ++ 5 files changed, 137 insertions(+), 12 deletions(-) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/NullMessageDigest.java 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 0fca65290..618ccc0a0 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.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 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 01366d259..e12ec17f3 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -19,6 +19,12 @@ + + + + + + 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 03da61583..e56061223 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.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 static DirCache lock(final File indexLocation, final FS fs, /** 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. *

@@ -446,7 +450,8 @@ public void clear() { 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 @@ private void readFrom(InputStream inStream) throws IOException, } 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 void write() throws IOException { } 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 @@ void writeTo(File dir, OutputStream os) throws IOException { 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. *

@@ -1071,6 +1090,8 @@ private static class DirCacheConfig { 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 DirCacheConfig(Config cfg) { 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 000000000..ea5877fff --- /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 7d3430ffc..634e3f7f8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -348,6 +348,12 @@ public final class ConfigConstants { /** The "indexversion" key */ 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 From f73efea21f0dd1aefcf3aa1cd1a3718f2e598b34 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Fri, 14 Apr 2023 18:13:18 +0200 Subject: [PATCH 2/2] Remove blank in maven.config Maven 3.9.1 doesn't accept this whitespace. Change-Id: I0f6e3652b1e581615c370d35bc782184712ac922 --- .mvn/maven.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/maven.config b/.mvn/maven.config index ebbe28853..3944d880e 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -1 +1 @@ --T 1C +-T1C