Merge "Merge branch 'stable-3.6' into stable-3.7" into stable-3.7
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index c959a07..b92a89d 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -58,9 +58,6 @@
 link:cmd-ban-commit.html[gerrit ban-commit]::
 	Bans a commit from a project's repository.
 
-link:cmd-copy-approvals.html[gerrit copy-approvals]::
-	Copy all inferred approvals labels to the latest patch-set.
-
 link:cmd-check-project-access.html[gerrit check-project-access]::
 	Check if user(s) can read non-config refs of a project
 
diff --git a/java/com/google/gerrit/index/Schema.java b/java/com/google/gerrit/index/Schema.java
index 403be35..dda9ce5 100644
--- a/java/com/google/gerrit/index/Schema.java
+++ b/java/com/google/gerrit/index/Schema.java
@@ -296,22 +296,19 @@
   /**
    * Build all fields in the schema from an input object.
    *
-   * <p>Null values are omitted, as are fields which cause errors, which are logged.
+   * <p>Null values are omitted, as are fields which cause errors, which are logged. If any of the
+   * fields cause a StorageException, the whole operation fails and the exception is propagated to
+   * the caller.
    *
    * @param obj input object.
    * @param skipFields set of field names to skip when indexing the document
    * @return all non-null field values from the object.
    */
   public final Iterable<Values<T>> buildFields(T obj, ImmutableSet<String> skipFields) {
-    try {
-      return schemaFields.values().stream()
-          .map(f -> fieldValues(obj, f, skipFields))
-          .filter(Objects::nonNull)
-          .collect(toImmutableList());
-
-    } catch (StorageException e) {
-      return ImmutableList.of();
-    }
+    return schemaFields.values().stream()
+        .map(f -> fieldValues(obj, f, skipFields))
+        .filter(Objects::nonNull)
+        .collect(toImmutableList());
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/account/GroupCacheImpl.java b/java/com/google/gerrit/server/account/GroupCacheImpl.java
index eaec9ba..36f725f 100644
--- a/java/com/google/gerrit/server/account/GroupCacheImpl.java
+++ b/java/com/google/gerrit/server/account/GroupCacheImpl.java
@@ -283,7 +283,7 @@
       List<Cache.GroupKeyProto> keyList = new ArrayList<>();
       try (TraceTimer ignored =
               TraceContext.newTimer(
-                  "Loading group from serialized cache",
+                  "Building keys to load group(s) from serialized cache",
                   Metadata.builder().cacheName(BYUUID_NAME_PERSISTED).build());
           Repository allUsers = repoManager.openRepository(allUsersName)) {
         while (uuidIterator.hasNext()) {
@@ -302,8 +302,13 @@
           keyList.add(key);
         }
       }
-      persistedCache.getAll(keyList).entrySet().stream()
-          .forEach(g -> toReturn.put(g.getKey().getUuid(), Optional.of(g.getValue())));
+      try (TraceTimer ignored =
+          TraceContext.newTimer(
+              "Loading group(s) from serialized cache",
+              Metadata.builder().cacheName(BYUUID_NAME_PERSISTED).build())) {
+        persistedCache.getAll(keyList).entrySet().stream()
+            .forEach(g -> toReturn.put(g.getKey().getUuid(), Optional.of(g.getValue())));
+      }
       return toReturn;
     }
   }
diff --git a/java/com/google/gerrit/server/cache/CacheInfo.java b/java/com/google/gerrit/server/cache/CacheInfo.java
index d6eb065..832ca04 100644
--- a/java/com/google/gerrit/server/cache/CacheInfo.java
+++ b/java/com/google/gerrit/server/cache/CacheInfo.java
@@ -90,7 +90,7 @@
       space = bytes(value);
     }
 
