summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java49
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java21
6 files changed, 77 insertions, 5 deletions
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 992e10bad6..a99bd7e911 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -21,6 +21,7 @@ atLeastOnePathIsRequired=At least one path is required.
atLeastOnePatternIsRequired=At least one pattern is required.
atLeastTwoFiltersNeeded=At least two filters needed.
atomicPushNotSupported=Atomic push not supported.
+atomicRefUpdatesNotSupported=Atomic ref updates not supported
authenticationNotSupported=authentication not supported
badBase64InputCharacterAt=Bad Base64 input character at {0} : {1} (decimal)
badEntryDelimiter=Bad entry delimiter
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 7740a2bb80..dc640fe314 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -80,6 +80,7 @@ public class JGitText extends TranslationBundle {
/***/ public String atLeastOnePatternIsRequired;
/***/ public String atLeastTwoFiltersNeeded;
/***/ public String atomicPushNotSupported;
+ /***/ public String atomicRefUpdatesNotSupported;
/***/ public String authenticationNotSupported;
/***/ public String badBase64InputCharacterAt;
/***/ public String badEntryDelimiter;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
index ccf1b42b3d..de18eadb22 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
@@ -280,7 +280,7 @@ public class InMemoryRepository extends DfsRepository {
@Override
public void execute(RevWalk walk, ProgressMonitor monitor)
throws IOException {
- if (performsAtomicTransactions()) {
+ if (performsAtomicTransactions() && isAtomic()) {
try {
lock.writeLock().lock();
batch(getCommands());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
index a55a9f51e7..1cccd79810 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
@@ -98,8 +98,12 @@ class RefTreeBatch extends BatchRefUpdate {
}
if (c.getType() == UPDATE_NONFASTFORWARD) {
c.setResult(REJECTED_NONFASTFORWARD);
- ReceiveCommand.abort(getCommands());
- return;
+ if (isAtomic()) {
+ ReceiveCommand.abort(getCommands());
+ return;
+ } else {
+ continue;
+ }
}
}
todo.add(new Command(rw, c));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
index d7e930831e..35cadd3c97 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
@@ -89,6 +89,9 @@ public class BatchRefUpdate {
/** Push certificate associated with this update. */
private PushCertificate pushCert;
+ /** Whether updates should be atomic. */
+ private boolean atomic;
+
/**
* Initialize a new batch update.
*
@@ -98,6 +101,7 @@ public class BatchRefUpdate {
protected BatchRefUpdate(RefDatabase refdb) {
this.refdb = refdb;
this.commands = new ArrayList<ReceiveCommand>();
+ this.atomic = refdb.performsAtomicTransactions();
}
/**
@@ -200,6 +204,36 @@ public class BatchRefUpdate {
}
/**
+ * Request that all updates in this batch be performed atomically.
+ * <p>
+ * When atomic updates are used, either all commands apply successfully, or
+ * none do. Commands that might have otherwise succeeded are rejected with
+ * {@code REJECTED_OTHER_REASON}.
+ * <p>
+ * This method only works if the underlying ref database supports atomic
+ * transactions, i.e. {@link RefDatabase#performsAtomicTransactions()} returns
+ * true. Calling this method with true if the underlying ref database does not
+ * support atomic transactions will cause all commands to fail with {@code
+ * REJECTED_OTHER_REASON}.
+ *
+ * @param atomic whether updates should be atomic.
+ * @return {@code this}
+ * @since 4.4
+ */
+ public BatchRefUpdate setAtomic(boolean atomic) {
+ this.atomic = atomic;
+ return this;
+ }
+
+ /**
+ * @return atomic whether updates should be atomic.
+ * @since 4.4
+ */
+ public boolean isAtomic() {
+ return atomic;
+ }
+
+ /**
* Set a push certificate associated with this update.
* <p>
* This usually includes commands to update the refs in this batch, but is not
@@ -271,6 +305,10 @@ public class BatchRefUpdate {
* <p>
* The default implementation of this method performs a sequential reference
* update over each reference.
+ * <p>
+ * Implementations must respect the atomicity requirements of the underlying
+ * database as described in {@link #setAtomic(boolean)} and {@link
+ * RefDatabase#performsAtomicTransactions()}.
*
* @param walk
* a RevWalk to parse tags in case the storage system wants to
@@ -284,6 +322,17 @@ public class BatchRefUpdate {
*/
public void execute(RevWalk walk, ProgressMonitor monitor)
throws IOException {
+
+ if (atomic && !refdb.performsAtomicTransactions()) {
+ for (ReceiveCommand c : commands) {
+ if (c.getResult() == NOT_ATTEMPTED) {
+ c.setResult(REJECTED_OTHER_REASON,
+ JGitText.get().atomicRefUpdatesNotSupported);
+ }
+ }
+ return;
+ }
+
monitor.beginTask(JGitText.get().updatingReferences, commands.size());
List<ReceiveCommand> commands2 = new ArrayList<ReceiveCommand>(
commands.size());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
index c0c3862c8b..517c8aa538 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -207,8 +207,25 @@ public abstract class RefDatabase {
}
/**
- * @return if the database performs {@code newBatchUpdate()} as an atomic
- * transaction.
+ * Whether the database is capable of performing batch updates as atomic
+ * transactions.
+ * <p>
+ * If true, by default {@link BatchRefUpdate} instances will perform updates
+ * atomically, meaning either all updates will succeed, or all updates will
+ * fail. It is still possible to turn off this behavior on a per-batch basis
+ * by calling {@code update.setAtomic(false)}.
+ * <p>
+ * If false, {@link BatchRefUpdate} instances will never perform updates
+ * atomically, and calling {@code update.setAtomic(true)} will cause the
+ * entire batch to fail with {@code REJECTED_OTHER_REASON}.
+ * <p>
+ * This definition of atomicity is stronger than what is provided by
+ * {@link org.eclipse.jgit.transport.ReceivePack}. {@code ReceivePack} will
+ * attempt to reject all commands if it knows in advance some commands may
+ * fail, even if the storage layer does not support atomic transactions. Here,
+ * atomicity applies even in the case of unforeseeable errors.
+ *
+ * @return whether transactions are atomic by default.
* @since 3.6
*/
public boolean performsAtomicTransactions() {