/// <summary> /// Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts /// </summary> /// <returns></returns> public IRedisClient GetClient() { try { var poolTimedOut = false; var inactivePoolIndex = -1; lock (writeClients) { AssertValidReadWritePool(); RedisClient inActiveClient; while ((inactivePoolIndex = GetInActiveWriteClient(out inActiveClient)) == -1) { if (PoolTimeout.HasValue) { // wait for a connection, cry out if made to wait too long if (!Monitor.Wait(writeClients, PoolTimeout.Value)) { poolTimedOut = true; break; } } else { Monitor.Wait(writeClients, RecheckPoolAfterMs); } } //inActiveClient != null only for Valid InActive Clients if (inActiveClient != null) { WritePoolIndex++; inActiveClient.Active = true; InitClient(inActiveClient); return(inActiveClient); } } if (poolTimedOut) { throw new TimeoutException(PoolTimeoutError); } //Reaches here when there's no Valid InActive Clients try { //inactivePoolIndex = index of reservedSlot || index of invalid client var existingClient = writeClients[inactivePoolIndex]; if (existingClient != null && existingClient != reservedSlot && existingClient.HadExceptions) { RedisState.DeactivateClient(existingClient); } var newClient = InitNewClient(RedisResolver.CreateMasterClient(inactivePoolIndex)); //Put all blocking I/O or potential Exceptions before lock lock (writeClients) { //If existingClient at inactivePoolIndex changed (failover) return new client outside of pool if (writeClients[inactivePoolIndex] != existingClient) { if (Log.IsDebugEnabled) { Log.Debug("writeClients[inactivePoolIndex] != existingClient: {0}".Fmt(writeClients[inactivePoolIndex])); } return(newClient); //return client outside of pool } WritePoolIndex++; writeClients[inactivePoolIndex] = newClient; return(newClient); } } catch { //Revert free-slot for any I/O exceptions that can throw (before lock) lock (writeClients) { writeClients[inactivePoolIndex] = null; //free slot } throw; } } finally { RedisState.DisposeExpiredClients(); } }
/// <summary> /// Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts /// </summary> /// <returns></returns> public IRedisClient GetClient() { try { var inactivePoolIndex = -1; lock (clients) { AssertValidPool(); RedisClient inActiveClient; //-1 when no available clients otherwise index of reservedSlot or existing Client inactivePoolIndex = GetInActiveClient(out inActiveClient); //inActiveClient != null only for Valid InActive Clients if (inActiveClient != null) { poolIndex++; inActiveClient.Active = true; return(inActiveClient); } } //Reaches here when there's no Valid InActive Clients try { //inactivePoolIndex == -1 || index of reservedSlot || index of invalid client var existingClient = inactivePoolIndex >= 0 && inactivePoolIndex < clients.Length ? clients[inactivePoolIndex] : null; if (existingClient != null && existingClient != reservedSlot && existingClient.HadExceptions) { RedisState.DeactivateClient(existingClient); } var newClient = InitNewClient(RedisResolver.CreateMasterClient(Math.Max(inactivePoolIndex, 0))); //Put all blocking I/O or potential Exceptions before lock lock (clients) { //Create new client outside of pool when max pool size exceeded //Reverting free-slot not needed when -1 since slwo wasn't reserved or //when existingClient changed (failover) since no longer reserver var stillReserved = inactivePoolIndex >= 0 && inactivePoolIndex < clients.Length && clients[inactivePoolIndex] == existingClient; if (inactivePoolIndex == -1 || !stillReserved) { if (Log.IsDebugEnabled) { Log.Debug("clients[inactivePoolIndex] != existingClient: {0}".Fmt(!stillReserved ? "!stillReserved" : "-1")); } Interlocked.Increment(ref RedisState.TotalClientsCreatedOutsidePool); //Don't handle callbacks for new client outside pool newClient.ClientManager = null; return(newClient); } poolIndex++; clients[inactivePoolIndex] = newClient; return(newClient); } } catch { //Revert free-slot for any I/O exceptions that can throw (before lock) lock (clients) { if (inactivePoolIndex >= 0 && inactivePoolIndex < clients.Length) { clients[inactivePoolIndex] = null; } } throw; } } finally { RedisState.DisposeExpiredClients(); } }