-    private static String bytes(double value) {
+    public static String bytes(double value) {
       value /= 1024;
       String suffix = "k";
 
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java b/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
index 7db4443..cc26178 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
@@ -28,6 +28,7 @@
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.server.cache.CacheInfo;
 import com.google.gerrit.server.cache.PersistentCache;
 import com.google.gerrit.server.cache.serialize.CacheSerializer;
 import com.google.gerrit.server.logging.Metadata;
@@ -660,12 +661,19 @@
           try (ResultSet r = s.executeQuery("SELECT SUM(space) FROM data")) {
             used = r.next() ? r.getLong(1) : 0;
           }
+          String formattedMaxSize = CacheInfo.EntriesInfo.bytes(maxSize);
           if (used <= maxSize) {
+            logger.atInfo().log(
+                "Cache %s size (%s) is less than maxSize (%s), not pruning",
+                url, CacheInfo.EntriesInfo.bytes(used), formattedMaxSize);
             return;
           }
 
           try (ResultSet r =
               s.executeQuery("SELECT k, space, created FROM data ORDER BY accessed")) {
+            logger.atInfo().log(
+                "Cache %s size (%s) is greater than maxSize (%s), pruning",
+                url, CacheInfo.EntriesInfo.bytes(used), formattedMaxSize);
             while (maxSize < used && r.next()) {
               K key = keyType.get(r, 1);
               Timestamp created = r.getTimestamp(3);
@@ -676,6 +684,9 @@
                 used -= r.getLong(2);
               }
             }
+            logger.atInfo().log(
+                "Done pruning cache %s, size (%s) is now less than maxSize (%s)",
+                url, CacheInfo.EntriesInfo.bytes(used), formattedMaxSize);
           }
         }
       } catch (IOException | SQLException e) {
diff --git a/java/com/google/gerrit/server/git/MergeUtil.java b/java/com/google/gerrit/server/git/MergeUtil.java
index ae247ad..5186cf6 100644
--- a/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/java/com/google/gerrit/server/git/MergeUtil.java
@@ -673,6 +673,10 @@
       return false;
     }
 
+    return canMerge(mergeTip, repo, toMerge);
+  }
+
+  private boolean canMerge(CodeReviewCommit mergeTip, Repository repo, CodeReviewCommit toMerge) {
     try (ObjectInserter ins = new InMemoryInserter(repo)) {
       return newThreeWayMerger(ins, repo.getConfig()).merge(mergeTip, toMerge);
     } catch (LargeObjectException e) {
@@ -694,6 +698,11 @@
       return false;
     }
 
+    return canFastForward(mergeTip, rw, toMerge);
+  }
+
+  private boolean canFastForward(
+      CodeReviewCommit mergeTip, CodeReviewRevWalk rw, CodeReviewCommit toMerge) {
     try {
       return mergeTip == null
           || rw.isMergedInto(mergeTip, toMerge)
@@ -703,6 +712,19 @@
     }
   }
 
+  public boolean canFastForwardOrMerge(
+      MergeSorter mergeSorter,
+      CodeReviewCommit mergeTip,
+      CodeReviewRevWalk rw,
+      Repository repo,
+      CodeReviewCommit toMerge) {
+    if (hasMissingDependencies(mergeSorter, toMerge)) {
+      return false;
+    }
+
+    return canFastForward(mergeTip, rw, toMerge) || canMerge(mergeTip, repo, toMerge);
+  }
+
   public boolean canCherryPick(
       MergeSorter mergeSorter,
       Repository repo,
@@ -745,8 +767,7 @@
     // by an equivalent merge with a different first parent. So
     // instead behave as though MERGE_IF_NECESSARY was configured.
     //
-    return canFastForward(mergeSorter, mergeTip, rw, toMerge)
-        || canMerge(mergeSorter, repo, mergeTip, toMerge);
+    return canFastForwardOrMerge(mergeSorter, mergeTip, rw, repo, toMerge);
   }
 
   public boolean hasMissingDependencies(MergeSorter mergeSorter, CodeReviewCommit toMerge) {
diff --git a/java/com/google/gerrit/server/submit/MergeIfNecessary.java b/java/com/google/gerrit/server/submit/MergeIfNecessary.java
index 75136f5..b8417b8 100644
--- a/java/com/google/gerrit/server/submit/MergeIfNecessary.java
+++ b/java/com/google/gerrit/server/submit/MergeIfNecessary.java
@@ -49,7 +49,7 @@
 
   static boolean dryRun(
       SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge) {
-    return args.mergeUtil.canFastForward(args.mergeSorter, mergeTip, args.rw, toMerge)
-        || args.mergeUtil.canMerge(args.mergeSorter, args.repo, mergeTip, toMerge);
+    return args.mergeUtil.canFastForwardOrMerge(
+        args.mergeSorter, mergeTip, args.rw, args.repo, toMerge);
   }
 }