LockFailureException: Expose ref names

Change-Id: I0bc3c077fe8e0a05e5b36987c959193058ce363e
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsUpdate.java
index 00dc05a5..db37147 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsUpdate.java
@@ -840,7 +840,7 @@
       case FORCED:
         break;
       case LOCK_FAILURE:
-        throw new LockFailureException("Updating external IDs failed with " + res);
+        throw new LockFailureException("Updating external IDs failed with " + res, u);
       case IO_FAILURE:
       case NOT_ATTEMPTED:
       case REJECTED:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LockFailureException.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LockFailureException.java
index 7380b0a..02a30e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LockFailureException.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LockFailureException.java
@@ -14,13 +14,38 @@
 
 package com.google.gerrit.server.git;
 
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
+import com.google.common.collect.ImmutableList;
 import java.io.IOException;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.transport.ReceiveCommand;
 
 /** Thrown when updating a ref in Git fails with LOCK_FAILURE. */
 public class LockFailureException extends IOException {
   private static final long serialVersionUID = 1L;
 
-  public LockFailureException(String message) {
+  private final ImmutableList<String> refs;
+
+  public LockFailureException(String message, RefUpdate refUpdate) {
     super(message);
+    refs = ImmutableList.of(refUpdate.getName());
+  }
+
+  public LockFailureException(String message, BatchRefUpdate batchRefUpdate) {
+    super(message);
+    refs =
+        batchRefUpdate
+            .getCommands()
+            .stream()
+            .filter(c -> c.getResult() == ReceiveCommand.Result.LOCK_FAILURE)
+            .map(ReceiveCommand::getRefName)
+            .collect(toImmutableList());
+  }
+
+  /** Subset of ref names that caused the lock failure. */
+  public ImmutableList<String> getFailedRefs() {
+    return refs;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
index 1bf3586..92edc47 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
@@ -395,7 +395,8 @@
                     + " in "
                     + db.getDirectory()
                     + ": "
-                    + ru.getResult());
+                    + ru.getResult(),
+                ru);
           case FORCED:
           case IO_FAILURE:
           case NOT_ATTEMPTED:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/update/RefUpdateUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/update/RefUpdateUtil.java
index ab0b78e..86b4eef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/update/RefUpdateUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/update/RefUpdateUtil.java
@@ -74,7 +74,7 @@
     }
 
     if (lockFailure + aborted == bru.getCommands().size()) {
-      throw new LockFailureException("Update aborted with one or more lock failures: " + bru);
+      throw new LockFailureException("Update aborted with one or more lock failures: " + bru, bru);
     } else if (failure > 0) {
       throw new IOException("Update failed: " + bru);
     }