using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using Vinno.IUS.Common.IO; using Vinno.IUS.Common.Log; namespace Vinno.IUS.Common.Network.Transfer { /// /// Message Pool /// public static class MessagePool { private static int _maximumMsgOfEachType = 10; private static bool _enabled; private static readonly object _getMessageLock = new Object(); /// /// get Message pool is or not cached /// public static bool Enabled => _enabled; /// /// Maxinum of messages of each type /// public static int MaximumMessageOfEachType => _maximumMsgOfEachType; private static readonly ConcurrentDictionary MaxSpecialTypeMessageDictionary = new ConcurrentDictionary(); private static readonly ConcurrentDictionary> AvailableMessagePool = new ConcurrentDictionary>(); /// /// Get idle message from message pool /// if all message of type of T is working ,so get new message /// /// Message /// T public static T GetMessage() where T : Message { try { if (Enabled) { if (AvailableMessagePool.TryGetValue(typeof(T), out Stack messageStack)) { lock (_getMessageLock) { if (messageStack.Count > 0) { var message = messageStack?.Pop(); if (message != null) { return message as T; } } } } } } catch (Exception e) { throw new Exception($"{e}"); } return NewMessage(); } private static T NewMessage() where T : Message { var message = Activator.CreateInstance(typeof(T), new object[] { }) as Message; return message as T; } /// /// Release current message /// this message changed busy to idle /// /// public static void Recover(Message message) { if (message == null) { return; } if (Enabled) { try { var messageType = message.GetType(); AvailableMessagePool.AddOrUpdate(messageType, s => { var stack = new Stack(); stack.Push(RevertToMessage(message)); return stack; }, (s, m) => { var maximum = _maximumMsgOfEachType; MaxSpecialTypeMessageDictionary.TryGetValue(messageType.Name, out int? specialMaximum); if (specialMaximum != null) { maximum = specialMaximum.Value; } if (m.Count < maximum) { m.Push(RevertToMessage(message)); } return m; }); } catch (Exception e) { throw new InvalidOperationException($"MessagePool Recover,Error:{e}"); } } } private static Message RevertToMessage(Message message) { var properties = message.GetType().GetProperties(); foreach (var propertyInfo in properties) { if (propertyInfo.CanWrite) { if (propertyInfo.Name == nameof(message.Element) || propertyInfo.Name == nameof(message.Tag)) { continue; } var defaultvalue = GetDefaultValue(propertyInfo.PropertyType); propertyInfo.SetValue(message, defaultvalue); } } return message; } private static object GetDefaultValue(Type type) { object value = null; switch (type.Name) { case nameof(String): value = string.Empty; break; case nameof(Enum): value = default(Enum); break; case nameof(Int32): value = 0; break; case nameof(Int16): value = 0; break; case nameof(Int64): value = 0; break; case nameof(Single): value = 0; break; case nameof(Double): value = 0; break; case nameof(Boolean): value = false; break; case nameof(DateTime): value = default(DateTime); break; case nameof(IBuffer): value = new ByteBuffer(new byte[0]); break; case "Byte[]": value = new byte[0]; break; } return value; } public static void Initialize(IMessagePoolConfig config) { if (config !=null) { _enabled = config.Enabled; _maximumMsgOfEachType = config.MaximumNumberOfMessages; foreach (var key in config.CustomMessageCountDictionary) { MaxSpecialTypeMessageDictionary.GetOrAdd(key.Key, key.Value); } } } } /// /// interface message pool config /// public interface IMessagePoolConfig { /// /// MessagePool Enabled /// bool Enabled { get; } /// /// Maximum number of messages per type /// int MaximumNumberOfMessages { get; } /// /// custom message count,string:message name,int:maximum count of message /// Dictionary CustomMessageCountDictionary { get; } } }