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");
}
}