Browse Source

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>
stable-3.6
Stefan Beller 10 years ago
parent
commit
88c1b82e7a
  1. 1
      org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
  2. 1
      org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
  3. 8
      org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
  4. 20
      org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
  5. 8
      org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
  6. 7
      org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java

1
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}

1
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;

8
org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java

@ -196,6 +196,14 @@ public abstract class RefDatabase {
return new BatchRefUpdate(this);
}
/**
* @return if the database performs {@code newBatchUpdate()} as an atomic
* transaction.
*/
public boolean performsAtomicTransactions() {
return false;
}
/**
* Read a single reference.
* <p>

20
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.
*

8
org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java

@ -129,6 +129,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.
*

7
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();

Loading…
Cancel
Save