Merge branch 'stable-3.5' into stable-3.6 * stable-3.5: Roll back batch ref updates on uncaught throwables Change-Id: I897eb21e40786513d3fbc97103f8f29987435f3b
diff --git a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java index f461a9a..1e45951 100644 --- a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java +++ b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java
@@ -157,14 +157,21 @@ try (CloseableSet<AutoCloseable> locks = new CloseableSet<>()) { final List<RefPair> finalRefsToUpdate = compareAndGetLatestLocalRefs(refsToUpdate, locks); delegateUpdate.invoke(); + boolean sharedDbUpdateSucceeded = false; try { updateSharedRefDb(batchRefUpdate.getCommands().stream(), finalRefsToUpdate); + sharedDbUpdateSucceeded = true; } catch (Exception e) { - List<ReceiveCommand> receiveCommands = batchRefUpdate.getCommands(); logger.atWarning().withCause(e).log( - "Batch ref-update failing because of failure during the global refdb update. Set all commands Result to LOCK_FAILURE [%d]", - receiveCommands.size()); - rollback(delegateUpdateRollback, finalRefsToUpdate, receiveCommands); + "Batch ref-update failed because of failure during the global refdb update."); + } finally { + if (!sharedDbUpdateSucceeded) { + List<ReceiveCommand> receiveCommands = batchRefUpdate.getCommands(); + logger.atWarning().log( + "Batch ref-update failed, set all commands Result to LOCK_FAILURE [%d]", + commands.size()); + rollback(delegateUpdateRollback, finalRefsToUpdate, receiveCommands); + } } } catch (OutOfSyncException e) { List<ReceiveCommand> receiveCommands = batchRefUpdate.getCommands();
diff --git a/src/test/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidatorTest.java b/src/test/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidatorTest.java index 2c4a1ea..e5d3409 100644 --- a/src/test/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidatorTest.java +++ b/src/test/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidatorTest.java
@@ -15,11 +15,13 @@ package com.gerritforge.gerrit.globalrefdb.validation; import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static java.util.Collections.singletonList; import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -180,6 +182,35 @@ } @Test + public void shouldRollbackWhenSharedRefUpdateCompareAndPutThrowsUncaughtThrowable() + throws Exception { + String REF_NAME = "refs/changes/01/1/meta"; + BatchRefUpdate batchRefUpdate = + newBatchUpdate(singletonList(new ReceiveCommand(A, B, REF_NAME, UPDATE))); + BatchRefUpdateValidator batchRefUpdateValidator = + getRefValidatorForEnforcement(A_TEST_PROJECT_NAME, tmpRefEnforcement); + + doReturn(SharedRefEnforcement.EnforcePolicy.REQUIRED) + .when(batchRefUpdateValidator.refEnforcement) + .getPolicy(A_TEST_PROJECT_NAME, REF_NAME); + doReturn(true).when(sharedRefDatabase).isUpToDate(any(), any()); + + doThrow(TestError.class).when(sharedRefDatabase).compareAndPut(any(), any(), any()); + + assertThrows( + TestError.class, + () -> + batchRefUpdateValidator.executeBatchUpdateWithValidation( + batchRefUpdate, () -> execute(batchRefUpdate), rollbackFunction)); + + verify(rollbackFunction).invoke(any()); + List<ReceiveCommand> commands = batchRefUpdate.getCommands(); + assertThat(commands.size()).isEqualTo(1); + commands.forEach( + (command) -> assertThat(command.getResult()).isEqualTo(ReceiveCommand.Result.LOCK_FAILURE)); + } + + @Test public void shouldRollbackRefUpdateWhenRefDbIsNotUpdated() throws Exception { String REF_NAME = "refs/changes/01/1/meta"; BatchRefUpdate batchRefUpdate = @@ -266,4 +297,6 @@ public String testBranch() { return "branch_" + nameRule.getMethodName(); } + + private static class TestError extends Error {} }