Log the reason why a ref object wasn't loaded by RevisionReader

It may happen that one ref cannot be read in memory for being used
in an ApplyObject REST-API. Add more logging on the reason behind
the failure to read all the objects pointed to a ref, so that the
Gerrit admin can take the appropriate actions to allow the replication
shortcut and avoid a full git fetch.

Change-Id: I7dbaa7b6ed35c389c7e2477467829d85dfc542e8
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java
index 92cbd95..eedd9eb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java
@@ -81,7 +81,7 @@
 
       ObjectLoader commitLoader = git.open(objectId);
       totalRefSize += commitLoader.getSize();
-      verifySize(totalRefSize, commitLoader);
+      verifySize(project, refName, objectId, totalRefSize, commitLoader);
 
       if (commitLoader.getType() == Constants.OBJ_BLOB) {
         return Optional.of(
@@ -108,7 +108,7 @@
       RevTree tree = commit.getTree();
       ObjectLoader treeLoader = git.open(commit.getTree().toObjectId());
       totalRefSize += treeLoader.getSize();
-      verifySize(totalRefSize, treeLoader);
+      verifySize(project, refName, commit.getTree().toObjectId(), totalRefSize, treeLoader);
 
       RevisionObjectData treeRev =
           new RevisionObjectData(tree.getType(), treeLoader.getCachedBytes());
@@ -117,11 +117,11 @@
       try (TreeWalk walk = new TreeWalk(git)) {
         if (commit.getParentCount() > 0) {
           List<DiffEntry> diffEntries = readDiffs(git, commit, tree, walk);
-          blobs = readBlobs(git, totalRefSize, diffEntries);
+          blobs = readBlobs(project, refName, git, totalRefSize, diffEntries);
         } else {
           walk.setRecursive(true);
           walk.addTree(tree);
-          blobs = readBlobs(git, totalRefSize, walk);
+          blobs = readBlobs(project, refName, git, totalRefSize, walk);
         }
       }
       return Optional.of(new RevisionData(commitRev, treeRev, blobs));
@@ -143,7 +143,8 @@
     return DiffEntry.scan(walk, true);
   }
 
-  private List<RevisionObjectData> readBlobs(Repository git, Long totalRefSize, TreeWalk walk)
+  private List<RevisionObjectData> readBlobs(
+      Project.NameKey projectName, String refName, Repository git, Long totalRefSize, TreeWalk walk)
       throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException,
           IOException {
     List<RevisionObjectData> blobs = Lists.newLinkedList();
@@ -151,7 +152,7 @@
       ObjectId objectId = walk.getObjectId(0);
       ObjectLoader objectLoader = git.open(objectId);
       totalRefSize += objectLoader.getSize();
-      verifySize(totalRefSize, objectLoader);
+      verifySize(projectName, refName, objectId, totalRefSize, objectLoader);
 
       RevisionObjectData rev =
           new RevisionObjectData(objectLoader.getType(), objectLoader.getCachedBytes());
@@ -161,14 +162,19 @@
   }
 
   private List<RevisionObjectData> readBlobs(
-      Repository git, Long totalRefSize, List<DiffEntry> diffEntries)
+      Project.NameKey projectName,
+      String refName,
+      Repository git,
+      Long totalRefSize,
+      List<DiffEntry> diffEntries)
       throws MissingObjectException, IOException {
     List<RevisionObjectData> blobs = Lists.newLinkedList();
     for (DiffEntry diffEntry : diffEntries) {
       if (!ChangeType.DELETE.equals(diffEntry.getChangeType())) {
         ObjectLoader objectLoader = git.open(diffEntry.getNewId().toObjectId());
         totalRefSize += objectLoader.getSize();
-        verifySize(totalRefSize, objectLoader);
+        verifySize(
+            projectName, refName, diffEntry.getNewId().toObjectId(), totalRefSize, objectLoader);
         RevisionObjectData rev =
             new RevisionObjectData(objectLoader.getType(), objectLoader.getCachedBytes());
         blobs.add(rev);
@@ -185,9 +191,44 @@
     return parentCommit.getTree();
   }
 
-  private void verifySize(Long totalRefSize, ObjectLoader loader) throws LargeObjectException {
-    if (loader.isLarge() || totalRefSize > maxRefSize) {
-      throw new LargeObjectException();
+  private void verifySize(
+      Project.NameKey projectName,
+      String refName,
+      ObjectId objectId,
+      Long totalRefSize,
+      ObjectLoader loader)
+      throws LargeObjectException {
+    if (loader.isLarge()) {
+      repLog.warn(
+          "Objects associated with {}:{} ({}) are too big to fit into the object loader's memory",
+          projectName,
+          refName,
+          objectTypeToString(loader.getType()));
+      throw new LargeObjectException(objectId);
+    }
+
+    if (totalRefSize > maxRefSize) {
+      repLog.warn(
+          "Objects associated with {}:{} ({}) use {} bytes, over the maximum limit of {} bytes",
+          projectName,
+          refName,
+          objectTypeToString(loader.getType()),
+          totalRefSize,
+          maxRefSize);
+      throw new LargeObjectException(objectId);
+    }
+  }
+
+  private static String objectTypeToString(int type) {
+    switch (type) {
+      case Constants.OBJ_BLOB:
+        return "BLOB";
+      case Constants.OBJ_COMMIT:
+        return "COMMIT";
+      case Constants.OBJ_TREE:
+        return "TREE";
+      default:
+        return "type:" + type;
     }
   }
 }