Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

BasePackFetchConnection.java 21KB

Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 år sedan
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*
  2. * Copyright (C) 2008-2010, Google Inc.
  3. * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
  4. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  5. * and other copyright owners as documented in the project's IP log.
  6. *
  7. * This program and the accompanying materials are made available
  8. * under the terms of the Eclipse Distribution License v1.0 which
  9. * accompanies this distribution, is reproduced below, and is
  10. * available at http://www.eclipse.org/org/documents/edl-v10.php
  11. *
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or
  15. * without modification, are permitted provided that the following
  16. * conditions are met:
  17. *
  18. * - Redistributions of source code must retain the above copyright
  19. * notice, this list of conditions and the following disclaimer.
  20. *
  21. * - Redistributions in binary form must reproduce the above
  22. * copyright notice, this list of conditions and the following
  23. * disclaimer in the documentation and/or other materials provided
  24. * with the distribution.
  25. *
  26. * - Neither the name of the Eclipse Foundation, Inc. nor the
  27. * names of its contributors may be used to endorse or promote
  28. * products derived from this software without specific prior
  29. * written permission.
  30. *
  31. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  32. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  33. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  34. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  36. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  37. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  38. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  39. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  40. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  41. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  42. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  43. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. */
  45. package org.eclipse.jgit.transport;
  46. import java.io.IOException;
  47. import java.io.InputStream;
  48. import java.text.MessageFormat;
  49. import java.util.Collection;
  50. import java.util.Collections;
  51. import java.util.Date;
  52. import java.util.Set;
  53. import org.eclipse.jgit.JGitText;
  54. import org.eclipse.jgit.errors.PackProtocolException;
  55. import org.eclipse.jgit.errors.TransportException;
  56. import org.eclipse.jgit.lib.AnyObjectId;
  57. import org.eclipse.jgit.lib.Config;
  58. import org.eclipse.jgit.lib.Constants;
  59. import org.eclipse.jgit.lib.MutableObjectId;
  60. import org.eclipse.jgit.lib.ObjectId;
  61. import org.eclipse.jgit.lib.ObjectInserter;
  62. import org.eclipse.jgit.lib.ProgressMonitor;
  63. import org.eclipse.jgit.lib.Ref;
  64. import org.eclipse.jgit.lib.Config.SectionParser;
  65. import org.eclipse.jgit.revwalk.RevCommit;
  66. import org.eclipse.jgit.revwalk.RevCommitList;
  67. import org.eclipse.jgit.revwalk.RevFlag;
  68. import org.eclipse.jgit.revwalk.RevObject;
  69. import org.eclipse.jgit.revwalk.RevSort;
  70. import org.eclipse.jgit.revwalk.RevWalk;
  71. import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
  72. import org.eclipse.jgit.revwalk.filter.RevFilter;
  73. import org.eclipse.jgit.storage.file.PackLock;
  74. import org.eclipse.jgit.transport.PacketLineIn.AckNackResult;
  75. import org.eclipse.jgit.util.TemporaryBuffer;
  76. /**
  77. * Fetch implementation using the native Git pack transfer service.
  78. * <p>
  79. * This is the canonical implementation for transferring objects from the remote
  80. * repository to the local repository by talking to the 'git-upload-pack'
  81. * service. Objects are packed on the remote side into a pack file and then sent
  82. * down the pipe to us.
  83. * <p>
  84. * This connection requires only a bi-directional pipe or socket, and thus is
  85. * easily wrapped up into a local process pipe, anonymous TCP socket, or a
  86. * command executed through an SSH tunnel.
  87. * <p>
  88. * If {@link BasePackConnection#statelessRPC} is {@code true}, this connection
  89. * can be tunneled over a request-response style RPC system like HTTP. The RPC
  90. * call boundary is determined by this class switching from writing to the
  91. * OutputStream to reading from the InputStream.
  92. * <p>
  93. * Concrete implementations should just call
  94. * {@link #init(java.io.InputStream, java.io.OutputStream)} and
  95. * {@link #readAdvertisedRefs()} methods in constructor or before any use. They
  96. * should also handle resources releasing in {@link #close()} method if needed.
  97. */
  98. public abstract class BasePackFetchConnection extends BasePackConnection
  99. implements FetchConnection {
  100. /**
  101. * Maximum number of 'have' lines to send before giving up.
  102. * <p>
  103. * During {@link #negotiate(ProgressMonitor)} we send at most this many
  104. * commits to the remote peer as 'have' lines without an ACK response before
  105. * we give up.
  106. */
  107. private static final int MAX_HAVES = 256;
  108. /**
  109. * Amount of data the client sends before starting to read.
  110. * <p>
  111. * Any output stream given to the client must be able to buffer this many
  112. * bytes before the client will stop writing and start reading from the
  113. * input stream. If the output stream blocks before this many bytes are in
  114. * the send queue, the system will deadlock.
  115. */
  116. protected static final int MIN_CLIENT_BUFFER = 2 * 32 * 46 + 8;
  117. /** Include tags if we are also including the referenced objects. */
  118. public static final String OPTION_INCLUDE_TAG = "include-tag";
  119. /** Mutli-ACK support for improved negotiation. */
  120. public static final String OPTION_MULTI_ACK = "multi_ack";
  121. /** Mutli-ACK detailed support for improved negotiation. */
  122. public static final String OPTION_MULTI_ACK_DETAILED = "multi_ack_detailed";
  123. /** The client supports packs with deltas but not their bases. */
  124. public static final String OPTION_THIN_PACK = "thin-pack";
  125. /** The client supports using the side-band for progress messages. */
  126. public static final String OPTION_SIDE_BAND = "side-band";
  127. /** The client supports using the 64K side-band for progress messages. */
  128. public static final String OPTION_SIDE_BAND_64K = "side-band-64k";
  129. /** The client supports packs with OFS deltas. */
  130. public static final String OPTION_OFS_DELTA = "ofs-delta";
  131. /** The client supports shallow fetches. */
  132. public static final String OPTION_SHALLOW = "shallow";
  133. /** The client does not want progress messages and will ignore them. */
  134. public static final String OPTION_NO_PROGRESS = "no-progress";
  135. /** The client supports receiving a pack before it has sent "done". */
  136. public static final String OPTION_NO_DONE = "no-done";
  137. static enum MultiAck {
  138. OFF, CONTINUE, DETAILED;
  139. }
  140. private final RevWalk walk;
  141. /** All commits that are immediately reachable by a local ref. */
  142. private RevCommitList<RevCommit> reachableCommits;
  143. /** Marks an object as having all its dependencies. */
  144. final RevFlag REACHABLE;
  145. /** Marks a commit known to both sides of the connection. */
  146. final RevFlag COMMON;
  147. /** Like {@link #COMMON} but means its also in {@link #pckState}. */
  148. private final RevFlag STATE;
  149. /** Marks a commit listed in the advertised refs. */
  150. final RevFlag ADVERTISED;
  151. private MultiAck multiAck = MultiAck.OFF;
  152. private boolean thinPack;
  153. private boolean sideband;
  154. private boolean includeTags;
  155. private boolean allowOfsDelta;
  156. private boolean noDone;
  157. private String lockMessage;
  158. private PackLock packLock;
  159. /** RPC state, if {@link BasePackConnection#statelessRPC} is true. */
  160. private TemporaryBuffer.Heap state;
  161. private PacketLineOut pckState;
  162. /**
  163. * Create a new connection to fetch using the native git transport.
  164. *
  165. * @param packTransport
  166. * the transport.
  167. */
  168. public BasePackFetchConnection(final PackTransport packTransport) {
  169. super(packTransport);
  170. final FetchConfig cfg = local.getConfig().get(FetchConfig.KEY);
  171. includeTags = transport.getTagOpt() != TagOpt.NO_TAGS;
  172. thinPack = transport.isFetchThin();
  173. allowOfsDelta = cfg.allowOfsDelta;
  174. walk = new RevWalk(local);
  175. reachableCommits = new RevCommitList<RevCommit>();
  176. REACHABLE = walk.newFlag("REACHABLE");
  177. COMMON = walk.newFlag("COMMON");
  178. STATE = walk.newFlag("STATE");
  179. ADVERTISED = walk.newFlag("ADVERTISED");
  180. walk.carry(COMMON);
  181. walk.carry(REACHABLE);
  182. walk.carry(ADVERTISED);
  183. }
  184. private static class FetchConfig {
  185. static final SectionParser<FetchConfig> KEY = new SectionParser<FetchConfig>() {
  186. public FetchConfig parse(final Config cfg) {
  187. return new FetchConfig(cfg);
  188. }
  189. };
  190. final boolean allowOfsDelta;
  191. FetchConfig(final Config c) {
  192. allowOfsDelta = c.getBoolean("repack", "usedeltabaseoffset", true);
  193. }
  194. }
  195. public final void fetch(final ProgressMonitor monitor,
  196. final Collection<Ref> want, final Set<ObjectId> have)
  197. throws TransportException {
  198. markStartedOperation();
  199. doFetch(monitor, want, have);
  200. }
  201. public boolean didFetchIncludeTags() {
  202. return false;
  203. }
  204. public boolean didFetchTestConnectivity() {
  205. return false;
  206. }
  207. public void setPackLockMessage(final String message) {
  208. lockMessage = message;
  209. }
  210. public Collection<PackLock> getPackLocks() {
  211. if (packLock != null)
  212. return Collections.singleton(packLock);
  213. return Collections.<PackLock> emptyList();
  214. }
  215. /**
  216. * Execute common ancestor negotiation and fetch the objects.
  217. *
  218. * @param monitor
  219. * progress monitor to receive status updates.
  220. * @param want
  221. * the advertised remote references the caller wants to fetch.
  222. * @param have
  223. * additional objects to assume that already exist locally. This
  224. * will be added to the set of objects reachable from the
  225. * destination repository's references.
  226. * @throws TransportException
  227. * if any exception occurs.
  228. */
  229. protected void doFetch(final ProgressMonitor monitor,
  230. final Collection<Ref> want, final Set<ObjectId> have)
  231. throws TransportException {
  232. try {
  233. markRefsAdvertised();
  234. markReachable(have, maxTimeWanted(want));
  235. if (statelessRPC) {
  236. state = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
  237. pckState = new PacketLineOut(state);
  238. }
  239. if (sendWants(want)) {
  240. negotiate(monitor);
  241. walk.dispose();
  242. reachableCommits = null;
  243. state = null;
  244. pckState = null;
  245. receivePack(monitor);
  246. }
  247. } catch (CancelledException ce) {
  248. close();
  249. return; // Caller should test (or just know) this themselves.
  250. } catch (IOException err) {
  251. close();
  252. throw new TransportException(err.getMessage(), err);
  253. } catch (RuntimeException err) {
  254. close();
  255. throw new TransportException(err.getMessage(), err);
  256. }
  257. }
  258. @Override
  259. public void close() {
  260. walk.release();
  261. super.close();
  262. }
  263. private int maxTimeWanted(final Collection<Ref> wants) {
  264. int maxTime = 0;
  265. for (final Ref r : wants) {
  266. try {
  267. final RevObject obj = walk.parseAny(r.getObjectId());
  268. if (obj instanceof RevCommit) {
  269. final int cTime = ((RevCommit) obj).getCommitTime();
  270. if (maxTime < cTime)
  271. maxTime = cTime;
  272. }
  273. } catch (IOException error) {
  274. // We don't have it, but we want to fetch (thus fixing error).
  275. }
  276. }
  277. return maxTime;
  278. }
  279. private void markReachable(final Set<ObjectId> have, final int maxTime)
  280. throws IOException {
  281. for (final Ref r : local.getAllRefs().values()) {
  282. ObjectId id = r.getPeeledObjectId();
  283. if (id == null)
  284. id = r.getObjectId();
  285. if (id == null)
  286. continue;
  287. parseReachable(id);
  288. }
  289. for (ObjectId id : local.getAdditionalHaves())
  290. parseReachable(id);
  291. for (ObjectId id : have)
  292. parseReachable(id);
  293. if (maxTime > 0) {
  294. // Mark reachable commits until we reach maxTime. These may
  295. // wind up later matching up against things we want and we
  296. // can avoid asking for something we already happen to have.
  297. //
  298. final Date maxWhen = new Date(maxTime * 1000L);
  299. walk.sort(RevSort.COMMIT_TIME_DESC);
  300. walk.markStart(reachableCommits);
  301. walk.setRevFilter(CommitTimeRevFilter.after(maxWhen));
  302. for (;;) {
  303. final RevCommit c = walk.next();
  304. if (c == null)
  305. break;
  306. if (c.has(ADVERTISED) && !c.has(COMMON)) {
  307. // This is actually going to be a common commit, but
  308. // our peer doesn't know that fact yet.
  309. //
  310. c.add(COMMON);
  311. c.carry(COMMON);
  312. reachableCommits.add(c);
  313. }
  314. }
  315. }
  316. }
  317. private void parseReachable(ObjectId id) {
  318. try {
  319. RevCommit o = walk.parseCommit(id);
  320. if (!o.has(REACHABLE)) {
  321. o.add(REACHABLE);
  322. reachableCommits.add(o);
  323. }
  324. } catch (IOException readError) {
  325. // If we cannot read the value of the ref skip it.
  326. }
  327. }
  328. private boolean sendWants(final Collection<Ref> want) throws IOException {
  329. final PacketLineOut p = statelessRPC ? pckState : pckOut;
  330. boolean first = true;
  331. for (final Ref r : want) {
  332. try {
  333. if (walk.parseAny(r.getObjectId()).has(REACHABLE)) {
  334. // We already have this object. Asking for it is
  335. // not a very good idea.
  336. //
  337. continue;
  338. }
  339. } catch (IOException err) {
  340. // Its OK, we don't have it, but we want to fix that
  341. // by fetching the object from the other side.
  342. }
  343. final StringBuilder line = new StringBuilder(46);
  344. line.append("want ");
  345. line.append(r.getObjectId().name());
  346. if (first) {
  347. line.append(enableCapabilities());
  348. first = false;
  349. }
  350. line.append('\n');
  351. p.writeString(line.toString());
  352. }
  353. if (first)
  354. return false;
  355. p.end();
  356. outNeedsEnd = false;
  357. return true;
  358. }
  359. private String enableCapabilities() throws TransportException {
  360. final StringBuilder line = new StringBuilder();
  361. if (includeTags)
  362. includeTags = wantCapability(line, OPTION_INCLUDE_TAG);
  363. if (allowOfsDelta)
  364. wantCapability(line, OPTION_OFS_DELTA);
  365. if (wantCapability(line, OPTION_MULTI_ACK_DETAILED)) {
  366. multiAck = MultiAck.DETAILED;
  367. if (statelessRPC)
  368. noDone = wantCapability(line, OPTION_NO_DONE);
  369. } else if (wantCapability(line, OPTION_MULTI_ACK))
  370. multiAck = MultiAck.CONTINUE;
  371. else
  372. multiAck = MultiAck.OFF;
  373. if (thinPack)
  374. thinPack = wantCapability(line, OPTION_THIN_PACK);
  375. if (wantCapability(line, OPTION_SIDE_BAND_64K))
  376. sideband = true;
  377. else if (wantCapability(line, OPTION_SIDE_BAND))
  378. sideband = true;
  379. if (statelessRPC && multiAck != MultiAck.DETAILED) {
  380. // Our stateless RPC implementation relies upon the detailed
  381. // ACK status to tell us common objects for reuse in future
  382. // requests. If its not enabled, we can't talk to the peer.
  383. //
  384. throw new PackProtocolException(uri, MessageFormat.format(
  385. JGitText.get().statelessRPCRequiresOptionToBeEnabled,
  386. OPTION_MULTI_ACK_DETAILED));
  387. }
  388. return line.toString();
  389. }
  390. private void negotiate(final ProgressMonitor monitor) throws IOException,
  391. CancelledException {
  392. final MutableObjectId ackId = new MutableObjectId();
  393. int resultsPending = 0;
  394. int havesSent = 0;
  395. int havesSinceLastContinue = 0;
  396. boolean receivedContinue = false;
  397. boolean receivedAck = false;
  398. boolean receivedReady = false;
  399. if (statelessRPC)
  400. state.writeTo(out, null);
  401. negotiateBegin();
  402. SEND_HAVES: for (;;) {
  403. final RevCommit c = walk.next();
  404. if (c == null)
  405. break SEND_HAVES;
  406. pckOut.writeString("have " + c.getId().name() + "\n");
  407. havesSent++;
  408. havesSinceLastContinue++;
  409. if ((31 & havesSent) != 0) {
  410. // We group the have lines into blocks of 32, each marked
  411. // with a flush (aka end). This one is within a block so
  412. // continue with another have line.
  413. //
  414. continue;
  415. }
  416. if (monitor.isCancelled())
  417. throw new CancelledException();
  418. pckOut.end();
  419. resultsPending++; // Each end will cause a result to come back.
  420. if (havesSent == 32 && !statelessRPC) {
  421. // On the first block we race ahead and try to send
  422. // more of the second block while waiting for the
  423. // remote to respond to our first block request.
  424. // This keeps us one block ahead of the peer.
  425. //
  426. continue;
  427. }
  428. READ_RESULT: for (;;) {
  429. final AckNackResult anr = pckIn.readACK(ackId);
  430. switch (anr) {
  431. case NAK:
  432. // More have lines are necessary to compute the
  433. // pack on the remote side. Keep doing that.
  434. //
  435. resultsPending--;
  436. break READ_RESULT;
  437. case ACK:
  438. // The remote side is happy and knows exactly what
  439. // to send us. There is no further negotiation and
  440. // we can break out immediately.
  441. //
  442. multiAck = MultiAck.OFF;
  443. resultsPending = 0;
  444. receivedAck = true;
  445. if (statelessRPC)
  446. state.writeTo(out, null);
  447. break SEND_HAVES;
  448. case ACK_CONTINUE:
  449. case ACK_COMMON:
  450. case ACK_READY:
  451. // The server knows this commit (ackId). We don't
  452. // need to send any further along its ancestry, but
  453. // we need to continue to talk about other parts of
  454. // our local history.
  455. //
  456. markCommon(walk.parseAny(ackId), anr);
  457. receivedAck = true;
  458. receivedContinue = true;
  459. havesSinceLastContinue = 0;
  460. if (anr == AckNackResult.ACK_READY)
  461. receivedReady = true;
  462. break;
  463. }
  464. if (monitor.isCancelled())
  465. throw new CancelledException();
  466. }
  467. if (noDone & receivedReady)
  468. break SEND_HAVES;
  469. if (statelessRPC)
  470. state.writeTo(out, null);
  471. if (receivedContinue && havesSinceLastContinue > MAX_HAVES) {
  472. // Our history must be really different from the remote's.
  473. // We just sent a whole slew of have lines, and it did not
  474. // recognize any of them. Avoid sending our entire history
  475. // to them by giving up early.
  476. //
  477. break SEND_HAVES;
  478. }
  479. }
  480. // Tell the remote side we have run out of things to talk about.
  481. //
  482. if (monitor.isCancelled())
  483. throw new CancelledException();
  484. if (!receivedReady || !noDone) {
  485. // When statelessRPC is true we should always leave SEND_HAVES
  486. // loop above while in the middle of a request. This allows us
  487. // to just write done immediately.
  488. //
  489. pckOut.writeString("done\n");
  490. pckOut.flush();
  491. }
  492. if (!receivedAck) {
  493. // Apparently if we have never received an ACK earlier
  494. // there is one more result expected from the done we
  495. // just sent to the remote.
  496. //
  497. multiAck = MultiAck.OFF;
  498. resultsPending++;
  499. }
  500. READ_RESULT: while (resultsPending > 0 || multiAck != MultiAck.OFF) {
  501. final AckNackResult anr = pckIn.readACK(ackId);
  502. resultsPending--;
  503. switch (anr) {
  504. case NAK:
  505. // A NAK is a response to an end we queued earlier
  506. // we eat it and look for another ACK/NAK message.
  507. //
  508. break;
  509. case ACK:
  510. // A solitary ACK at this point means the remote won't
  511. // speak anymore, but is going to send us a pack now.
  512. //
  513. break READ_RESULT;
  514. case ACK_CONTINUE:
  515. case ACK_COMMON:
  516. case ACK_READY:
  517. // We will expect a normal ACK to break out of the loop.
  518. //
  519. multiAck = MultiAck.CONTINUE;
  520. break;
  521. }
  522. if (monitor.isCancelled())
  523. throw new CancelledException();
  524. }
  525. }
  526. private void negotiateBegin() throws IOException {
  527. walk.resetRetain(REACHABLE, ADVERTISED);
  528. walk.markStart(reachableCommits);
  529. walk.sort(RevSort.COMMIT_TIME_DESC);
  530. walk.setRevFilter(new RevFilter() {
  531. @Override
  532. public RevFilter clone() {
  533. return this;
  534. }
  535. @Override
  536. public boolean include(final RevWalk walker, final RevCommit c) {
  537. final boolean remoteKnowsIsCommon = c.has(COMMON);
  538. if (c.has(ADVERTISED)) {
  539. // Remote advertised this, and we have it, hence common.
  540. // Whether or not the remote knows that fact is tested
  541. // before we added the flag. If the remote doesn't know
  542. // we have to still send them this object.
  543. //
  544. c.add(COMMON);
  545. }
  546. return !remoteKnowsIsCommon;
  547. }
  548. @Override
  549. public boolean requiresCommitBody() {
  550. return false;
  551. }
  552. });
  553. }
  554. private void markRefsAdvertised() {
  555. for (final Ref r : getRefs()) {
  556. markAdvertised(r.getObjectId());
  557. if (r.getPeeledObjectId() != null)
  558. markAdvertised(r.getPeeledObjectId());
  559. }
  560. }
  561. private void markAdvertised(final AnyObjectId id) {
  562. try {
  563. walk.parseAny(id).add(ADVERTISED);
  564. } catch (IOException readError) {
  565. // We probably just do not have this object locally.
  566. }
  567. }
  568. private void markCommon(final RevObject obj, final AckNackResult anr)
  569. throws IOException {
  570. if (statelessRPC && anr == AckNackResult.ACK_COMMON && !obj.has(STATE)) {
  571. StringBuilder s;
  572. s = new StringBuilder(6 + Constants.OBJECT_ID_STRING_LENGTH);
  573. s.append("have "); //$NON-NLS-1$
  574. s.append(obj.name());
  575. s.append('\n');
  576. pckState.writeString(s.toString());
  577. obj.add(STATE);
  578. }
  579. obj.add(COMMON);
  580. if (obj instanceof RevCommit)
  581. ((RevCommit) obj).carry(COMMON);
  582. }
  583. private void receivePack(final ProgressMonitor monitor) throws IOException {
  584. InputStream input = in;
  585. if (sideband)
  586. input = new SideBandInputStream(input, monitor, getMessageWriter());
  587. ObjectInserter ins = local.newObjectInserter();
  588. try {
  589. PackParser parser = ins.newPackParser(input);
  590. parser.setAllowThin(thinPack);
  591. parser.setObjectChecking(transport.isCheckFetchedObjects());
  592. parser.setLockMessage(lockMessage);
  593. packLock = parser.parse(monitor);
  594. ins.flush();
  595. } finally {
  596. ins.release();
  597. }
  598. }
  599. private static class CancelledException extends Exception {
  600. private static final long serialVersionUID = 1L;
  601. }
  602. }