/// <summary> /// Initialise a ChunkDataWrapper when the ChunkAvailabilityReply is received before associated data. /// </summary> /// <param name="chunkAvailabilityReply">The matching ChunkAvailabilityReply</param> public ChunkDataWrapper(ChunkAvailabilityReply chunkAvailabilityReply) { if (chunkAvailabilityReply == null) { throw new Exception("Unable to create a ChunkDataWrapper with a null ChunkAvailabilityReply reference."); } this.ChunkAvailabilityReply = chunkAvailabilityReply; this.TimeCreated = DateTime.Now; }
/// <summary> /// Initialise a ChunkDataWrapper when the ChunkAvailabilityReply is received before associated data. /// </summary> /// <param name="chunkAvailabilityReply">The matching ChunkAvailabilityReply</param> public ChunkDataWrapper(ChunkAvailabilityReply chunkAvailabilityReply) { if (chunkAvailabilityReply == null) throw new Exception("Unable to create a ChunkDataWrapper with a null ChunkAvailabilityReply reference."); this.ChunkAvailabilityReply = chunkAvailabilityReply; this.TimeCreated = DateTime.Now; }
/// <summary> /// UDP and TCP - Received when a peer sends us a chunk data information possibly following a request /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="incomingReply"></param> private static void IncomingChunkInterestReplyInfo(PacketHeader packetHeader, Connection connection, ChunkAvailabilityReply incomingReply) { try { ConnectionInfo incomingConnectionInfo = new ConnectionInfo(connection.ConnectionInfo.ConnectionType, incomingReply.SourceNetworkIdentifier, connection.ConnectionInfo.RemoteEndPoint, true); if (DFS.loggingEnabled) DFS._DFSLogger.Trace("IncomingChunkInterestReplyInfo from " + connection + " for item " + incomingReply.ItemCheckSum + ", chunkIndex " + incomingReply.ChunkIndex + "."); if (incomingReply.ReplyState == ChunkReplyState.DataIncluded && incomingReply.PacketIdentifier == null) throw new ArgumentNullException("The specified packet identifier cannot be null."); DistributedItem item = null; lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(incomingReply.ItemCheckSum)) item = swarmedItemsDict[incomingReply.ItemCheckSum]; } if (item != null) { //Do we have the data yet? bool handleReply = false; lock (chunkDataCacheLocker) { //We generally expect the data to arrive first, but we handle both situations anyway //Realistic testing across a 100MB connection shows that we already have the data 90.1% of the time if (incomingReply.ReplyState == ChunkReplyState.DataIncluded && chunkDataCache.ContainsKey(incomingReply.SourceNetworkIdentifier) && chunkDataCache[incomingReply.SourceNetworkIdentifier].ContainsKey(incomingReply.PacketIdentifier)) { incomingReply.SetChunkData(chunkDataCache[incomingReply.SourceNetworkIdentifier][incomingReply.PacketIdentifier].Data); chunkDataCache[incomingReply.SourceNetworkIdentifier].Remove(incomingReply.PacketIdentifier); if (DFS.loggingEnabled) DFS._DFSLogger.Debug("Completed ChunkAvailabilityReply using data in chunkDataCache from " + connection + ", packet identifier:" + incomingReply.PacketIdentifier + "."); if (chunkDataCache[incomingReply.SourceNetworkIdentifier].Count == 0) chunkDataCache.Remove(incomingReply.SourceNetworkIdentifier); } else if (incomingReply.ReplyState == ChunkReplyState.DataIncluded) { //We have beaten the data, we will add the chunk availability reply instead and wait, letting the incoming data trigger the handle if (!chunkDataCache.ContainsKey(incomingReply.SourceNetworkIdentifier)) chunkDataCache.Add(incomingReply.SourceNetworkIdentifier, new Dictionary<string,ChunkDataWrapper>()); chunkDataCache[incomingReply.SourceNetworkIdentifier].Add(incomingReply.PacketIdentifier, new ChunkDataWrapper(incomingReply)); if (DFS.loggingEnabled) DFS._DFSLogger.Debug("Added ChunkAvailabilityReply to chunkDataCache (awaiting data) from " + connection + ", packet identifier:" + incomingReply.PacketIdentifier + "."); } //We decide if we are going to handle the data within the lock to avoid possible handle contention if (incomingReply.ChunkDataSet || incomingReply.ReplyState != ChunkReplyState.DataIncluded) handleReply = true; } if (handleReply) { incomingReply.SetSourceConnectionInfo(incomingConnectionInfo); item.HandleIncomingChunkReply(incomingReply); } } } catch (Exception e) { LogTools.LogException(e, "Error_IncomingChunkInterestReplyInfo"); } }