Merge "Treat NoteDb LOCK_FAILURE as HTTP 409"
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
index 9504564..b7bcafa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
@@ -38,6 +38,7 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.InMemoryInserter;
import com.google.gerrit.server.git.InsertedObject;
+import com.google.gerrit.server.git.LockFailureException;
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
import com.google.gerrit.server.update.ChainedReceiveCommands;
import com.google.gwtorm.server.OrmConcurrencyException;
@@ -476,11 +477,18 @@
or.cmds.addTo(bru);
bru.setAllowNonFastForwards(true);
bru.execute(or.rw, NullProgressMonitor.INSTANCE);
+
+ boolean lockFailure = false;
for (ReceiveCommand cmd : bru.getCommands()) {
- if (cmd.getResult() != ReceiveCommand.Result.OK) {
+ if (cmd.getResult() == ReceiveCommand.Result.LOCK_FAILURE) {
+ lockFailure = true;
+ } else if (cmd.getResult() != ReceiveCommand.Result.OK) {
throw new IOException("Update failed: " + bru);
}
}
+ if (lockFailure) {
+ throw new LockFailureException("Update failed with one or more lock failures: " + bru);
+ }
}
private void addCommands() throws OrmException, IOException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
index d05f32e..37a25af 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
@@ -49,6 +49,7 @@
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.InsertedObject;
+import com.google.gerrit.server.git.LockFailureException;
import com.google.gerrit.server.index.change.ChangeIndexer;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
@@ -560,7 +561,8 @@
}
}
- private void executeNoteDbUpdates(List<ChangeTask> tasks) throws IOException {
+ private void executeNoteDbUpdates(List<ChangeTask> tasks)
+ throws ResourceConflictException, IOException {
// Aggregate together all NoteDb ref updates from the ops we executed,
// possibly in parallel. Each task had its own NoteDbUpdateManager instance
// with its own thread-local copy of the repo(s), but each of those was just
@@ -623,18 +625,21 @@
}
} catch (IOException e) {
if (tasks.stream().allMatch(t -> t.storage == PrimaryStorage.REVIEW_DB)) {
- // Ignore all errors trying to update NoteDb at this point. We've
- // already written the NoteDbChangeStates to ReviewDb, which means
- // if any state is out of date it will be rebuilt the next time it
- // is needed.
+ // Ignore all errors trying to update NoteDb at this point. We've already written the
+ // NoteDbChangeStates to ReviewDb, which means if any state is out of date it will be
+ // rebuilt the next time it is needed.
+ //
// Always log even without RequestId.
log.debug("Ignoring NoteDb update error after ReviewDb write", e);
- } else {
- // We can't prove it's safe to ignore the error, either because some
- // change had NOTE_DB primary, or a task failed before determining the
- // primary storage.
- throw e;
+
+ // Otherwise, we can't prove it's safe to ignore the error, either because some change had
+ // NOTE_DB primary, or a task failed before determining the primary storage.
+ } else if (e instanceof LockFailureException) {
+ // LOCK_FAILURE is a special case indicating there was a conflicting write to a meta ref,
+ // although it happened too late for us to produce anything but a generic error message.
+ throw new ResourceConflictException("Updating change failed due to conflicting write", e);
}
+ throw e;
}
}