Merge branch 'stable-6.2' into stable-6.3
* stable-6.2:
Use Java 11 ProcessHandle to get pid of the current process
Acquire file lock "gc.pid" before running gc
Silence API errors introduced by 9424052f
Change-Id: I53cf9675deac0b588048d8224216d2a7e8bd16ec
This commit is contained in:
commit
c70374e641
|
@ -137,6 +137,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}
|
||||
|
@ -311,6 +312,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
|
||||
|
@ -330,6 +332,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
|
||||
|
@ -695,6 +698,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
|
||||
|
|
|
@ -165,6 +165,7 @@ public static JGitText get() {
|
|||
/***/ public String cloneNonEmptyDirectory;
|
||||
/***/ public String closeLockTokenFailed;
|
||||
/***/ public String closed;
|
||||
/***/ public String closePidLockFailed;
|
||||
/***/ public String collisionOn;
|
||||
/***/ public String commandClosedStderrButDidntExit;
|
||||
/***/ public String commandRejectedByHook;
|
||||
|
@ -339,6 +340,7 @@ public static JGitText get() {
|
|||
/***/ public String expectedReportForRefNotReceived;
|
||||
/***/ public String failedAtomicFileCreation;
|
||||
/***/ public String failedCreateLockFile;
|
||||
/***/ public String failedPidLock;
|
||||
/***/ public String failedReadHttpsProtocols;
|
||||
/***/ public String failedToDetermineFilterDefinition;
|
||||
/***/ public String failedToConvert;
|
||||
|
@ -358,6 +360,7 @@ public static JGitText get() {
|
|||
/***/ public String flagNotFromThis;
|
||||
/***/ public String flagsAlreadyCreated;
|
||||
/***/ public String funnyRefname;
|
||||
/***/ public String gcAlreadyRunning;
|
||||
/***/ public String gcFailed;
|
||||
/***/ public String gcTooManyUnpruned;
|
||||
/***/ public String headRequiredToStash;
|
||||
|
@ -723,6 +726,7 @@ public static JGitText get() {
|
|||
/***/ public String sslTrustForRepo;
|
||||
/***/ public String sslTrustNow;
|
||||
/***/ public String sslVerifyCannotSave;
|
||||
/***/ public String stalePidLock;
|
||||
/***/ public String staleRevFlagsOn;
|
||||
/***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported;
|
||||
/***/ public String stashApplyConflict;
|
||||
|
|
|
@ -20,9 +20,16 @@
|
|||
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;
|
||||
|
@ -44,6 +51,7 @@
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -84,8 +92,11 @@
|
|||
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;
|
||||
|
@ -262,13 +273,18 @@ private Collection<Pack> doGc() throws IOException, ParseException {
|
|||
if (automatic && !needGc()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
pm.start(6 /* tasks */);
|
||||
packRefs();
|
||||
// TODO: implement reflog_expire(pm, repo);
|
||||
Collection<Pack> newPacks = repack();
|
||||
prune(Collections.emptySet());
|
||||
// TODO: implement rerere_gc(pm);
|
||||
return newPacks;
|
||||
try (PidLock lock = new PidLock()) {
|
||||
if (!lock.lock()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
pm.start(6 /* tasks */);
|
||||
packRefs();
|
||||
// TODO: implement reflog_expire(pm, repo);
|
||||
Collection<Pack> newPacks = repack();
|
||||
prune(Collections.emptySet());
|
||||
// TODO: implement rerere_gc(pm);
|
||||
return newPacks;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1596,4 +1612,143 @@ private int getLooseObjectLimit() {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue