Inheritance: IRedisResolver, IRedisResolverExtended
Exemple #1
0
        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);
                    }
                }
            }
        }
Exemple #2
0
        public RedisManagerPool(IEnumerable <string> hosts, RedisPoolConfig config)
        {
            if (hosts == null)
            {
                throw new ArgumentNullException(nameof(hosts));
            }

            RedisResolver = new RedisResolver(hosts, null);

            if (config == null)
            {
                config = new RedisPoolConfig();
            }

            this.OnFailover = new List <Action <IRedisClientsManager> >();

            this.MaxPoolSize = config.MaxPoolSize;

            clients   = new RedisClient[MaxPoolSize];
            poolIndex = 0;

            this.AssertAccessOnlyOnSameThread = RedisConfig.AssertAccessOnlyOnSameThread;

            JsConfig.InitStatics();
        }
Exemple #3
0
        public void FailoverTo(IEnumerable <string> readWriteHosts, IEnumerable <string> readOnlyHosts)
        {
            Interlocked.Increment(ref RedisState.TotalFailovers);

            var masters  = readWriteHosts.ToList();
            var replicas = readOnlyHosts.ToList();

            Log.Info($"FailoverTo: {string.Join(",", masters)} : {string.Join(",", replicas)} Total: {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(replicas);
            }

            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(masters);
            }

            if (this.OnFailover != null)
            {
                foreach (var callback in OnFailover)
                {
                    try
                    {
                        callback(this);
                    }
                    catch (Exception ex)
                    {
                        Log.Error("Error firing OnFailover callback(): ", ex);
                    }
                }
            }
        }
        public RedisManagerPool(IEnumerable<string> hosts, RedisPoolConfig config)
        {
            if (hosts == null)
                throw new ArgumentNullException("hosts");

            RedisResolver = new RedisResolver(hosts, null);

            if (config == null)
                config = new RedisPoolConfig();

            this.OnFailover = new List<Action<IRedisClientsManager>>();

            this.MaxPoolSize = config.MaxPoolSize;

            clients = new RedisClient[MaxPoolSize];
            poolIndex = 0;
        }
Exemple #5
0
        public PooledRedisClientManager(
            IEnumerable <string> readWriteHosts,
            IEnumerable <string> readOnlyHosts,
            RedisClientManagerConfig config,
            long?initalDb,
            int?poolSizeMultiplier,
            int?poolTimeOutSeconds)
        {
            this.Db = config != null
                ? config.DefaultDb ?? initalDb
                : initalDb;

            var masters  = (readWriteHosts ?? TypeConstants.EmptyStringArray).ToArray();
            var replicas = (readOnlyHosts ?? TypeConstants.EmptyStringArray).ToArray();

            RedisResolver = new RedisResolver(masters, replicas);

            this.PoolSizeMultiplier = poolSizeMultiplier ?? 20;

            this.Config = config ?? new RedisClientManagerConfig
            {
                MaxWritePoolSize = RedisConfig.DefaultMaxPoolSize ?? masters.Length * PoolSizeMultiplier,
                MaxReadPoolSize  = RedisConfig.DefaultMaxPoolSize ?? replicas.Length * PoolSizeMultiplier,
            };

            this.OnFailover = new List <Action <IRedisClientsManager> >();

            // if timeout provided, convert into milliseconds
            this.PoolTimeout = poolTimeOutSeconds != null
                ? poolTimeOutSeconds * 1000
                : 2000; //Default Timeout

            this.AssertAccessOnlyOnSameThread = RedisConfig.AssertAccessOnlyOnSameThread;

            JsConfig.InitStatics();

            if (this.Config.AutoStart)
            {
                this.OnStart();
            }
        }
        public RedisManagerPool(IEnumerable <string> hosts, RedisPoolConfig config)
        {
            if (hosts == null)
            {
                throw new ArgumentNullException("hosts");
            }

            RedisResolver = new RedisResolver(hosts, null);

            if (config == null)
            {
                config = new RedisPoolConfig();
            }

            this.OnFailover = new List <Action <IRedisClientsManager> >();

            this.MaxPoolSize = config.MaxPoolSize;

            clients   = new RedisClient[MaxPoolSize];
            poolIndex = 0;
        }
        public PooledRedisClientManager(
            IEnumerable <string> readWriteHosts,
            IEnumerable <string> readOnlyHosts,
            RedisClientManagerConfig config,
            long?initalDb,
            int?poolSizeMultiplier,
            int?poolTimeOutSeconds)
        {
            this.Db = config != null
                ? config.DefaultDb ?? initalDb
                : initalDb;

            var masters = (readWriteHosts ?? new string[0]).ToArray();
            var slaves  = (readOnlyHosts ?? new string[0]).ToArray();

            RedisResolver = new RedisResolver(masters, slaves);

            this.PoolSizeMultiplier = poolSizeMultiplier ?? 10;

            this.Config = config ?? new RedisClientManagerConfig
            {
                MaxWritePoolSize = masters.Length * PoolSizeMultiplier,
                MaxReadPoolSize  = slaves.Length * PoolSizeMultiplier,
            };

            this.OnFailover = new List <Action <IRedisClientsManager> >();

            // if timeout provided, convert into milliseconds
            this.PoolTimeout = poolTimeOutSeconds != null
                ? poolTimeOutSeconds * 1000
                : 2000; //Default Timeout


            if (this.Config.AutoStart)
            {
                this.OnStart();
            }
        }
Exemple #8
0
        /// <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();
            }
        }
Exemple #9
0
        /// <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();
            }
        }
Exemple #10
0
        /// <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(!AssertAccessOnlyOnSameThread
                            ? inActiveClient
                            : inActiveClient.LimitAccessToThread(Thread.CurrentThread.ManagedThreadId, Environment.StackTrace));
                    }
                }

                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(!AssertAccessOnlyOnSameThread
                            ? newClient
                            : newClient.LimitAccessToThread(Thread.CurrentThread.ManagedThreadId, Environment.StackTrace));
                    }
                }
                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();
            }
        }
        private async ValueTask <IRedisClientAsync> GetClientAsync()
        {
            try
            {
                var inactivePoolIndex = -1;
                do
                {
                    RedisClient inActiveClient;
                    lock (writeClients)
                    {
                        AssertValidReadWritePool();

                        // If it's -1, then we want to try again after a delay of some kind. So if it's NOT negative one, process it...
                        if ((inactivePoolIndex = GetInActiveWriteClient(out inActiveClient)) != -1)
                        {
                            //inActiveClient != null only for Valid InActive Clients
                            if (inActiveClient != null)
                            {
                                WritePoolIndex++;
                                inActiveClient.Activate();

                                InitClient(inActiveClient);

                                return(inActiveClient);
                            }
                            else
                            {
                                // Still need to be in lock for this!
                                break;
                            }
                        }
                    }

                    if (PoolTimeout.HasValue)
                    {
                        // We have a timeout value set - so try to not wait longer than this.
                        if (!await waitForWriter(PoolTimeout.Value))
                        {
                            throw new TimeoutException(PoolTimeoutError);
                        }
                    }
                    else
                    {
                        // Wait forever, so just retry till we get one.
                        await waitForWriter(RecheckPoolAfterMs);
                    }
                } while (true); // Just keep repeating until we get a slot.

                //Reaches here when there's no Valid InActive Clients, but we have a slot for one!
                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((!AssertAccessOnlyOnSameThread)
                            ? newClient
                            : newClient.LimitAccessToThread(Thread.CurrentThread.ManagedThreadId, Environment.StackTrace));
                    }
                }
                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();
            }
        }