Merge branch 'stable-5.13' into stable-6.0

* stable-5.13:
  Remove stray files (probes or lock files) created by background threads

Change-Id: I7af1355a77f14995118145162f6bb8a4f1755f2b
This commit is contained in:
Matthias Sohn 2022-05-27 16:20:28 +02:00
commit 9612aae885
3 changed files with 39 additions and 9 deletions

View File

@ -200,4 +200,16 @@ public void testLockForAppend() throws Exception {
assertFalse(lock.isLocked()); assertFalse(lock.isLocked());
checkFile(f, "contentother"); checkFile(f, "contentother");
} }
@Test
public void testUnlockNoop() throws Exception {
File f = writeTrashFile("somefile", "content");
try {
LockFile lock = new LockFile(f);
lock.unlock();
lock.unlock();
} catch (Throwable e) {
fail("unlock should be noop if not locked at all.");
}
}
} }

View File

@ -216,9 +216,10 @@ public void save() throws IOException {
} }
final LockFile lf = new LockFile(getFile()); final LockFile lf = new LockFile(getFile());
if (!lf.lock())
throw new LockFailedException(getFile());
try { try {
if (!lf.lock()) {
throw new LockFailedException(getFile());
}
lf.setNeedSnapshotNoConfig(true); lf.setNeedSnapshotNoConfig(true);
lf.write(out); lf.write(out);
if (!lf.commit()) if (!lf.commit())

View File

@ -47,7 +47,6 @@
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -262,8 +261,9 @@ public static final class FileStoreAttributes {
* *
* @see java.util.concurrent.Executors#newCachedThreadPool() * @see java.util.concurrent.Executors#newCachedThreadPool()
*/ */
private static final Executor FUTURE_RUNNER = new ThreadPoolExecutor(0, private static final ExecutorService FUTURE_RUNNER = new ThreadPoolExecutor(
5, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), 0, 5, 30L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
runnable -> { runnable -> {
Thread t = new Thread(runnable, Thread t = new Thread(runnable,
"JGit-FileStoreAttributeReader-" //$NON-NLS-1$ "JGit-FileStoreAttributeReader-" //$NON-NLS-1$
@ -285,8 +285,9 @@ public static final class FileStoreAttributes {
* small keep-alive time to avoid delays on shut-down. * small keep-alive time to avoid delays on shut-down.
* </p> * </p>
*/ */
private static final Executor SAVE_RUNNER = new ThreadPoolExecutor(0, 1, private static final ExecutorService SAVE_RUNNER = new ThreadPoolExecutor(
1L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), 0, 1, 1L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
runnable -> { runnable -> {
Thread t = new Thread(runnable, Thread t = new Thread(runnable,
"JGit-FileStoreAttributeWriter-" //$NON-NLS-1$ "JGit-FileStoreAttributeWriter-" //$NON-NLS-1$
@ -296,6 +297,18 @@ public static final class FileStoreAttributes {
return t; return t;
}); });
static {
// Shut down the SAVE_RUNNER on System.exit()
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
SAVE_RUNNER.shutdownNow();
SAVE_RUNNER.awaitTermination(100, TimeUnit.MILLISECONDS);
} catch (Exception e) {
// Ignore; we're shutting down
}
}));
}
/** /**
* Whether FileStore attributes should be determined asynchronously * Whether FileStore attributes should be determined asynchronously
* *
@ -452,11 +465,13 @@ private static FileStoreAttributes getFileStoreAttributes(Path dir) {
return null; return null;
} }
// fall through and return fallback // fall through and return fallback
} catch (IOException | InterruptedException } catch (IOException | ExecutionException | CancellationException e) {
| ExecutionException | CancellationException e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
} catch (TimeoutException | SecurityException e) { } catch (TimeoutException | SecurityException e) {
// use fallback // use fallback
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
Thread.currentThread().interrupt();
} }
LOG.debug("{}: use fallback timestamp resolution for directory {}", //$NON-NLS-1$ LOG.debug("{}: use fallback timestamp resolution for directory {}", //$NON-NLS-1$
Thread.currentThread(), dir); Thread.currentThread(), dir);
@ -474,6 +489,7 @@ private static Duration measureMinimalRacyInterval(Path dir) {
Path probe = dir.resolve(".probe-" + UUID.randomUUID()); //$NON-NLS-1$ Path probe = dir.resolve(".probe-" + UUID.randomUUID()); //$NON-NLS-1$
Instant end = Instant.now().plusSeconds(3); Instant end = Instant.now().plusSeconds(3);
try { try {
probe.toFile().deleteOnExit();
Files.createFile(probe); Files.createFile(probe);
do { do {
n++; n++;
@ -540,6 +556,7 @@ private static Optional<Duration> measureFsTimestampResolution(
} }
Path probe = dir.resolve(".probe-" + UUID.randomUUID()); //$NON-NLS-1$ Path probe = dir.resolve(".probe-" + UUID.randomUUID()); //$NON-NLS-1$
try { try {
probe.toFile().deleteOnExit();
Files.createFile(probe); Files.createFile(probe);
Duration fsResolution = getFsResolution(s, dir, probe); Duration fsResolution = getFsResolution(s, dir, probe);
Duration clockResolution = measureClockResolution(); Duration clockResolution = measureClockResolution();