aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Sohn <matthias.sohn@sap.com>2023-02-22 02:18:10 +0100
committerMatthias Sohn <matthias.sohn@sap.com>2023-02-22 02:18:10 +0100
commit95240cefaceaf31c991b19777fe77806abf08ad3 (patch)
tree46d910cd13f27de299ba6f6c3620ded6dc8f5e77
parentc8683db55d79b06ca7bdd04651a6520eaa7b15d9 (diff)
parente92212a5a00c84f5e1dda0b44646ba90c147b4da (diff)
downloadjgit-95240cefaceaf31c991b19777fe77806abf08ad3.tar.gz
jgit-95240cefaceaf31c991b19777fe77806abf08ad3.zip
Merge branch 'master' into stable-6.5
* master: Use Java 11 ProcessHandle to get pid of the current process UploadPack: use allow-any-sha1-in-want configuration Acquire file lock "gc.pid" before running gc Silence API errors introduced by 9424052f Change-Id: I71c8ee39e0f3438cbc1992c24f9f6c33ece88c07
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java44
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java154
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java15
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java4
6 files changed, 224 insertions, 1 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index 4ad7fa3149..0e97d7b155 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -2726,6 +2726,50 @@ public class UploadPackTest {
assertEquals(1, stats.getNotAdvertisedWants());
}
+ @Test
+ public void testAllowAnySha1InWantConfig() {
+ server.getConfig().setBoolean("uploadpack", null, "allowanysha1inwant",
+ true);
+
+ try (UploadPack uploadPack = new UploadPack(server)) {
+ assertEquals(RequestPolicy.ANY, uploadPack.getRequestPolicy());
+ }
+ }
+
+ @Test
+ public void testAllowReachableSha1InWantConfig() {
+ server.getConfig().setBoolean("uploadpack", null,
+ "allowreachablesha1inwant", true);
+
+ try (UploadPack uploadPack = new UploadPack(server)) {
+ assertEquals(RequestPolicy.REACHABLE_COMMIT,
+ uploadPack.getRequestPolicy());
+ }
+ }
+
+ @Test
+ public void testAllowTipSha1InWantConfig() {
+ server.getConfig().setBoolean("uploadpack", null, "allowtipsha1inwant",
+ true);
+
+ try (UploadPack uploadPack = new UploadPack(server)) {
+ assertEquals(RequestPolicy.TIP, uploadPack.getRequestPolicy());
+ }
+ }
+
+ @Test
+ public void testAllowReachableTipSha1InWantConfig() {
+ server.getConfig().setBoolean("uploadpack", null,
+ "allowreachablesha1inwant", true);
+ server.getConfig().setBoolean("uploadpack", null, "allowtipsha1inwant",
+ true);
+
+ try (UploadPack uploadPack = new UploadPack(server)) {
+ assertEquals(RequestPolicy.REACHABLE_COMMIT_TIP,
+ uploadPack.getRequestPolicy());
+ }
+ }
+
private class RefCallsCountingRepository extends InMemoryRepository {
private final InMemoryRepository.MemRefDatabase refdb;
private int numRefCalls;
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 72a3d1cdea..faea9cbea3 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -140,6 +140,7 @@ classCastNotA=Not a {0}
cloneNonEmptyDirectory=Destination path "{0}" already exists and is not an empty directory
closed=closed
closeLockTokenFailed=Closing LockToken ''{0}'' failed
+closePidLockFailed=Closing lock file ''{0}'' failed
collisionOn=Collision on {0}
commandClosedStderrButDidntExit=Command {0} closed stderr stream but didn''t exit within timeout {1} seconds
commandRejectedByHook=Rejected by "{0}" hook.\n{1}
@@ -323,6 +324,7 @@ expectedReceivedContentType=expected Content-Type {0}; received Content-Type {1}
expectedReportForRefNotReceived={0}: expected report for ref {1} not received
failedAtomicFileCreation=Atomic file creation failed, number of hard links to file {0} was not 2 but {1}
failedCreateLockFile=Creating lock file {} failed
+failedPidLock=Failed to lock ''{0}'' guarding git gc
failedReadHttpsProtocols=Failed to read system property https.protocols, assuming it is not set
failedToConvert=Failed to convert rest: %s
failedToDetermineFilterDefinition=An exception occurred while determining filter definitions
@@ -343,6 +345,7 @@ flagIsDisposed={0} is disposed.
flagNotFromThis={0} not from this.
flagsAlreadyCreated={0} flags already created.
funnyRefname=funny refname
+gcAlreadyRunning=fatal: gc is already running on machine ''{0}'' pid {1}
gcFailed=Garbage collection failed.
gcTooManyUnpruned=Too many loose, unpruneable objects after garbage collection. Consider adjusting gc.auto or gc.pruneExpire.
headRequiredToStash=HEAD required to stash local changes
@@ -714,6 +717,7 @@ sslTrustAlways=Always skip SSL verification for this server from now on
sslTrustForRepo=Skip SSL verification for git operations for repository {0}
sslTrustNow=Skip SSL verification for this single git operation
sslVerifyCannotSave=Could not save setting for http.sslVerify
+stalePidLock=Lock file ''{0}'' is older than 12 hours and seems to be stale, lastModified: {1}, trying to lock it
staleRevFlagsOn=Stale RevFlags on {0}
startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported
stashApplyConflict=Applying stashed changes resulted in a conflict
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index d8720be56f..39cc749cc4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -168,6 +168,7 @@ public class JGitText extends TranslationBundle {
/***/ public String cloneNonEmptyDirectory;
/***/ public String closeLockTokenFailed;
/***/ public String closed;
+ /***/ public String closePidLockFailed;
/***/ public String collisionOn;
/***/ public String commandClosedStderrButDidntExit;
/***/ public String commandRejectedByHook;
@@ -351,6 +352,7 @@ public class JGitText extends TranslationBundle {
/***/ public String expectedReportForRefNotReceived;
/***/ public String failedAtomicFileCreation;
/***/ public String failedCreateLockFile;
+ /***/ public String failedPidLock;
/***/ public String failedReadHttpsProtocols;
/***/ public String failedToDetermineFilterDefinition;
/***/ public String failedToConvert;
@@ -371,6 +373,7 @@ public class JGitText extends TranslationBundle {
/***/ public String flagNotFromThis;
/***/ public String flagsAlreadyCreated;
/***/ public String funnyRefname;
+ /***/ public String gcAlreadyRunning;
/***/ public String gcFailed;
/***/ public String gcTooManyUnpruned;
/***/ public String headRequiredToStash;
@@ -742,6 +745,7 @@ public class JGitText extends TranslationBundle {
/***/ public String sslTrustForRepo;
/***/ public String sslTrustNow;
/***/ public String sslVerifyCannotSave;
+ /***/ public String stalePidLock;
/***/ public String staleRevFlagsOn;
/***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported;
/***/ public String stashApplyConflict;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index d41aea4fdd..111a4f301f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -21,9 +21,16 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.io.RandomAccessFile;
import java.io.StringWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
@@ -89,8 +96,11 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.LockToken;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.GitDateParser;
+import org.eclipse.jgit.util.StringUtils;
import org.eclipse.jgit.util.SystemReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -265,6 +275,10 @@ public class GC {
if (automatic && !needGc()) {
return Collections.emptyList();
}
+ try (PidLock lock = new PidLock()) {
+ if (!lock.lock()) {
+ return Collections.emptyList();
+ }
pm.start(6 /* tasks */);
packRefs();
// TODO: implement reflog_expire(pm, repo);
@@ -276,6 +290,7 @@ public class GC {
}
return newPacks;
}
+ }
/**
* Loosen objects in a pack file which are not also in the newly-created
@@ -1706,4 +1721,143 @@ public class GC {
return repo.getConfig().getInt(ConfigConstants.CONFIG_GC_SECTION,
ConfigConstants.CONFIG_KEY_AUTO, DEFAULT_AUTOLIMIT);
}
+
+ private class PidLock implements AutoCloseable {
+
+ private static final String GC_PID = "gc.pid"; //$NON-NLS-1$
+
+ private final Path pidFile;
+
+ private LockToken token;
+
+ private FileLock lock;
+
+ private RandomAccessFile f;
+
+ private FileChannel channel;
+
+ PidLock() {
+ pidFile = repo.getDirectory().toPath().resolve(GC_PID);
+ }
+
+ boolean lock() {
+ if (Files.exists(pidFile)) {
+ Instant mtime = FS.DETECTED
+ .lastModifiedInstant(pidFile.toFile());
+ Instant twelveHoursAgo = Instant.now().minus(12,
+ ChronoUnit.HOURS);
+ if (mtime.compareTo(twelveHoursAgo) > 0) {
+ gcAlreadyRunning();
+ return false;
+ }
+ LOG.warn(MessageFormat.format(JGitText.get().stalePidLock,
+ pidFile, mtime));
+ }
+ try {
+ token = FS.DETECTED.createNewFileAtomic(pidFile.toFile());
+ f = new RandomAccessFile(pidFile.toFile(), "rw"); //$NON-NLS-1$
+ channel = f.getChannel();
+ lock = channel.tryLock();
+ if (lock == null) {
+ failedToLock();
+ return false;
+ }
+ channel.write(ByteBuffer
+ .wrap(getProcDesc().getBytes(StandardCharsets.UTF_8)));
+ Thread cleanupHook = new Thread(() -> close());
+ try {
+ Runtime.getRuntime().addShutdownHook(cleanupHook);
+ } catch (IllegalStateException e) {
+ // ignore - the VM is already shutting down
+ }
+ } catch (IOException | OverlappingFileLockException e) {
+ try {
+ failedToLock();
+ } catch (Exception e1) {
+ LOG.error(
+ MessageFormat.format(
+ JGitText.get().closePidLockFailed, pidFile),
+ e1);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ private void failedToLock() {
+ close();
+ LOG.error(MessageFormat.format(JGitText.get().failedPidLock,
+ pidFile));
+ }
+
+ private void gcAlreadyRunning() {
+ close();
+ try {
+ Optional<String> s = Files.lines(pidFile).findFirst();
+ String machine = null;
+ String pid = null;
+ if (s.isPresent()) {
+ String[] c = s.get().split("\\s+"); //$NON-NLS-1$
+ pid = c[0];
+ machine = c[1];
+ }
+ if (!StringUtils.isEmptyOrNull(machine)
+ && !StringUtils.isEmptyOrNull(pid)) {
+ LOG.error(MessageFormat.format(
+ JGitText.get().gcAlreadyRunning, machine, pid));
+ return;
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ LOG.error(MessageFormat.format(JGitText.get().failedPidLock,
+ pidFile));
+ }
+
+ private String getProcDesc() {
+ StringBuffer s = new StringBuffer(Long.toString(getPID()));
+ s.append(' ');
+ s.append(getHostName());
+ return s.toString();
+ }
+
+ private long getPID() {
+ return ProcessHandle.current().pid();
+ }
+
+ private String getHostName() {
+ try {
+ return InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e) {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public void close() {
+ boolean wasLocked = false;
+ try {
+ if (lock != null) {
+ lock.release();
+ wasLocked = true;
+ }
+ if (channel != null) {
+ channel.close();
+ }
+ if (f != null) {
+ f.close();
+ }
+ if (token != null) {
+ token.close();
+ }
+ if (wasLocked) {
+ FileUtils.delete(pidFile.toFile(), FileUtils.RETRY);
+ }
+ } catch (IOException e) {
+ LOG.error(MessageFormat
+ .format(JGitText.get().closePidLockFailed, pidFile), e);
+ }
+ }
+
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index 805166a405..064201a629 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2020 Google Inc. and others
+ * Copyright (C) 2008, 2023 Google Inc. 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
@@ -118,6 +118,7 @@ public class TransferConfig {
private final boolean allowRefInWant;
private final boolean allowTipSha1InWant;
private final boolean allowReachableSha1InWant;
+ private final boolean allowAnySha1InWant;
private final boolean allowFilter;
private final boolean allowSidebandAll;
@@ -202,6 +203,8 @@ public class TransferConfig {
"uploadpack", "allowtipsha1inwant", false);
allowReachableSha1InWant = rc.getBoolean(
"uploadpack", "allowreachablesha1inwant", false);
+ allowAnySha1InWant = rc.getBoolean("uploadpack", "allowanysha1inwant",
+ false);
allowFilter = rc.getBoolean(
"uploadpack", "allowfilter", false);
protocolVersion = ProtocolVersion.parse(rc
@@ -284,6 +287,16 @@ public class TransferConfig {
}
/**
+ * Whether to allow clients to request any SHA-1s
+ *
+ * @return allow clients to request any SHA-1s?
+ * @since 6.5
+ */
+ public boolean isAllowAnySha1InWant() {
+ return allowAnySha1InWant;
+ }
+
+ /**
* @return true if clients are allowed to specify a "filter" line
* @since 5.0
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 38c7cb94bb..b648706475 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -681,6 +681,10 @@ public class UploadPack implements Closeable {
*/
public void setTransferConfig(@Nullable TransferConfig tc) {
this.transferConfig = tc != null ? tc : new TransferConfig(db);
+ if (transferConfig.isAllowAnySha1InWant()) {
+ setRequestPolicy(RequestPolicy.ANY);
+ return;
+ }
if (transferConfig.isAllowTipSha1InWant()) {
setRequestPolicy(transferConfig.isAllowReachableSha1InWant()
? RequestPolicy.REACHABLE_COMMIT_TIP : RequestPolicy.TIP);