protected virtual void Dispose(bool disposing) { if (Interlocked.Increment(ref disposeAttempts) > 1) { return; } if (disposing) { // get rid of managed resources } try { // get rid of unmanaged resources for (var i = 0; i < writeClients.Length; i++) { Dispose(writeClients[i]); } for (var i = 0; i < readClients.Length; i++) { Dispose(readClients[i]); } } catch (Exception ex) { Log.Error("Error when trying to dispose of PooledRedisClientManager", ex); } RedisState.DisposeAllDeactivatedClients(); }
public void FailoverTo(params string[] readWriteHosts) { Interlocked.Increment(ref RedisState.TotalFailovers); lock (clients) { for (var i = 0; i < clients.Length; i++) { var redis = clients[i]; if (redis != null) { RedisState.DeactivateClient(redis); } clients[i] = null; } RedisResolver.ResetMasters(readWriteHosts); } if (this.OnFailover != null) { foreach (var callback in OnFailover) { try { callback(this); } catch (Exception ex) { Log.Error("Error firing OnFailover callback(): ", ex); } } } }
public void FailoverTo(IEnumerable <string> readWriteHosts, IEnumerable <string> readOnlyHosts) { Interlocked.Increment(ref RedisState.TotalFailovers); lock (readClients) { for (var i = 0; i < readClients.Length; i++) { var redis = readClients[i]; if (redis != null) { RedisState.DeactivateClient(redis); } readClients[i] = null; } RedisResolver.ResetSlaves(readOnlyHosts); } lock (writeClients) { for (var i = 0; i < writeClients.Length; i++) { var redis = writeClients[i]; if (redis != null) { RedisState.DeactivateClient(redis); } writeClients[i] = null; } RedisResolver.ResetMasters(readWriteHosts); } if (this.OnFailover != null) { foreach (var callback in OnFailover) { try { callback(this); } catch (Exception ex) { Log.Error("Error firing OnFailover callback(): ", ex); } } } }
/// <summary> /// Returns a ReadOnly client using the hosts defined in ReadOnlyHosts. /// </summary> /// <returns></returns> public virtual IRedisClient GetReadOnlyClient() { try { var poolTimedOut = false; var inactivePoolIndex = -1; lock (readClients) { AssertValidReadOnlyPool(); RedisClient inActiveClient; while ((inactivePoolIndex = GetInActiveReadClient(out inActiveClient)) == -1) { if (PoolTimeout.HasValue) { // wait for a connection, break out if made to wait too long if (!Monitor.Wait(readClients, PoolTimeout.Value)) { poolTimedOut = true; break; } } else { Monitor.Wait(readClients, RecheckPoolAfterMs); } } //inActiveClient != null only for Valid InActive Clients if (inActiveClient != null) { ReadPoolIndex++; 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 = readClients[inactivePoolIndex]; if (existingClient != null && existingClient != reservedSlot && existingClient.HadExceptions) { RedisState.DeactivateClient(existingClient); } var newClient = InitNewClient(RedisResolver.CreateSlaveClient(inactivePoolIndex)); //Put all blocking I/O or potential Exceptions before lock lock (readClients) { //If existingClient at inactivePoolIndex changed (failover) return new client outside of pool if (readClients[inactivePoolIndex] != existingClient) { if (Log.IsDebugEnabled) { Log.Debug("readClients[inactivePoolIndex] != existingClient: {0}".Fmt(readClients[inactivePoolIndex])); } Interlocked.Increment(ref RedisState.TotalClientsCreatedOutsidePool); //Don't handle callbacks for new client outside pool newClient.ClientManager = null; return(newClient); //return client outside of pool } ReadPoolIndex++; readClients[inactivePoolIndex] = newClient; return(newClient); } } catch { //Revert free-slot for any I/O exceptions that can throw lock (readClients) { readClients[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 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(); } }