Count lock-failures when updating the superproject

If the repository changed while the commit is being prepared, the update
fails with a "lock failure". Supermanifest doesn't retry it, so we only
know about it when a user reports missing submodules.

Add a metric to see how frequently this happens.

Change-Id: I12caf237388e606745a530ad4ca8f7742ce4ef6a
diff --git a/java/com/googlesource/gerrit/plugins/supermanifest/SuperManifestRefUpdatedListener.java b/java/com/googlesource/gerrit/plugins/supermanifest/SuperManifestRefUpdatedListener.java
index 84e7831..c876d4a 100644
--- a/java/com/googlesource/gerrit/plugins/supermanifest/SuperManifestRefUpdatedListener.java
+++ b/java/com/googlesource/gerrit/plugins/supermanifest/SuperManifestRefUpdatedListener.java
@@ -29,12 +29,17 @@
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.logging.PluginMetadata;
 import com.google.gerrit.server.permissions.GlobalPermission;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -56,6 +61,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.RefNotFoundException;
 import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -92,10 +98,34 @@
   private final Provider<IdentifiedUser> identifiedUser;
   private final PermissionBackend permissionBackend;
   private final PluginMapContext<DownloadScheme> downloadScheme;
+  private final SupermanifestMetrics metrics;
 
   // Mutable.
   private Set<ConfigEntry> config;
 
+  @Singleton
+  private static class SupermanifestMetrics {
+    final Counter1<String> manifestUpdateResultCounter;
+
+    @Inject
+    SupermanifestMetrics(MetricMaker metrics) {
+      manifestUpdateResultCounter =
+          metrics.newCounter(
+              "supermanifest/update_result",
+              new Description(
+                  "Result of a manifest update for a specific conf (all conf parsed fine)"),
+              Field.ofString(
+                      "result",
+                      (metadataBuilder, fieldValue) ->
+                          metadataBuilder
+                              .pluginName("supermanifest")
+                              .addPluginMetadata(
+                                  PluginMetadata.create("update_result", fieldValue)))
+                  .description("result of a manifest update")
+                  .build());
+    }
+  }
+
   @Inject
   SuperManifestRefUpdatedListener(
       AllProjectsName allProjectsName,
@@ -107,7 +137,8 @@
       @GerritPersonIdent Provider<PersonIdent> serverIdent,
       SuperManifestRepoManager.Factory repoManagerFactory,
       Provider<IdentifiedUser> identifiedUser,
-      PermissionBackend permissionBackend) {
+      PermissionBackend permissionBackend,
+      SupermanifestMetrics metrics) {
 
     this.pluginName = pluginName;
     this.serverIdent = serverIdent;
@@ -124,6 +155,7 @@
     this.projectCache = projectCache;
     this.identifiedUser = identifiedUser;
     this.permissionBackend = permissionBackend;
+    this.metrics = metrics;
   }
 
   @FormatMethod
@@ -334,9 +366,16 @@
         throw new ConfigInvalidException(
             String.format("invalid toolType: %s", c.getToolType().name()));
     }
+
+    String status = "NOT_ATTEMPTED";
     try (GerritRemoteReader reader =
         new GerritRemoteReader(repoManagerFactory.create(c), canonicalWebUrl.toString())) {
       subModuleUpdater.update(reader, c, refName);
+      status = "OK";
+    } catch (ConcurrentRefUpdateException e) {
+      status = "LOCK_FAILURE";
+    } finally {
+      metrics.manifestUpdateResultCounter.increment(status);
     }
   }