You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FullConnectivityChecker.java 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Copyright (c) 2019, Google LLC and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * http://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.transport.connectivity;
  11. import java.io.IOException;
  12. import java.util.Set;
  13. import org.eclipse.jgit.errors.MissingObjectException;
  14. import org.eclipse.jgit.internal.JGitText;
  15. import org.eclipse.jgit.lib.Constants;
  16. import org.eclipse.jgit.lib.ObjectId;
  17. import org.eclipse.jgit.lib.ObjectIdSubclassMap;
  18. import org.eclipse.jgit.lib.ProgressMonitor;
  19. import org.eclipse.jgit.revwalk.ObjectWalk;
  20. import org.eclipse.jgit.revwalk.RevBlob;
  21. import org.eclipse.jgit.revwalk.RevCommit;
  22. import org.eclipse.jgit.revwalk.RevFlag;
  23. import org.eclipse.jgit.revwalk.RevObject;
  24. import org.eclipse.jgit.revwalk.RevSort;
  25. import org.eclipse.jgit.revwalk.RevTree;
  26. import org.eclipse.jgit.transport.ConnectivityChecker;
  27. import org.eclipse.jgit.transport.ReceiveCommand;
  28. import org.eclipse.jgit.transport.ReceiveCommand.Result;
  29. /**
  30. * A connectivity checker that uses the entire reference database to perform
  31. * reachability checks when checking the connectivity of objects. If
  32. * info.isCheckObjects() is set it will also check that objects referenced by
  33. * deltas are either provided or reachable as well.
  34. */
  35. public final class FullConnectivityChecker implements ConnectivityChecker {
  36. @Override
  37. public void checkConnectivity(ConnectivityCheckInfo connectivityCheckInfo,
  38. Set<ObjectId> haves, ProgressMonitor pm)
  39. throws MissingObjectException, IOException {
  40. pm.beginTask(JGitText.get().countingObjects,
  41. ProgressMonitor.UNKNOWN);
  42. try (ObjectWalk ow = new ObjectWalk(connectivityCheckInfo.getRepository())) {
  43. if (!markStartAndKnownNodes(connectivityCheckInfo, ow, haves,
  44. pm)) {
  45. return;
  46. }
  47. checkCommitTree(connectivityCheckInfo, ow, pm);
  48. checkObjects(connectivityCheckInfo, ow, pm);
  49. } finally {
  50. pm.endTask();
  51. }
  52. }
  53. /**
  54. * @param connectivityCheckInfo
  55. * Source for connectivity check.
  56. * @param ow
  57. * Walk which can also check blobs.
  58. * @param haves
  59. * Set of references known for client.
  60. * @param pm
  61. * Monitor to publish progress to.
  62. * @return true if at least one new node was marked.
  63. * @throws IOException
  64. * an error occurred during connectivity checking.
  65. */
  66. private boolean markStartAndKnownNodes(
  67. ConnectivityCheckInfo connectivityCheckInfo,
  68. ObjectWalk ow,
  69. Set<ObjectId> haves, ProgressMonitor pm)
  70. throws IOException {
  71. boolean markTrees = connectivityCheckInfo
  72. .isCheckObjects()
  73. && !connectivityCheckInfo.getParser().getBaseObjectIds()
  74. .isEmpty();
  75. if (connectivityCheckInfo.isCheckObjects()) {
  76. ow.sort(RevSort.TOPO);
  77. if (!connectivityCheckInfo.getParser().getBaseObjectIds()
  78. .isEmpty()) {
  79. ow.sort(RevSort.BOUNDARY, true);
  80. }
  81. }
  82. boolean hasInteresting = false;
  83. for (ReceiveCommand cmd : connectivityCheckInfo.getCommands()) {
  84. if (cmd.getResult() != Result.NOT_ATTEMPTED) {
  85. continue;
  86. }
  87. if (cmd.getType() == ReceiveCommand.Type.DELETE) {
  88. continue;
  89. }
  90. if (haves.contains(cmd.getNewId())) {
  91. continue;
  92. }
  93. ow.markStart(ow.parseAny(cmd.getNewId()));
  94. pm.update(1);
  95. hasInteresting = true;
  96. }
  97. if (!hasInteresting) {
  98. return false;
  99. }
  100. for (ObjectId have : haves) {
  101. RevObject o = ow.parseAny(have);
  102. ow.markUninteresting(o);
  103. pm.update(1);
  104. if (markTrees) {
  105. o = ow.peel(o);
  106. if (o instanceof RevCommit) {
  107. o = ((RevCommit) o).getTree();
  108. }
  109. if (o instanceof RevTree) {
  110. ow.markUninteresting(o);
  111. }
  112. }
  113. }
  114. return true;
  115. }
  116. /**
  117. * @param connectivityCheckInfo
  118. * Source for connectivity check.
  119. * @param ow
  120. * Walk which can also check blobs.
  121. * @param pm
  122. * Monitor to publish progress to.
  123. * @throws IOException
  124. * an error occurred during connectivity checking.
  125. */
  126. private void checkCommitTree(ConnectivityCheckInfo connectivityCheckInfo,
  127. ObjectWalk ow,
  128. ProgressMonitor pm) throws IOException {
  129. RevCommit c;
  130. ObjectIdSubclassMap<ObjectId> newObjectIds = connectivityCheckInfo
  131. .getParser()
  132. .getNewObjectIds();
  133. while ((c = ow.next()) != null) {
  134. pm.update(1);
  135. if (connectivityCheckInfo.isCheckObjects()
  136. && !c.has(RevFlag.UNINTERESTING)
  137. && !newObjectIds.contains(c)) {
  138. throw new MissingObjectException(c, Constants.TYPE_COMMIT);
  139. }
  140. }
  141. }
  142. /**
  143. * @param connectivityCheckInfo
  144. * Source for connectivity check.
  145. * @param ow
  146. * Walk which can also check blobs.
  147. * @param pm
  148. * Monitor to publish progress to.
  149. * @throws IOException
  150. * an error occurred during connectivity checking.
  151. *
  152. */
  153. private void checkObjects(ConnectivityCheckInfo connectivityCheckInfo,
  154. ObjectWalk ow,
  155. ProgressMonitor pm) throws IOException {
  156. RevObject o;
  157. ObjectIdSubclassMap<ObjectId> newObjectIds = connectivityCheckInfo
  158. .getParser()
  159. .getNewObjectIds();
  160. while ((o = ow.nextObject()) != null) {
  161. pm.update(1);
  162. if (o.has(RevFlag.UNINTERESTING)) {
  163. continue;
  164. }
  165. if (connectivityCheckInfo.isCheckObjects()) {
  166. if (newObjectIds.contains(o)) {
  167. continue;
  168. }
  169. throw new MissingObjectException(o, o.getType());
  170. }
  171. if (o instanceof RevBlob
  172. && !connectivityCheckInfo.getRepository().getObjectDatabase()
  173. .has(o)) {
  174. throw new MissingObjectException(o, Constants.TYPE_BLOB);
  175. }
  176. }
  177. if (connectivityCheckInfo.isCheckObjects()) {
  178. for (ObjectId id : connectivityCheckInfo.getParser()
  179. .getBaseObjectIds()) {
  180. o = ow.parseAny(id);
  181. if (!o.has(RevFlag.UNINTERESTING)) {
  182. throw new MissingObjectException(o, o.getType());
  183. }
  184. }
  185. }
  186. }
  187. }