aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorStefan Beller <sbeller@google.com>2014-11-07 18:51:18 -0800
committerStefan Beller <sbeller@google.com>2014-11-07 18:51:18 -0800
commit88c1b82e7a27a5e25c9be9cba246f076825da4c6 (patch)
treea6d0ffad3c3ea0c5b19cfe77fb0e20fd117c4d44 /org.eclipse.jgit
parent2532c28cb93ccb8e674ef374f08fb3bf246c353b (diff)
downloadjgit-88c1b82e7a27a5e25c9be9cba246f076825da4c6.tar.gz
jgit-88c1b82e7a27a5e25c9be9cba246f076825da4c6.zip
Implement atomic refs update, if possible by database
Inspired by the series[1], this implements the possibility to have atomic ref transactions. If the database supports atomic ref update capabilities, we'll advertise these. If the client wishes to use this feature, either all refs will be updated or none at all. [1] http://thread.gmane.org/gmane.comp.version-control.git/259019/focus=259024 Change-Id: I7b5d19c21f3b5557e41b9bcb5d359a65ff1a493d Signed-off-by: Stefan Beller <sbeller@google.com>
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/lib/RefDatabase.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java20
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java7
6 files changed, 45 insertions, 0 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 45021e847c..524aa3e6ac 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -500,6 +500,7 @@ tagOnRepoWithoutHEADCurrentlyNotSupported=Tag on repository without HEAD current
theFactoryMustNotBeNull=The factory must not be null
timerAlreadyTerminated=Timer already terminated
topologicalSortRequired=Topological sort required.
+transactionAborted=transaction aborted
transportExceptionBadRef=Empty ref: {0}: {1}
transportExceptionEmptyRef=Empty ref: {0}
transportExceptionInvalid=Invalid {0} {1}:{2}
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 f2a1b948cc..dd1be0d5f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -556,6 +556,7 @@ public class JGitText extends TranslationBundle {
/***/ public String tagAlreadyExists;
/***/ public String tagNameInvalid;
/***/ public String tagOnRepoWithoutHEADCurrentlyNotSupported;
+ /***/ public String transactionAborted;
/***/ public String theFactoryMustNotBeNull;
/***/ public String timerAlreadyTerminated;
/***/ public String topologicalSortRequired;
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 682cac162c..0458ac4911 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -197,6 +197,14 @@ public abstract class RefDatabase {
}
/**
+ * @return if the database performs {@code newBatchUpdate()} as an atomic
+ * transaction.
+ */
+ public boolean performsAtomicTransactions() {
+ return false;
+ }
+
+ /**
* Read a single reference.
* <p>
* Aside from taking advantage of {@link #SEARCH_PATH}, this method may be
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
index 72c1697593..475ba35283 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
@@ -908,6 +909,8 @@ public abstract class BaseReceivePack {
adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
adv.advertiseCapability(CAPABILITY_DELETE_REFS);
adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
+ if (db.getRefDatabase().performsAtomicTransactions())
+ adv.advertiseCapability(CAPABILITY_ATOMIC);
if (allowOfsDelta)
adv.advertiseCapability(CAPABILITY_OFS_DELTA);
adv.send(getAdvertisedOrDefaultRefs());
@@ -1251,6 +1254,23 @@ public abstract class BaseReceivePack {
}
}
+ /** @return if any commands have been rejected so far. */
+ protected boolean anyRejects() {
+ for (ReceiveCommand cmd : commands) {
+ if (cmd.getResult() != Result.NOT_ATTEMPTED && cmd.getResult() != Result.OK)
+ return true;
+ }
+ return false;
+ }
+
+ /** Set the result to fail for any command that was not processed yet. */
+ protected void failPendingCommands() {
+ for (ReceiveCommand cmd : commands) {
+ if (cmd.getResult() == Result.NOT_ATTEMPTED)
+ cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().transactionAborted);
+ }
+ }
+
/**
* Filter the list of commands according to result.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index c0a70d0437..43fd07944c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -130,6 +130,14 @@ public class GitProtocolConstants {
public static final String OPTION_ALLOW_TIP_SHA1_IN_WANT = "allow-tip-sha1-in-want"; //$NON-NLS-1$
/**
+ * The client supports atomic pushes. If this option is used, the server
+ * will update all refs within one atomic transaction.
+ *
+ * @since 3.6
+ */
+ public static final String CAPABILITY_ATOMIC = "atomic-push"; //$NON-NLS-1$
+
+ /**
* The client expects a status report after the server processes the pack.
*
* @since 3.2
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 4d931dd5df..e5eb822418 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
import java.io.IOException;
@@ -199,8 +200,14 @@ public class ReceivePack extends BaseReceivePack {
}
if (unpackError == null) {
+ boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC);
validateCommands();
+ if (atomic && anyRejects())
+ failPendingCommands();
+
preReceive.onPreReceive(this, filterCommands(Result.NOT_ATTEMPTED));
+ if (atomic && anyRejects())
+ failPendingCommands();
executeCommands();
}
unlockPack();