/Lidgren.Network/NetPeer.MessagePools.cs

http://lidgren-network-gen3.googlecode.com/ · C# · 228 lines · 180 code · 25 blank · 23 comment · 37 complexity · c1a1026bea2b9d77bfe79d108aaf646f MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace Lidgren.Network
  5. {
  6. public partial class NetPeer
  7. {
  8. private List<byte[]> m_storagePool; // sorted smallest to largest
  9. private NetQueue<NetOutgoingMessage> m_outgoingMessagesPool;
  10. private NetQueue<NetIncomingMessage> m_incomingMessagesPool;
  11. internal int m_storagePoolBytes;
  12. private void InitializePools()
  13. {
  14. if (m_configuration.UseMessageRecycling)
  15. {
  16. m_storagePool = new List<byte[]>(16);
  17. m_outgoingMessagesPool = new NetQueue<NetOutgoingMessage>(4);
  18. m_incomingMessagesPool = new NetQueue<NetIncomingMessage>(4);
  19. }
  20. else
  21. {
  22. m_storagePool = null;
  23. m_outgoingMessagesPool = null;
  24. m_incomingMessagesPool = null;
  25. }
  26. }
  27. internal byte[] GetStorage(int minimumCapacityInBytes)
  28. {
  29. if (m_storagePool == null)
  30. return new byte[minimumCapacityInBytes];
  31. lock (m_storagePool)
  32. {
  33. for (int i = 0; i < m_storagePool.Count; i++)
  34. {
  35. byte[] retval = m_storagePool[i];
  36. if (retval != null && retval.Length >= minimumCapacityInBytes)
  37. {
  38. m_storagePool[i] = null;
  39. m_storagePoolBytes -= retval.Length;
  40. return retval;
  41. }
  42. }
  43. }
  44. m_statistics.m_bytesAllocated += minimumCapacityInBytes;
  45. return new byte[minimumCapacityInBytes];
  46. }
  47. internal void Recycle(byte[] storage)
  48. {
  49. if (m_storagePool == null)
  50. return;
  51. lock (m_storagePool)
  52. {
  53. m_storagePoolBytes += storage.Length;
  54. int cnt = m_storagePool.Count;
  55. for (int i = 0; i < cnt; i++)
  56. {
  57. if (m_storagePool[i] == null)
  58. {
  59. m_storagePool[i] = storage;
  60. return;
  61. }
  62. }
  63. m_storagePool.Add(storage);
  64. }
  65. }
  66. /// <summary>
  67. /// Creates a new message for sending
  68. /// </summary>
  69. public NetOutgoingMessage CreateMessage()
  70. {
  71. return CreateMessage(m_configuration.m_defaultOutgoingMessageCapacity);
  72. }
  73. /// <summary>
  74. /// Creates a new message for sending and writes the provided string to it
  75. /// </summary>
  76. public NetOutgoingMessage CreateMessage(string content)
  77. {
  78. byte[] bytes = Encoding.UTF8.GetBytes(content);
  79. NetOutgoingMessage om = CreateMessage(2 + bytes.Length);
  80. om.WriteVariableUInt32((uint)bytes.Length);
  81. om.Write(bytes);
  82. return om;
  83. }
  84. /// <summary>
  85. /// Creates a new message for sending
  86. /// </summary>
  87. /// <param name="initialCapacity">initial capacity in bytes</param>
  88. public NetOutgoingMessage CreateMessage(int initialCapacity)
  89. {
  90. NetOutgoingMessage retval;
  91. if (m_outgoingMessagesPool == null || !m_outgoingMessagesPool.TryDequeue(out retval))
  92. retval = new NetOutgoingMessage();
  93. byte[] storage = GetStorage(initialCapacity);
  94. retval.m_data = storage;
  95. return retval;
  96. }
  97. internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, byte[] useStorageData)
  98. {
  99. NetIncomingMessage retval;
  100. if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval))
  101. retval = new NetIncomingMessage(tp);
  102. else
  103. retval.m_incomingMessageType = tp;
  104. retval.m_data = useStorageData;
  105. return retval;
  106. }
  107. internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, int minimumByteSize)
  108. {
  109. NetIncomingMessage retval;
  110. if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval))
  111. retval = new NetIncomingMessage(tp);
  112. else
  113. retval.m_incomingMessageType = tp;
  114. retval.m_data = GetStorage(minimumByteSize);
  115. return retval;
  116. }
  117. /// <summary>
  118. /// Recycles a NetIncomingMessage instance for reuse; taking pressure off the garbage collector
  119. /// </summary>
  120. public void Recycle(NetIncomingMessage msg)
  121. {
  122. if (m_incomingMessagesPool == null)
  123. return;
  124. #if DEBUG
  125. if (m_incomingMessagesPool.Contains(msg))
  126. throw new NetException("Recyling already recycled message! Thread race?");
  127. #endif
  128. byte[] storage = msg.m_data;
  129. msg.m_data = null;
  130. Recycle(storage);
  131. msg.Reset();
  132. m_incomingMessagesPool.Enqueue(msg);
  133. }
  134. /// <summary>
  135. /// Recycles a list of NetIncomingMessage instances for reuse; taking pressure off the garbage collector
  136. /// </summary>
  137. public void Recycle(IEnumerable<NetIncomingMessage> toRecycle)
  138. {
  139. if (m_incomingMessagesPool == null)
  140. return;
  141. // first recycle the storage of each message
  142. if (m_storagePool != null)
  143. {
  144. lock (m_storagePool)
  145. {
  146. foreach (var msg in toRecycle)
  147. {
  148. var storage = msg.m_data;
  149. msg.m_data = null;
  150. m_storagePoolBytes += storage.Length;
  151. int cnt = m_storagePool.Count;
  152. for (int i = 0; i < cnt; i++)
  153. {
  154. if (m_storagePool[i] == null)
  155. {
  156. m_storagePool[i] = storage;
  157. return;
  158. }
  159. }
  160. msg.Reset();
  161. m_storagePool.Add(storage);
  162. }
  163. }
  164. }
  165. // then recycle the message objects
  166. m_incomingMessagesPool.Enqueue(toRecycle);
  167. }
  168. internal void Recycle(NetOutgoingMessage msg)
  169. {
  170. if (m_outgoingMessagesPool == null)
  171. return;
  172. #if DEBUG
  173. if (m_outgoingMessagesPool.Contains(msg))
  174. throw new NetException("Recyling already recycled message! Thread race?");
  175. #endif
  176. byte[] storage = msg.m_data;
  177. msg.m_data = null;
  178. // message fragments cannot be recycled
  179. // TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them
  180. if (msg.m_fragmentGroup == 0)
  181. Recycle(storage);
  182. msg.Reset();
  183. m_outgoingMessagesPool.Enqueue(msg);
  184. }
  185. /// <summary>
  186. /// Creates an incoming message with the required capacity for releasing to the application
  187. /// </summary>
  188. internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, string text)
  189. {
  190. NetIncomingMessage retval;
  191. if (string.IsNullOrEmpty(text))
  192. {
  193. retval = CreateIncomingMessage(tp, 1);
  194. retval.Write(string.Empty);
  195. return retval;
  196. }
  197. int numBytes = System.Text.Encoding.UTF8.GetByteCount(text);
  198. retval = CreateIncomingMessage(tp, numBytes + (numBytes > 127 ? 2 : 1));
  199. retval.Write(text);
  200. return retval;
  201. }
  202. }
  203. }