// We probably just do not have this object locally. /// <exception cref="System.IO.IOException"></exception> private void MarkCommon(RevObject obj, PacketLineIn.AckNackResult anr) { if (statelessRPC && anr == PacketLineIn.AckNackResult.ACK_COMMON && !obj.Has(STATE )) { StringBuilder s; s = new StringBuilder(6 + Constants.OBJECT_ID_STRING_LENGTH); s.Append("have "); //$NON-NLS-1$ s.Append(obj.Name); s.Append('\n'); pckState.WriteString(s.ToString()); obj.Add(STATE); } obj.Add(COMMON); if (obj is RevCommit) { ((RevCommit)obj).Carry(COMMON); } }
/// <exception cref="System.IO.IOException"></exception> /// <exception cref="NGit.Transport.BasePackFetchConnection.CancelledException"></exception> private void Negotiate(ProgressMonitor monitor) { MutableObjectId ackId = new MutableObjectId(); int resultsPending = 0; int havesSent = 0; int havesSinceLastContinue = 0; bool receivedContinue = false; bool receivedAck = false; bool receivedReady = false; if (statelessRPC) { state.WriteTo(@out, null); } NegotiateBegin(); while (!receivedReady) { RevCommit c = walk.Next(); if (c == null) { goto SEND_HAVES_break; } pckOut.WriteString("have " + c.Id.Name + "\n"); havesSent++; havesSinceLastContinue++; if ((31 & havesSent) != 0) { // We group the have lines into blocks of 32, each marked // with a flush (aka end). This one is within a block so // continue with another have line. // continue; } if (monitor.IsCancelled()) { throw new BasePackFetchConnection.CancelledException(); } pckOut.End(); resultsPending++; // Each end will cause a result to come back. if (havesSent == 32 && !statelessRPC) { // On the first block we race ahead and try to send // more of the second block while waiting for the // remote to respond to our first block request. // This keeps us one block ahead of the peer. // continue; } for (; ;) { PacketLineIn.AckNackResult anr = pckIn.ReadACK(ackId); switch (anr) { case PacketLineIn.AckNackResult.NAK: { // More have lines are necessary to compute the // pack on the remote side. Keep doing that. // resultsPending--; goto READ_RESULT_break; } case PacketLineIn.AckNackResult.ACK: { // The remote side is happy and knows exactly what // to send us. There is no further negotiation and // we can break out immediately. // multiAck = BasePackFetchConnection.MultiAck.OFF; resultsPending = 0; receivedAck = true; if (statelessRPC) { state.WriteTo(@out, null); } goto SEND_HAVES_break; } case PacketLineIn.AckNackResult.ACK_CONTINUE: case PacketLineIn.AckNackResult.ACK_COMMON: case PacketLineIn.AckNackResult.ACK_READY: { // The server knows this commit (ackId). We don't // need to send any further along its ancestry, but // we need to continue to talk about other parts of // our local history. // MarkCommon(walk.ParseAny(ackId), anr); receivedAck = true; receivedContinue = true; havesSinceLastContinue = 0; if (anr == PacketLineIn.AckNackResult.ACK_READY) { receivedReady = true; } break; } } if (monitor.IsCancelled()) { throw new BasePackFetchConnection.CancelledException(); } READ_RESULT_continue :; } READ_RESULT_break :; if (statelessRPC) { state.WriteTo(@out, null); } if (receivedContinue && havesSinceLastContinue > MAX_HAVES) { // Our history must be really different from the remote's. // We just sent a whole slew of have lines, and it did not // recognize any of them. Avoid sending our entire history // to them by giving up early. // goto SEND_HAVES_break; } SEND_HAVES_continue :; } SEND_HAVES_break :; // Tell the remote side we have run out of things to talk about. // if (monitor.IsCancelled()) { throw new BasePackFetchConnection.CancelledException(); } if (!receivedReady || !noDone) { // When statelessRPC is true we should always leave SEND_HAVES // loop above while in the middle of a request. This allows us // to just write done immediately. // pckOut.WriteString("done\n"); pckOut.Flush(); } if (!receivedAck) { // Apparently if we have never received an ACK earlier // there is one more result expected from the done we // just sent to the remote. // multiAck = BasePackFetchConnection.MultiAck.OFF; resultsPending++; } while (resultsPending > 0 || multiAck != BasePackFetchConnection.MultiAck.OFF) { PacketLineIn.AckNackResult anr = pckIn.ReadACK(ackId); resultsPending--; switch (anr) { case PacketLineIn.AckNackResult.NAK: { // A NAK is a response to an end we queued earlier // we eat it and look for another ACK/NAK message. // break; } case PacketLineIn.AckNackResult.ACK: { // A solitary ACK at this point means the remote won't // speak anymore, but is going to send us a pack now. // goto READ_RESULT_break2; } case PacketLineIn.AckNackResult.ACK_CONTINUE: case PacketLineIn.AckNackResult.ACK_COMMON: case PacketLineIn.AckNackResult.ACK_READY: { // We will expect a normal ACK to break out of the loop. // multiAck = BasePackFetchConnection.MultiAck.CONTINUE; break; } } if (monitor.IsCancelled()) { throw new BasePackFetchConnection.CancelledException(); } READ_RESULT_continue :; } READ_RESULT_break2 :; }
private void Negotiate(ProgressMonitor monitor) { var ackId = new MutableObjectId(); int resultsPending = 0; int havesSent = 0; int havesSinceLastContinue = 0; bool receivedContinue = false; bool receivedAck = false; bool sendHaves = true; NegotiateBegin(); while (sendHaves) { RevCommit c = _walk.next(); if (c == null) { break; } pckOut.WriteString("have " + c.getId().Name + "\n"); havesSent++; havesSinceLastContinue++; if ((31 & havesSent) != 0) { continue; } if (monitor.IsCancelled) { throw new CancelledException(); } pckOut.End(); resultsPending++; if (havesSent == 32) { continue; } for (; ;) { PacketLineIn.AckNackResult anr = pckIn.readACK(ackId); if (anr == PacketLineIn.AckNackResult.NAK) { resultsPending--; break; } if (anr == PacketLineIn.AckNackResult.ACK) { _multiAck = false; resultsPending = 0; receivedAck = true; sendHaves = false; break; } if (anr == PacketLineIn.AckNackResult.ACK_CONTINUE) { MarkCommon(_walk.parseAny(ackId)); receivedAck = true; receivedContinue = true; havesSinceLastContinue = 0; } if (monitor.IsCancelled) { throw new CancelledException(); } } if (receivedContinue && havesSinceLastContinue > MAX_HAVES) { break; } } if (monitor.IsCancelled) { throw new CancelledException(); } pckOut.WriteString("done\n"); pckOut.Flush(); if (!receivedAck) { _multiAck = false; resultsPending++; } while (resultsPending > 0 || _multiAck) { PacketLineIn.AckNackResult anr = pckIn.readACK(ackId); resultsPending--; if (anr == PacketLineIn.AckNackResult.ACK) { break; } if (anr == PacketLineIn.AckNackResult.ACK_CONTINUE) { _multiAck = true; } if (monitor.IsCancelled) { throw new CancelledException(); } } }