diff options
Diffstat (limited to 'org.eclipse.jgit')
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() { |