aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org
diff options
context:
space:
mode:
authorMatthias Sohn <matthias.sohn@sap.com>2024-11-15 08:37:10 +0100
committerMatthias Sohn <matthias.sohn@sap.com>2025-03-03 20:50:40 +0100
commit1ff9c2a1cbd5ac718559eef152d954755f257bc8 (patch)
treec748f6d95d82344549733ec6d75044c06a320e23 /org.eclipse.jgit/src/org
parent5db57fe2a932fc05d28e057df9ff9d6a0bd6abe3 (diff)
downloadjgit-1ff9c2a1cbd5ac718559eef152d954755f257bc8.tar.gz
jgit-1ff9c2a1cbd5ac718559eef152d954755f257bc8.zip
FileReftableDatabase: consider ref updates by another process
FileReftableDatabase didn't consider that refs might be changed by another process e.g. using git (which started supporting reftable with version 2.45). Add a test creating a light-weight tag which is updated using git running in another process and assert that FileReftableDatabase recognizes the tag modification. FileReftableStack#addReftable checks if the stack is up-to-date while it holds the FileLock for tables.list, if it is not up-to-date the RefUpdate fails with a LOCK_FAILURE to protect against lost ref updates if another instance of FileReftableDatabase or another thread or process updated the reftable stack since we last read it. If option `reftable.autoRefresh = true` or `setAutoRefresh(true)` was called check before each ref resolution if the reftable stack is up-to-date and, if necessary, reload the reftable stack automatically. Calling `setAutoRefresh(true)` takes precedence over the configured value for option `reftable.autoRefresh`. Add a testConcurrentRacyReload which tests that updates still abort ref updates if the reftable stack the update is based on was outdated. Bug: jgit-102 Change-Id: I1f9faa2afdbfff27e83ff295aef6d572babed4fe
Diffstat (limited to 'org.eclipse.jgit/src/org')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java54
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java14
2 files changed, 68 insertions, 0 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
index 6040ad554d..d70fa839e9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
@@ -16,6 +16,7 @@ import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
import java.io.File;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -37,6 +38,7 @@ import org.eclipse.jgit.internal.storage.reftable.ReftableBatchRefUpdate;
import org.eclipse.jgit.internal.storage.reftable.ReftableDatabase;
import org.eclipse.jgit.internal.storage.reftable.ReftableWriter;
import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
@@ -70,6 +72,8 @@ public class FileReftableDatabase extends RefDatabase {
private final FileReftableStack reftableStack;
+ private boolean autoRefresh;
+
FileReftableDatabase(FileRepository repo) throws IOException {
this(repo, new File(new File(repo.getCommonDirectory(), Constants.REFTABLE),
Constants.TABLES_LIST));
@@ -77,6 +81,9 @@ public class FileReftableDatabase extends RefDatabase {
FileReftableDatabase(FileRepository repo, File refstackName) throws IOException {
this.fileRepository = repo;
+ this.autoRefresh = repo.getConfig().getBoolean(
+ ConfigConstants.CONFIG_REFTABLE_SECTION,
+ ConfigConstants.CONFIG_KEY_AUTOREFRESH, false);
this.reftableStack = new FileReftableStack(refstackName,
new File(fileRepository.getCommonDirectory(), Constants.REFTABLE),
() -> fileRepository.fireEvent(new RefsChangedEvent()),
@@ -183,6 +190,7 @@ public class FileReftableDatabase extends RefDatabase {
@Override
public Ref exactRef(String name) throws IOException {
+ autoRefresh();
return reftableDatabase.exactRef(name);
}
@@ -193,6 +201,7 @@ public class FileReftableDatabase extends RefDatabase {
@Override
public Map<String, Ref> getRefs(String prefix) throws IOException {
+ autoRefresh();
List<Ref> refs = reftableDatabase.getRefsByPrefix(prefix);
RefList.Builder<Ref> builder = new RefList.Builder<>(refs.size());
for (Ref r : refs) {
@@ -205,6 +214,7 @@ public class FileReftableDatabase extends RefDatabase {
@Override
public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes)
throws IOException {
+ autoRefresh();
return reftableDatabase.getRefsByPrefixWithExclusions(include, excludes);
}
@@ -223,6 +233,50 @@ public class FileReftableDatabase extends RefDatabase {
}
+ /**
+ * Whether to auto-refresh the reftable stack if it is out of date.
+ *
+ * @param autoRefresh
+ * whether to auto-refresh the reftable stack if it is out of
+ * date.
+ */
+ public void setAutoRefresh(boolean autoRefresh) {
+ this.autoRefresh = autoRefresh;
+ }
+
+ /**
+ * Whether the reftable stack is auto-refreshed if it is out of date.
+ *
+ * @return whether the reftable stack is auto-refreshed if it is out of
+ * date.
+ */
+ public boolean isAutoRefresh() {
+ return autoRefresh;
+ }
+
+ private void autoRefresh() {
+ if (autoRefresh) {
+ refresh();
+ }
+ }
+
+ /**
+ * Check if the reftable stack is up to date, and if not, reload it.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void refresh() {
+ try {
+ if (!reftableStack.isUpToDate()) {
+ reftableDatabase.clearCache();
+ reftableStack.reload();
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
private Ref doPeel(Ref leaf) throws IOException {
try (RevWalk rw = new RevWalk(fileRepository)) {
RevObject obj = rw.parseAny(leaf.getObjectId());
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 30e7de47c3..f62bf161a7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -1093,4 +1093,18 @@ public final class ConfigConstants {
* @since 7.1
*/
public static final String CONFIG_KEY_LOAD_REV_INDEX_IN_PARALLEL = "loadRevIndexInParallel";
+
+ /**
+ * The "reftable" section
+ *
+ * @since 7.2
+ */
+ public static final String CONFIG_REFTABLE_SECTION = "reftable";
+
+ /**
+ * The "autorefresh" key
+ *
+ * @since 7.2
+ */
+ public static final String CONFIG_KEY_AUTOREFRESH = "autorefresh";
}