Add connectivity check from references

Make sure all objects referenced by references are reachable. Stop at
the first missing object.

Change-Id: Ifcd7392c4321b17d9290bd87f038bc62bc10dabb
Signed-off-by: Zhen Chen <czhen@google.com>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
index 3fa3952..8d223c8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java
@@ -198,4 +198,46 @@
 			}
 		}
 	}
+
+	@Test
+	public void testValidConnectivity() throws Exception {
+		ObjectId blobId = ins
+				.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
+
+		byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH];
+		blobId.copyRawTo(blobIdBytes, 0);
+		byte[] data = concat(encodeASCII("100644 regular-file\0"), blobIdBytes);
+		ObjectId treeId = ins.insert(Constants.OBJ_TREE, data);
+		ins.flush();
+
+		RevCommit commit = git.commit().message("0").setTopLevelTree(treeId)
+				.create();
+
+		git.update("master", commit);
+
+		DfsFsck fsck = new DfsFsck(repo);
+		FsckError errors = fsck.check(null);
+		assertEquals(errors.getMissingObjects().size(), 0);
+	}
+
+	@Test
+	public void testMissingObject() throws Exception {
+		ObjectId blobId = ObjectId
+				.fromString("19102815663d23f8b75a47e7a01965dcdc96468c");
+		byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH];
+		blobId.copyRawTo(blobIdBytes, 0);
+		byte[] data = concat(encodeASCII("100644 regular-file\0"), blobIdBytes);
+		ObjectId treeId = ins.insert(Constants.OBJ_TREE, data);
+		ins.flush();
+
+		RevCommit commit = git.commit().message("0").setTopLevelTree(treeId)
+				.create();
+
+		git.update("master", commit);
+
+		DfsFsck fsck = new DfsFsck(repo);
+		FsckError errors = fsck.check(null);
+		assertEquals(errors.getMissingObjects().size(), 1);
+		assertEquals(errors.getMissingObjects().iterator().next(), blobId);
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
index 1cc475a..9549dbb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsFsck.java
@@ -54,6 +54,9 @@
 import org.eclipse.jgit.internal.storage.pack.PackExt;
 import org.eclipse.jgit.lib.ObjectChecker;
 import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.revwalk.ObjectWalk;
+import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.transport.PackedObjectInfo;
 
 /** Verify the validity and connectivity of a DFS repository. */
@@ -115,6 +118,19 @@
 							e.getErrorType()));
 				}
 			}
+
+			try (ObjectWalk ow = new ObjectWalk(ctx)) {
+				for (Ref r : repo.getAllRefs().values()) {
+					try {
+						RevObject tip = ow.parseAny(r.getObjectId());
+						ow.markStart(tip);
+						ow.checkConnectivity();
+						ow.markUninteresting(tip);
+					} catch (MissingObjectException e) {
+						errors.getMissingObjects().add(e.getObjectId());
+					}
+				}
+			}
 		} finally {
 			ctx.close();
 		}