aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDariusz Luksza <dariusz.luksza@gmail.com>2024-02-12 09:58:41 +0000
committerDariusz Luksza <dariusz.luksza@gmail.com>2024-02-12 09:58:41 +0000
commit4f85ca0dc0ad12ee03d4015d1357962bbce1d157 (patch)
tree6cb2653217032cbfbc7dee1d4b306e74487105da
parent03d465c49c7957fc51fcc3e2f32021913b113784 (diff)
parent56d040b8c73c224aea19c6930bf0892b5b9aca1c (diff)
downloadjgit-4f85ca0dc0ad12ee03d4015d1357962bbce1d157.tar.gz
jgit-4f85ca0dc0ad12ee03d4015d1357962bbce1d157.zip
Merge branch 'stable-6.7' into stable-6.8
* stable-6.7: Improve handling of NFS stale handle errors Fix handling of missing pack index file Add tests for handling pack files removal during fetch Change-Id: I409d1dc3354ad65c048d2c40f39071a1207246c6
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackHandleDeletedPackFileTest.java146
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java24
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java4
3 files changed, 169 insertions, 5 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackHandleDeletedPackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackHandleDeletedPackFileTest.java
new file mode 100644
index 0000000000..417ce61df2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackHandleDeletedPackFileTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2023, Dariusz Luksza <dariusz.luksza@gmail.com> 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.transport;
+
+import static org.junit.Assert.fail;
+import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.internal.storage.file.GC;
+import org.eclipse.jgit.internal.storage.file.Pack;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.junit.TestRepository.CommitBuilder;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.UploadPack.RequestPolicy;
+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 UploadPackHandleDeletedPackFileTest
+ extends LocalDiskRepositoryTestCase {
+
+ private FileRepository server;
+
+ private TestRepository<FileRepository> remote;
+
+ private Repository client;
+
+ private RevCommit head;
+
+ @Parameter
+ public boolean emptyCommit;
+
+ @Parameters(name="empty commit: {0}")
+ public static Collection<Boolean[]> initTestData() {
+ return Arrays.asList(
+ new Boolean[][] { { Boolean.TRUE }, { Boolean.FALSE } });
+ }
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ server = createBareRepository();
+ server.getConfig().setString("protocol", null, "version", "2");
+
+ remote = new TestRepository<>(server);
+ client = new InMemoryRepository(new DfsRepositoryDescription("client"));
+
+ setupServerRepo();
+ head = server.parseCommit(server.resolve(HEAD));
+ }
+
+ @Test
+ public void testV2PackFileRemovedDuringUploadPack() throws Exception {
+ doRemovePackFileDuringUploadPack(PackExt.PACK);
+ }
+
+ @Test
+ public void testV2IdxFileRemovedDuringUploadPack() throws Exception {
+ doRemovePackFileDuringUploadPack(PackExt.INDEX);
+ }
+
+ @Test
+ public void testV2BitmapFileRemovedDuringUploadPack() throws Exception {
+ doRemovePackFileDuringUploadPack(PackExt.BITMAP_INDEX);
+ }
+
+ private void doRemovePackFileDuringUploadPack(PackExt packExt)
+ throws Exception {
+ Object ctx = new Object();
+ TestProtocol testProtocol = new TestProtocol<>(
+ (Object req, Repository db) -> {
+ UploadPack up = new UploadPack(db);
+ up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);
+ Collection<Pack> packs = server.getObjectDatabase()
+ .getPacks();
+ assertEquals("single pack expected", 1, packs.size());
+ Pack pack = packs.iterator().next();
+
+ try {
+ addNewCommit();
+
+ new GC(remote.getRepository()).gc();
+
+ pack.getPackFile().create(packExt).delete();
+ } catch (Exception e) {
+ fail("GC or pack file removal failed");
+ }
+
+ return up;
+ }, null);
+
+ URIish uri = testProtocol.register(ctx, server);
+
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.fetch(NullProgressMonitor.INSTANCE,
+ Collections.singletonList(new RefSpec(head.name())));
+ assertTrue(client.getObjectDatabase().has(head));
+ }
+ }
+
+ private void addNewCommit() throws Exception {
+ CommitBuilder commit = remote.commit().message("2");
+ if (!emptyCommit) {
+ commit = commit.add("test2.txt", remote.blob("2"));
+ }
+ remote.update("master", commit.parent(head).create());
+ }
+
+ private void setupServerRepo() throws Exception {
+ RevCommit commit0 = remote.commit().message("0")
+ .add("test.txt", remote.blob("0"))
+ .create();
+ remote.update("master", commit0);
+
+ new GC(remote.getRepository()).gc(); // create pack files
+
+ head = remote.commit().message("1").parent(commit0)
+ .add("test1.txt", remote.blob("1"))
+ .create();
+ remote.update("master", head);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
index 90f9811679..4f1d348844 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
@@ -64,6 +64,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.util.Hex;
+import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.LongList;
import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.RawParseUtils;
@@ -682,7 +683,12 @@ public class Pack implements Iterable<PackIndex.MutableEntry> {
// exceptions signaling permanent problems with a pack
openFail(true, pe);
throw pe;
- } catch (IOException | RuntimeException ge) {
+ } catch (IOException ioe) {
+ // mark this packfile as invalid when NFS stale file handle error
+ // occur
+ openFail(FileUtils.isStaleFileHandleInCausalChain(ioe), ioe);
+ throw ioe;
+ } catch (RuntimeException ge) {
// generic exceptions could be transient so we should not mark the
// pack invalid to avoid false MissingObjectExceptions
openFail(false, ge);
@@ -1153,9 +1159,19 @@ public class Pack implements Iterable<PackIndex.MutableEntry> {
return idx;
}
} catch (FileNotFoundException e) {
- // Once upon a time this bitmap file existed. Now it
- // has been removed. Most likely an external gc has
- // removed this packfile and the bitmap
+ // Once upon a time the bitmap or index files existed. Now one
+ // of them has been removed. Most likely an external gc has
+ // removed index, packfile or the bitmap
+ bitmapIdxFile = null;
+ return null;
+ } catch (IOException e) {
+ if (!FileUtils.isStaleFileHandleInCausalChain(e)) {
+ throw e;
+ }
+ // Ignore NFS stale handle exception the same way as
+ // FileNotFoundException above.
+ bitmapIdxFile = null;
+ return null;
}
bitmapIdxFile = null;
return null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
index 99987cd635..c42d1c8866 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -64,7 +64,9 @@ public abstract class PackIndex
public static PackIndex open(File idxFile) throws IOException {
try (SilentFileInputStream fd = new SilentFileInputStream(
idxFile)) {
- return read(fd);
+ return read(fd);
+ } catch (FileNotFoundException e) {
+ throw e;
} catch (IOException ioe) {
throw new IOException(
MessageFormat.format(JGitText.get().unreadablePackIndex,