ZhiYeJianKang_PeiXun/cyqdata-master/DistributedCache/CacheImplement/MemRedis/HostNode.cs

396 lines
13 KiB
C#
Raw Normal View History

2025-02-20 15:41:53 +08:00
using CYQ.Data.Tool;
using System;
using System.Collections.Generic;
using System.Threading;
namespace CYQ.Data.Cache
{
/// <summary>
/// The SocketPool encapsulates the list of PooledSockets against one specific host, and contains methods for
/// acquiring or returning PooledSockets.
/// </summary>
internal partial class HostNode : IDisposable
{
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤Ȩ<D6A4>޵<EFBFBD>ί<EFBFBD><CEAF><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
internal delegate bool OnAfterSocketCreateDelegate(MSocket socket);
internal event OnAfterSocketCreateDelegate OnAfterSocketCreateEvent;
#region <EFBFBD>ɶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//Public variables and properties
public readonly string Host;
/// <summary>
/// <20><>չ<EFBFBD><D5B9><EFBFBD>ԣ<EFBFBD><D4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӻ<EFBFBD><D3BA><EFBFBD>Ҫ<EFBFBD><D2AA>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EBA3A8>Redis<69><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public string Password;
//Debug variables and properties
public int NewSockets = 0;
public int CloseSockets = 0;
public int TimeoutFromSocketPool = 0;
public int FailedNewSockets = 0;
public int ReusedSockets = 0;
public int DeadSocketsInPool = 0;
public int DeadSocketsOnReturn = 0;
public int Acquired = 0;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2>
/// </summary>
public string Error;
/// <summary>
/// <20><>ǰ Socket <20>صĿ<D8B5><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public int Poolsize { get { return socketQueue.Count; } }
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5>Dz<EFBFBD><C7B2>ǹ<EFBFBD><C7B9>ˡ<EFBFBD>
/// </summary>
public bool IsEndPointDead = false;
public DateTime DeadEndPointRetryTime;
#endregion
/// <summary>
/// <20><><EFBFBD>ݵ<EFBFBD>Socket<65>أ<EFBFBD><D8A3><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><C4B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˱<EFBFBD><CBB1>ݵ<EFBFBD><DDB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><C2A3><EFBFBD><EFBFBD>ɱ<EFBFBD><C9B1><EFBFBD>Socket<65><74><EFBFBD><EFBFBD><E1B9A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
// public HostNode HostNodeBak;
/// <summary>
/// Socket<65>Ĺҿ<C4B9>ʱ<EFBFBD>
/// </summary>
private DateTime socketDeadTime = DateTime.MinValue;
public int MaxQueue
{
get
{
return hostServer.ServerType == CacheType.Redis ? AppConfig.Redis.MaxSocket : AppConfig.MemCache.MaxSocket;
}
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӻ<EFBFBD><D3BA>ĵȴ<C4B5>ʱ<EFBFBD>
/// </summary>
public int MaxWait
{
get
{
return hostServer.ServerType == CacheType.Redis ? AppConfig.Redis.MaxWait : AppConfig.MemCache.MaxWait;
}
}
public int minQueue = 1;
/// <summary>
/// If the host stops responding, we mark it as dead for this amount of seconds,
/// and we double this for each consecutive failed retry. If the host comes alive
/// again, we reset this to 1 again.
/// </summary>
private int deadEndPointSecondsUntilRetry = 1;
private const int maxDeadEndPointSecondsUntilRetry = 60;
private HostServer hostServer;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public HostServer HostServer
{
get
{
return hostServer;
}
}
private Queue<MSocket> socketQueue = new Queue<MSocket>(32);
internal HostNode(HostServer hostServer, string host)
{
this.hostServer = hostServer;
string[] items = host.Split('-');
Host = items[0].Trim();
if (items.Length > 1)
{
Password = items[1].Trim();
}
}
/// <summary>
/// <20>Ӷ<EFBFBD><D3B6>л<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܽ<EFBFBD><DCBD>еȴ<D0B5><C8B4><EFBFBD>
/// </summary>
/// <param name="wait"></param>
/// <returns></returns>
private MSocket GetFromQueue(int wait)
{
//Do we have free sockets in the pool?
//if so - return the first working one.
//if not - create a new one.
int count = 0;
while (true)
{
count++;
if (socketQueue.Count > 0)
{
MSocket mSocket = null;
lock (socketQueue)
{
if (socketQueue.Count > 0)
{
mSocket = socketQueue.Dequeue();
}
}
if (mSocket != null)
{
if (mSocket.IsAlive)
{
Interlocked.Increment(ref ReusedSockets);
return mSocket;
}
else
{
Interlocked.Increment(ref DeadSocketsInPool);
Interlocked.Increment(ref CloseSockets);
return null;
}
}
}
if (count > wait)
{
return null;
}
Thread.Sleep(1);
}
}
/// <summary>
/// Gets a socket from the pool.
/// If there are no free sockets, a new one will be created. If something goes
/// wrong while creating the new socket, this pool's endpoint will be marked as dead
/// and all subsequent calls to this method will return null until the retry interval
/// has passed.
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>չ<EFBFBD><D5B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳأ<D3B3>
/// </summary>
internal MSocket Acquire()
{
if (IsEndPointDead) { return null; }
//If we know the endpoint is dead, check if it is time for a retry, otherwise return null.
//<2F><><EFBFBD>⵱ǰ<E2B5B1>Ƿ<EFBFBD><C7B7>ҿƣ<D2BF><C6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(15<31><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<29><><EFBFBD>ɱ<EFBFBD><C9B1>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E1B9A9><EFBFBD><EFBFBD>
//if (socketDeadTime.AddMinutes(15) >= DateTime.Now && HostNodeBak != null)
//{
// return HostNodeBak.Acquire();
//}
//else
//{
Interlocked.Increment(ref Acquired);
//}
//<2F>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
MSocket socket = GetFromQueue(0);
if (socket != null) { return socket; }
//<2F><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>ٽ<EFBFBD><D9BD><EFBFBD>
if (NewSockets - CloseSockets >= MaxQueue)
{
//Try to create a new socket. On failure, mark endpoint as dead and return null.
socket = GetFromQueue(MaxWait);
if (socket != null) { return socket; }
Interlocked.Increment(ref TimeoutFromSocketPool);
return null;
}
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E2B2A2>˲ʱ<CBB2><CAB1><EFBFBD><EFBFBD>̫<EFBFBD><CCAB><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><D3A3>˷<EFBFBD><CBB7><EFBFBD>Դ
lock (this)
{
if (NewSockets - CloseSockets < MaxQueue)
{
//If we know the endpoint is dead, check if it is time for a retry, otherwise return null.
if (IsEndPointDead) { return null; }
socket = new MSocket(this, Host);
if (socket.IsAlive)
{
Interlocked.Increment(ref NewSockets);//<2F>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
else
{
Interlocked.Increment(ref FailedNewSockets);//<2F>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
AddToDeadPool();
}
}
}
if (socket == null)
{
if (NewSockets - CloseSockets >= MaxQueue)
{
//Try to create a new socket. On failure, mark endpoint as dead and return null.
socket = GetFromQueue(MaxWait);
if (socket != null) { return socket; }
Interlocked.Increment(ref TimeoutFromSocketPool);
}
return null;
}
if (socket.IsAlive)
{
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><ECB3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD>
if (OnAfterSocketCreateEvent != null)
{
OnAfterSocketCreateEvent(socket);
}
return socket;
}
else
{
Log.Write("Error connecting to: " + Host, LogType.Cache);
return null;
}
}
/// <summary>
/// Returns a socket to the pool.
/// If the socket is dead, it will be destroyed.
/// If there are more than MaxPoolSize sockets in the pool, it will be destroyed.
/// If there are less than MinPoolSize sockets in the pool, it will always be put back.
/// If there are something inbetween those values, the age of the socket is checked.
/// If it is older than the SocketRecycleAge, it is destroyed, otherwise it will be
/// put back in the pool.
/// </summary>
internal void Return(MSocket socket)
{
//If the socket is dead, destroy it.
if (!socket.IsAlive || hasDisponse)
{
Interlocked.Increment(ref DeadSocketsOnReturn);
Interlocked.Increment(ref CloseSockets);
socket.Close();
}
else
{
//Clean up socket
socket.Reset();
//Check pool size.
if (socketQueue.Count >= MaxQueue)
{
//If the pool is full, destroy the socket.
Interlocked.Increment(ref CloseSockets);
socket.Close();
}
else if (socketQueue.Count > minQueue && socket.CreateTime.AddMinutes(10) < DateTime.Now)
{
//socket <20><><EFBFBD>񳬹<EFBFBD><F1B3ACB9><EFBFBD>Сʱ<D0A1>ģ<EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD>ˣ<EFBFBD>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>׸<EFBFBD><D7B8><EFBFBD><EFBFBD><EFBFBD>
//If we have more than the minimum amount of sockets, but less than the max, and the socket is older than the recycle age, we destroy it.
Interlocked.Increment(ref CloseSockets);
socket.Close();
}
else
{
//Put the socket back in the pool.
lock (socketQueue)
{
socketQueue.Enqueue(socket);
}
}
}
}
/// <summary>
/// <20>̳߳<DFB3><CCB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD>
/// </summary>
/// <returns></returns>
internal bool TryConnection()
{
if (DateTime.Now > DeadEndPointRetryTime)
{
MSocket socket = new MSocket(this, Host);
if (socket.IsAlive)
{
IsEndPointDead = false;
deadEndPointSecondsUntilRetry = 1; //Reset retry timer on success.
if (OnAfterSocketCreateEvent != null)
{
OnAfterSocketCreateEvent(socket);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤
}
Return(socket);//<2F><><EFBFBD>˷ѣ<CBB7><D1A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>
return true;
}
else
{
//Retry in 1 minutes
DeadEndPointRetryTime = DateTime.Now.AddSeconds(deadEndPointSecondsUntilRetry);
if (deadEndPointSecondsUntilRetry < maxDeadEndPointSecondsUntilRetry)
{
deadEndPointSecondsUntilRetry += 1; //Double retry interval until next time
}
}
}
return false;
}
static bool isTaskDoing = false;
/// <summary>
/// <20><><EFBFBD>ӹ<EFBFBD><D3B9>Ͻڵ<CFBD>
/// </summary>
/// <param name="hostNode"></param>
public void AddToDeadPool()
{
if (!IsEndPointDead)
{
IsEndPointDead = true;
socketDeadTime = DateTime.Now;
if (!deadNode.ContainsKey(Host))
{
deadNode.Add(Host, this);
}
if (!isTaskDoing)
{
lock (deadNode)
{
isTaskDoing = true;
ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(DoHostNodeTask));
}
}
}
}
#region IDisposable <EFBFBD><EFBFBD>Ա
bool hasDisponse = false;
public void Dispose()
{
hasDisponse = true;
while (socketQueue.Count > 0)
{
socketQueue.Dequeue().Close();
}
}
#endregion
}
internal partial class HostNode
{
/// <summary>
/// <20>ѹ<EFBFBD><D1B9>Ͻڵ<CFBD>
/// </summary>
static MDictionary<string, HostNode> deadNode = new MDictionary<string, HostNode>();
/// <summary>
/// <20>̼߳<DFB3><CCBC><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9>Ͻڵ㡣
/// </summary>
/// <param name="threadID"></param>
static void DoHostNodeTask(object threadID)
{
while (true)
{
Thread.Sleep(1000);
if (deadNode.Count > 0)
{
List<string> keys = deadNode.GetKeys();
foreach (string key in keys)
{
if (deadNode[key].TryConnection())
{
deadNode.Remove(key);
}
}
}
}
}
}
}