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.

DepthGenerator.java 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (C) 2010, Garmin International
  3. * Copyright (C) 2010, Matt Fischer <matt.fischer@garmin.com>
  4. * and other copyright owners as documented in the project's IP log.
  5. *
  6. * This program and the accompanying materials are made available
  7. * under the terms of the Eclipse Distribution License v1.0 which
  8. * accompanies this distribution, is reproduced below, and is
  9. * available at http://www.eclipse.org/org/documents/edl-v10.php
  10. *
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or
  14. * without modification, are permitted provided that the following
  15. * conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. *
  20. * - Redistributions in binary form must reproduce the above
  21. * copyright notice, this list of conditions and the following
  22. * disclaimer in the documentation and/or other materials provided
  23. * with the distribution.
  24. *
  25. * - Neither the name of the Eclipse Foundation, Inc. nor the
  26. * names of its contributors may be used to endorse or promote
  27. * products derived from this software without specific prior
  28. * written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  31. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  32. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  33. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  35. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  39. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  42. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43. */
  44. package org.eclipse.jgit.revwalk;
  45. import java.io.IOException;
  46. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  47. import org.eclipse.jgit.errors.MissingObjectException;
  48. import org.eclipse.jgit.lib.ObjectId;
  49. /**
  50. * Only produce commits which are below a specified depth.
  51. *
  52. * @see DepthWalk
  53. */
  54. class DepthGenerator extends Generator {
  55. private final FIFORevQueue pending;
  56. private final int depth;
  57. private final int deepenSince;
  58. private final RevWalk walk;
  59. /**
  60. * Commits which used to be shallow in the client, but which are
  61. * being extended as part of this fetch. These commits should be
  62. * returned to the caller as UNINTERESTING so that their blobs/trees
  63. * can be marked appropriately in the pack writer.
  64. */
  65. private final RevFlag UNSHALLOW;
  66. /**
  67. * Commits which the normal framework has marked as UNINTERESTING,
  68. * but which we now care about again. This happens if a client is
  69. * extending a shallow checkout to become deeper--the new commits at
  70. * the bottom of the graph need to be sent, even though they are
  71. * below other commits which the client already has.
  72. */
  73. private final RevFlag REINTERESTING;
  74. /**
  75. * Commits reachable from commits that the client specified using --shallow-exclude.
  76. */
  77. private final RevFlag DEEPEN_NOT;
  78. /**
  79. * @param w
  80. * @param s Parent generator
  81. * @throws MissingObjectException
  82. * @throws IncorrectObjectTypeException
  83. * @throws IOException
  84. */
  85. DepthGenerator(DepthWalk w, Generator s) throws MissingObjectException,
  86. IncorrectObjectTypeException, IOException {
  87. pending = new FIFORevQueue();
  88. walk = (RevWalk)w;
  89. this.depth = w.getDepth();
  90. this.deepenSince = w.getDeepenSince();
  91. this.UNSHALLOW = w.getUnshallowFlag();
  92. this.REINTERESTING = w.getReinterestingFlag();
  93. this.DEEPEN_NOT = w.getDeepenNotFlag();
  94. s.shareFreeList(pending);
  95. // Begin by sucking out all of the source's commits, and
  96. // adding them to the pending queue
  97. FIFORevQueue unshallowCommits = new FIFORevQueue();
  98. for (;;) {
  99. RevCommit c = s.next();
  100. if (c == null)
  101. break;
  102. if (c.has(UNSHALLOW)) {
  103. unshallowCommits.add(c);
  104. } else if (((DepthWalk.Commit) c).getDepth() == 0) {
  105. pending.add(c);
  106. }
  107. }
  108. // Move unshallow commits to the front so that the REINTERESTING flag
  109. // carry over code is executed first.
  110. for (;;) {
  111. RevCommit c = unshallowCommits.next();
  112. if (c == null) {
  113. break;
  114. }
  115. pending.unpop(c);
  116. }
  117. // Mark DEEPEN_NOT on all deepen-not commits and their ancestors.
  118. // TODO(jonathantanmy): This implementation is somewhat
  119. // inefficient in that any "deepen-not <ref>" in the request
  120. // results in all commits reachable from that ref being parsed
  121. // and marked, even if the commit topology is such that it is
  122. // not necessary.
  123. for (ObjectId oid : w.getDeepenNots()) {
  124. RevCommit c;
  125. try {
  126. c = walk.parseCommit(oid);
  127. } catch (IncorrectObjectTypeException notCommit) {
  128. // The C Git implementation silently tolerates
  129. // non-commits, so do the same here.
  130. continue;
  131. }
  132. FIFORevQueue queue = new FIFORevQueue();
  133. queue.add(c);
  134. while ((c = queue.next()) != null) {
  135. if (c.has(DEEPEN_NOT)) {
  136. continue;
  137. }
  138. walk.parseHeaders(c);
  139. c.add(DEEPEN_NOT);
  140. for (RevCommit p : c.getParents()) {
  141. queue.add(p);
  142. }
  143. }
  144. }
  145. }
  146. @Override
  147. int outputType() {
  148. return pending.outputType() | HAS_UNINTERESTING;
  149. }
  150. @Override
  151. void shareFreeList(BlockRevQueue q) {
  152. pending.shareFreeList(q);
  153. }
  154. @Override
  155. RevCommit next() throws MissingObjectException,
  156. IncorrectObjectTypeException, IOException {
  157. // Perform a breadth-first descent into the commit graph,
  158. // marking depths as we go. This means that if a commit is
  159. // reachable by more than one route, we are guaranteed to
  160. // arrive by the shortest route first.
  161. for (;;) {
  162. final DepthWalk.Commit c = (DepthWalk.Commit) pending.next();
  163. if (c == null)
  164. return null;
  165. if ((c.flags & RevWalk.PARSED) == 0)
  166. c.parseHeaders(walk);
  167. if (c.getCommitTime() < deepenSince) {
  168. continue;
  169. }
  170. if (c.has(DEEPEN_NOT)) {
  171. continue;
  172. }
  173. int newDepth = c.depth + 1;
  174. for (RevCommit p : c.parents) {
  175. DepthWalk.Commit dp = (DepthWalk.Commit) p;
  176. // If no depth has been assigned to this commit, assign
  177. // it now. Since we arrive by the shortest route first,
  178. // this depth is guaranteed to be the smallest value that
  179. // any path could produce.
  180. if (dp.depth == -1) {
  181. boolean failsDeepenSince = false;
  182. if (deepenSince != 0) {
  183. if ((p.flags & RevWalk.PARSED) == 0) {
  184. p.parseHeaders(walk);
  185. }
  186. failsDeepenSince =
  187. p.getCommitTime() < deepenSince;
  188. }
  189. dp.depth = newDepth;
  190. // If the parent is not too deep and was not excluded, add
  191. // it to the queue so that we can produce it later
  192. if (newDepth <= depth && !failsDeepenSince &&
  193. !p.has(DEEPEN_NOT)) {
  194. pending.add(p);
  195. } else {
  196. dp.makesChildBoundary = true;
  197. }
  198. }
  199. if (dp.makesChildBoundary) {
  200. c.isBoundary = true;
  201. }
  202. // If the current commit has become unshallowed, everything
  203. // below us is new to the client. Mark its parent as
  204. // re-interesting, and carry that flag downward to all
  205. // of its ancestors.
  206. if(c.has(UNSHALLOW) || c.has(REINTERESTING)) {
  207. p.add(REINTERESTING);
  208. p.flags &= ~RevWalk.UNINTERESTING;
  209. }
  210. }
  211. boolean produce = true;
  212. // Unshallow commits are uninteresting, but still need to be sent
  213. // up to the PackWriter so that it will exclude objects correctly.
  214. // All other uninteresting commits should be omitted.
  215. if ((c.flags & RevWalk.UNINTERESTING) != 0 && !c.has(UNSHALLOW))
  216. produce = false;
  217. if (c.getCommitTime() < deepenSince) {
  218. produce = false;
  219. }
  220. if (produce)
  221. return c;
  222. }
  223. }
  224. }