Esempio n. 1
0
            public IEnumerable <TResult> Read <TResult>(Func <RedisResult, TResult> selector)
            {
                var pending = ReadNext(0, false);

                // need to wait for the first one
                connection.Wait(pending);
                do
                {
                    var  current = pending.Result;
                    long cursor  = current.ValueItems[0].ValueInt64;
                    var  rows    = current.ValueItems[1].ValueItems;
                    // kick off the next immediately, but don't wait for it yet
                    pending = ReadNext(cursor, true);

                    // now we can iterate the rows
                    for (int i = 0; i < rows.Length; i++)
                    {
                        yield return(selector(rows[i]));
                    }

                    // wait for the next, if any
                    if (pending != null)
                    {
                        connection.Wait(pending);
                    }
                } while (pending != null);
            }
        public RedisActivityMonitorTests()
        {
            redis = new RedisConnection("localhost", allowAdmin: true);
            sut = new RedisActivityMonitor(redis);
            redis.Wait(redis.Open());

            redis.Wait(redis.Server.FlushDb(0));
        }
Esempio n. 3
0
 public void CanNotOpenNonsenseConnection_IP()
 {
     using (var conn = new RedisConnection(Config.LocalHost, 6500))
     {
         conn.Wait(conn.Open());
     }
 }
Esempio n. 4
0
        public RedisConnection GetOpen()
        {
            lock (syncConnection)
            {
                if (_Connection != null && !(_Connection.State == RedisConnectionBase.ConnectionState.Closed || _Connection.State == RedisConnectionBase.ConnectionState.Closing))
                {
                    return _Connection;
                }

                if (_Connection == null || (_Connection.State == RedisConnectionBase.ConnectionState.Closed || _Connection.State == RedisConnectionBase.ConnectionState.Closing))
                {
                    try
                    {
                        RoqueTrace.Source.Trace(TraceEventType.Information, "[REDIS] connecting to {0}:{1}", _Host, _Port);

                        _Connection = new RedisConnection(_Host, _Port, _Timeout);
                        var openAsync = _Connection.Open();
                        _Connection.Wait(openAsync);

                        RoqueTrace.Source.Trace(TraceEventType.Information, "[REDIS] connected");
                    }
                    catch (Exception ex)
                    {
                        RoqueTrace.Source.Trace(TraceEventType.Error, "[REDIS] error connecting to {0}:{1}, {2}", _Host, _Port, ex.Message, ex);
                        throw;
                    }
                }
                return _Connection;
            }
        }
Esempio n. 5
0
 public void CanNotOpenNonsenseConnection()
 {
     using (var conn = new RedisConnection("127.0.0.1", 6500))
     {
         conn.Wait(conn.Open());
     }
 }
Esempio n. 6
0
 public void CanNotOpenNonsenseConnection_DNS()
 {
     using (var conn = new RedisConnection("doesnot.exist.ds.aasd981230d.com", 6500))
     {
         conn.Wait(conn.Open());
     }
 }
            public TestPackage(RedisConnection conn)
            {
                Redis = new RedisBooksleeveConnector(conn);
                var redisFS = new Resque.FailureService(new RedisBackendFactory(Redis));
                UnderTest = new Resque.Resque(new JobCreator(), redisFS, Redis);


                conn.Wait(conn.Keys.Remove(0, Redis.KeyInNamespace("queue:testQueue")));
            }
Esempio n. 8
0
        /// <summary>
        ///     Prompt all clients to reconnect.
        /// </summary>
        public static void BroadcastReconnectMessage(RedisConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            connection.Wait(connection.Publish(RedisMasterChangedChannel, "*"));
        }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters( GlobalFilters.Filters );
            RegisterRoutes( RouteTable.Routes );


            var redis = new RedisConnection( "localhost" );
            redis.Wait( redis.Open() );

            Application[ "RedisConnection" ] = redis;
        }
        public void should_create_queue_if_it_does_not_exist()
        {
            var testQueue = "testQueue";
            using (var conn = new RedisConnection("localhost"))
            {
                conn.Open();
                var package = new TestPackage(conn);

                package.UnderTest.Push(testQueue, "Testing");

                Assert.IsTrue(conn.Wait(conn.Keys.Exists(0, package.Redis.KeyInNamespace("queue:"+testQueue))));
            }
        }
		public List<string> Get(string prefix)
		{
			List<string> ret = new List<string>();
			RedisConnection connection = new RedisConnection(
				host: DemoSettings.CustomerRedisCache.Url, 
				password: DemoSettings.CustomerRedisCache.Password);
			connection.Open();
			var list = connection.Wait(connection.Keys.Find(0, "cust:" + prefix.Replace(' ', ':') + "*"));
			for (int i = 0; i < Math.Min(5, list.Length); i++)
			{
				ret.Add(list[i].Substring(5).Replace(':', ' '));
			}
			connection.Close(false);
			return ret;
		}
Esempio n. 12
0
        private static RedisConnection GetOpenConnection()
        {
            var connectionString = ConfigurationManager.AppSettings["REDISTOGO_URL"];
            var uri = new Uri(connectionString);
            var password = uri.UserInfo.Split(':').LastOrDefault();

            var conn = new RedisConnection(uri.Host, uri.Port, password: password, allowAdmin: false,
                                           syncTimeout: DefaultTimeout, ioTimeout: DefaultTimeout);

            conn.Error += (sender, e) => Logger.ErrorException(e.Cause, e.Exception);

            conn.Wait(conn.Open());

            return conn;
        }
		public List<string> Get(string prefix, string category)
		{
			List<string> ret = new List<string>();
			RedisConnection connection = new RedisConnection(
				host: DemoSettings.ProductsRedisCache.Url,
				password: DemoSettings.ProductsRedisCache.Password);
			connection.Open();
			var list = connection.Wait(connection.Keys.Find(0, "prod:" + category + ":" + prefix.Replace(' ', ':') + "*"));
			for (int i = 0; i < Math.Min(5, list.Length); i++)
			{
				string s = list[i].Substring(5);
				s = s.Substring(s.IndexOf(':') + 1);
				ret.Add(s.Replace(':', ' '));
			}
			connection.Close(false);
			return ret;
		}
        public void should_add_item_to_queue()
        {
            var testQueue = "testQueue";
            var item = new QueuedItem()
                               {
                                   @class = "Testing"
                               };
            using (var conn = new RedisConnection("localhost"))
            {
                conn.Open();
                var package = new TestPackage(conn);
                package.UnderTest.Push(testQueue, item.@class, item.args);

                var test = conn.Wait(conn.Lists.RemoveLastString(0, package.Redis.KeyInNamespace("queue:" + testQueue)));

                Assert.AreEqual(item.ToJson(), test);
            }
        }
        public static void Main(string[] args)
        {
            var time = new DateTime(2013, 11, 11, 10, 30, 0);
            var redis = new RedisConnection("localhost");
            redis.Wait(redis.Open());

            var activity = new RedisActivityMonitor(redis);

            // Normal activity.
            activity.Beacon("documents:1", time.AddSeconds(-15), 1, "John");
            activity.Beacon("documents:1", time, 2, "Sue");
            activity.Beacon("documents:1", time.AddSeconds(5), 3, "Mary");
            PrintAll(activity, "documents:1", time.AddSeconds(23));

            // Ignore duplicates.
            activity.Beacon("documents:2", time, 1, "John");
            activity.Beacon("documents:2", time.AddSeconds(5), 1, "John");
            PrintAll(activity, "documents:2", time.AddSeconds(7));

            redis.Close(abort: true);

            Console.Read();
        }
Esempio n. 16
0
 private static RedisConnection GetOldStyleConnection(string host, int port, bool open = true, bool allowAdmin = false, bool waitForOpen = false, int syncTimeout = 5000, int ioTimeout = 5000)
 {
     var conn = new RedisConnection(host, port, syncTimeout: syncTimeout, ioTimeout: ioTimeout, allowAdmin: allowAdmin);
     conn.Error += (s, args) =>
     {
         Trace.WriteLine(args.Exception.Message, args.Cause);
     };
     if (open)
     {
         var openAsync = conn.Open();
         if (waitForOpen) conn.Wait(openAsync);
     }
     return conn;
 }
Esempio n. 17
0
        private void TestSubscriberNameOnRemote(bool setName)
        {
            string id = Config.CreateUniqueName();

            using (var pub = new RedisConnection(Config.RemoteHost, allowAdmin: true))
            using (var sub = new RedisSubscriberConnection(Config.RemoteHost))
            {
                List<string> errors = new List<string>();
                EventHandler<BookSleeve.ErrorEventArgs> errorHandler = (sender, args) =>
                {
                    lock (errors) errors.Add(args.Exception.Message);
                };
                pub.Error += errorHandler;
                sub.Error += errorHandler;

                if (setName)
                {
                    pub.Name = "pub_" + id;
                    sub.Name = "sub_" + id;
                }
                int count = 0;
                var subscribe = sub.Subscribe("foo"+id, (key,payload) => Interlocked.Increment(ref count));

                Task pOpen = pub.Open(), sOpen = sub.Open();
                pub.WaitAll(pOpen, sOpen, subscribe);

                Assert.AreEqual(0, Interlocked.CompareExchange(ref count, 0, 0), "init message count");
                pub.Wait(pub.Publish("foo" + id, "hello"));

                PubSub.AllowReasonableTimeToPublishAndProcess();
                var clients = setName ? pub.Wait(pub.Server.ListClients()) : null;
                Assert.AreEqual(1, Interlocked.CompareExchange(ref count, 0, 0), "got message");
                lock (errors)
                {
                    foreach (var error in errors)
                    {
                        Console.WriteLine(error);
                    }
                    Assert.AreEqual(0, errors.Count, "zero errors");
                }
                if (setName)
                {
                    Assert.AreEqual(1, clients.Count(x => x.Name == pub.Name), "pub has name");
                    Assert.AreEqual(1, clients.Count(x => x.Name == sub.Name), "sub has name");
                }
            }
        }
Esempio n. 18
0
        internal static RedisConnection GetConnection()
        {
            var result = new RedisConnection("127.0.0.1");

            result.Error += (s, e) => Trace.WriteLine(e.Exception.Message, e.Cause);
            result.Wait(result.Open());

            return result;
        }
Esempio n. 19
0
 internal static RedisConnection GetUnsecuredConnection(bool open = true, bool allowAdmin = false, bool waitForOpen = false)
 {
     var conn = new RedisConnection(host, unsecuredPort, syncTimeout: 5000, ioTimeout: 5000, allowAdmin: allowAdmin);
     conn.Error += (s, args) =>
     {
         Trace.WriteLine(args.Exception.Message, args.Cause);
     };
     if (open)
     {
         var openAsync = conn.Open();
         if (waitForOpen) conn.Wait(openAsync);
     }
     return conn;
 }
Esempio n. 20
0
        protected RedisConnection GetOpenConnection()
        {
            lock (syncConnection)
            {
                if (_Connection != null && !(_Connection.State == RedisConnectionBase.ConnectionState.Closed || _Connection.State == RedisConnectionBase.ConnectionState.Closing))
                {
                    return _Connection;
                }

                if (_Connection == null || (_Connection.State == RedisConnectionBase.ConnectionState.Closed || _Connection.State == RedisConnectionBase.ConnectionState.Closing))
                {
                    string host = null;
                    int port = 0;
                    try
                    {
                        if (!Settings.TryGet("host", out host))
                        {
                            throw new Exception("Redis host is required");
                        }
                        port = Settings.Get("port", 6379);
                        EnqueueTimeoutSeconds = Settings.Get("enqueueTimeoutSeconds", 5);

                        _Connection = new RedisConnection(host, port);
                        var openAsync = _Connection.Open();
                        _Connection.Wait(openAsync);
                        if (Roque.Core.RoqueTrace.Switch.TraceInfo)
                        {
                            Trace.TraceInformation(string.Format("[REDIS] connected to {0}:{1}", host, port));
                        }
                    }
                    catch (Exception ex)
                    {
                        if (Roque.Core.RoqueTrace.Switch.TraceError)
                        {
                            Trace.TraceError(
                                string.Format("[REDIS] error connecting to {0}:{1}, {2}", host, port, ex.Message), ex);
                        }
                        throw;
                    }
                }
                return _Connection;
            }
        }
Esempio n. 21
0
        private static RedisConnection SelectAndCreateConnection(string configuration, TextWriter log,
                                                                 out string selectedConfiguration,
                                                                 out string[] availableEndpoints, bool autoMaster,
                                                                 string newMaster = null, string tieBreakerKey = null)
        {
            if (tieBreakerKey == null)
            {
                tieBreakerKey = "__Booksleeve_TieBreak";                        // default tie-breaker key
            }
            int    syncTimeout;
            bool   allowAdmin;
            string serviceName;
            string clientName;

            if (log == null)
            {
                log = new StringWriter();
            }
            string[] arr = GetConfigurationOptions(configuration, out syncTimeout, out allowAdmin, out serviceName,
                                                   out clientName);
            if (!string.IsNullOrWhiteSpace(newMaster))
            {
                allowAdmin = true;                                        // need this to diddle the slave/master config
            }
            log.WriteLine("{0} unique nodes specified", arr.Length);
            log.WriteLine("sync timeout: {0}ms, admin commands: {1}", syncTimeout,
                          allowAdmin ? "enabled" : "disabled");
            if (!string.IsNullOrEmpty(serviceName))
            {
                log.WriteLine("service: {0}", serviceName);
            }
            if (!string.IsNullOrEmpty(clientName))
            {
                log.WriteLine("client: {0}", clientName);
            }
            if (arr.Length == 0)
            {
                log.WriteLine("No nodes to consider");
                selectedConfiguration = null;
                availableEndpoints    = new string[0];
                return(null);
            }
            var             connections = new List <RedisConnection>(arr.Length);
            RedisConnection preferred   = null;

            try
            {
                var infos       = new List <Task <string> >(arr.Length);
                var tiebreakers = new List <Task <string> >(arr.Length);
                foreach (string option in arr)
                {
                    if (string.IsNullOrWhiteSpace(option))
                    {
                        continue;
                    }

                    RedisConnection conn = null;
                    try
                    {
                        string[] parts = option.Split(':');
                        if (parts.Length == 0)
                        {
                            continue;
                        }

                        string host = parts[0].Trim();
                        int    port = 6379, tmp;
                        if (parts.Length > 1 && int.TryParse(parts[1].Trim(), out tmp))
                        {
                            port = tmp;
                        }
                        conn      = new RedisConnection(host, port, syncTimeout: syncTimeout, allowAdmin: allowAdmin);
                        conn.Name = clientName;
                        log.WriteLine("Opening connection to {0}:{1}...", host, port);
                        conn.Open();
                        Task <string> info     = conn.GetInfo();
                        Task <string> tiebreak = conn.Strings.GetString(0, tieBreakerKey);
                        connections.Add(conn);
                        infos.Add(info);
                        tiebreakers.Add(tiebreak);
                    }
                    catch (Exception ex)
                    {
                        if (conn == null)
                        {
                            log.WriteLine("Error parsing option \"{0}\": {1}", option, ex.Message);
                        }
                        else
                        {
                            log.WriteLine("Error connecting: {0}", ex.Message);
                        }
                    }
                }
                List <RedisConnection> masters = new List <RedisConnection>(), slaves = new List <RedisConnection>();
                var breakerScores = new Dictionary <string, int>();
                foreach (var tiebreak in tiebreakers)
                {
                    try
                    {
                        if (tiebreak.Wait(syncTimeout))
                        {
                            string key = tiebreak.Result;
                            if (string.IsNullOrWhiteSpace(key))
                            {
                                continue;
                            }
                            int score;
                            if (breakerScores.TryGetValue(key, out score))
                            {
                                breakerScores[key] = score + 1;
                            }
                            else
                            {
                                breakerScores.Add(key, 1);
                            }
                        }
                    }
                    catch
                    {
                        /* if a node is down, that's fine too */
                    }
                }

                // see if any of our nodes are sentinels that know about the named service
                List <Tuple <RedisConnection, Task <Tuple <string, int> > > > sentinelNodes = null;
                foreach (RedisConnection conn in connections)
                {
                    // the "wait" we did during tie-breaker detection means we should now know what each server is
                    if (conn.ServerType == ServerType.Sentinel)
                    {
                        if (string.IsNullOrEmpty(serviceName))
                        {
                            log.WriteLine("Sentinel discovered, but no serviceName was specified; ignoring {0}:{1}",
                                          conn.Host, conn.Port);
                        }
                        else
                        {
                            log.WriteLine("Querying sentinel {0}:{1} for {2}...", conn.Host, conn.Port, serviceName);
                            if (sentinelNodes == null)
                            {
                                sentinelNodes = new List <Tuple <RedisConnection, Task <Tuple <string, int> > > >();
                            }
                            sentinelNodes.Add(Tuple.Create(conn, conn.QuerySentinelMaster(serviceName)));
                        }
                    }
                }

                // wait for sentinel results, if any
                if (sentinelNodes != null)
                {
                    var discoveredPairs = new Dictionary <Tuple <string, int>, int>();
                    foreach (var pair in sentinelNodes)
                    {
                        RedisConnection conn = pair.Item1;
                        try
                        {
                            Tuple <string, int> master = conn.Wait(pair.Item2);
                            if (master == null)
                            {
                                log.WriteLine("Sentinel {0}:{1} is not configured for {2}", conn.Host, conn.Port,
                                              serviceName);
                            }
                            else
                            {
                                log.WriteLine("Sentinel {0}:{1} nominates {2}:{3}", conn.Host, conn.Port, master.Item1,
                                              master.Item2);
                                int count;
                                if (discoveredPairs.TryGetValue(master, out count))
                                {
                                    count = 0;
                                }
                                discoveredPairs[master] = count + 1;
                            }
                        }
                        catch (Exception ex)
                        {
                            log.WriteLine("Error from sentinel {0}:{1} - {2}", conn.Host, conn.Port, ex.Message);
                        }
                    }
                    Tuple <string, int> finalChoice;
                    switch (discoveredPairs.Count)
                    {
                    case 0:
                        log.WriteLine("No sentinels nominated a master; unable to connect");
                        finalChoice = null;
                        break;

                    case 1:
                        finalChoice = discoveredPairs.Single().Key;
                        log.WriteLine("Sentinels nominated unanimous master: {0}:{1}", finalChoice.Item1,
                                      finalChoice.Item2);
                        break;

                    default:
                        finalChoice = discoveredPairs.OrderByDescending(kvp => kvp.Value).First().Key;
                        log.WriteLine("Sentinels nominated multiple masters; choosing arbitrarily: {0}:{1}",
                                      finalChoice.Item1, finalChoice.Item2);
                        break;
                    }

                    if (finalChoice != null)
                    {
                        RedisConnection toBeDisposed = null;
                        try
                        {
                            // good bet that in this scenario the input didn't specify any actual redis servers, so we'll assume open a new one
                            log.WriteLine("Opening nominated master: {0}:{1}...", finalChoice.Item1, finalChoice.Item2);
                            toBeDisposed = new RedisConnection(finalChoice.Item1, finalChoice.Item2,
                                                               allowAdmin: allowAdmin, syncTimeout: syncTimeout);
                            toBeDisposed.Wait(toBeDisposed.Open());
                            if (toBeDisposed.ServerType == ServerType.Master)
                            {
                                RedisConnection tmp = toBeDisposed;
                                toBeDisposed          = null; // so we don't dispose it
                                selectedConfiguration = tmp.Host + ":" + tmp.Port;
                                availableEndpoints    = new[] { selectedConfiguration };
                                return(tmp);
                            }
                            else
                            {
                                log.WriteLine("Server is {0} instead of a master", toBeDisposed.ServerType);
                            }
                        }
                        catch (Exception ex)
                        {
                            log.WriteLine("Error: {0}", ex.Message);
                        }
                        finally
                        {
                            // dispose if something went sour
                            using (toBeDisposed)
                            {
                            }
                        }
                    }
                    // something went south; BUT SENTINEL WINS TRUMPS; quit now
                    selectedConfiguration = null;
                    availableEndpoints    = new string[0];
                    return(null);
                }

                // check for tie-breakers (i.e. when we store which is the master)
                switch (breakerScores.Count)
                {
                case 0:
                    log.WriteLine("No tie-breakers found ({0})", tieBreakerKey);
                    break;

                case 1:
                    log.WriteLine("Tie-breaker ({0}) is unanimous: {1}", tieBreakerKey, breakerScores.Keys.Single());
                    break;

                default:
                    log.WriteLine("Ambiguous tie-breakers ({0}):", tieBreakerKey);
                    foreach (var kvp in breakerScores.OrderByDescending(x => x.Value))
                    {
                        log.WriteLine("\t{0}: {1}", kvp.Key, kvp.Value);
                    }
                    break;
                }

                for (int i = 0; i < connections.Count; i++)
                {
                    log.WriteLine("Reading configuration from {0}:{1}...", connections[i].Host, connections[i].Port);
                    try
                    {
                        if (!infos[i].Wait(syncTimeout))
                        {
                            log.WriteLine("\tTimeout fetching INFO");
                            continue;
                        }
                        var infoPairs = new StringDictionary();
                        using (var sr = new StringReader(infos[i].Result))
                        {
                            string line;
                            while ((line = sr.ReadLine()) != null)
                            {
                                int idx = line.IndexOf(':');
                                if (idx < 0)
                                {
                                    continue;
                                }
                                string key   = line.Substring(0, idx).Trim(),
                                       value = line.Substring(idx + 1, line.Length - (idx + 1)).Trim();
                                infoPairs[key] = value;
                            }
                        }
                        string role = infoPairs["role"];
                        switch (role)
                        {
                        case "slave":
                            log.WriteLine("\tServer is SLAVE of {0}:{1}",
                                          infoPairs["master_host"], infoPairs["master_port"]);
                            log.Write("\tLink is {0}, seen {1} seconds ago",
                                      infoPairs["master_link_status"], infoPairs["master_last_io_seconds_ago"]);
                            if (infoPairs["master_sync_in_progress"] == "1")
                            {
                                log.Write(" (sync is in progress)");
                            }
                            log.WriteLine();
                            slaves.Add(connections[i]);
                            break;

                        case "master":
                            log.WriteLine("\tServer is MASTER, with {0} slaves", infoPairs["connected_slaves"]);
                            masters.Add(connections[i]);
                            break;

                        default:
                            log.WriteLine("\tUnknown role: {0}", role);
                            break;
                        }
                        string tmp = infoPairs["connected_clients"];
                        int    clientCount, channelCount, patternCount;
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out clientCount))
                        {
                            clientCount = -1;
                        }
                        tmp = infoPairs["pubsub_channels"];
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out channelCount))
                        {
                            channelCount = -1;
                        }
                        tmp = infoPairs["pubsub_patterns"];
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out patternCount))
                        {
                            patternCount = -1;
                        }
                        log.WriteLine("\tClients: {0}; channels: {1}; patterns: {2}", clientCount, channelCount,
                                      patternCount);
                    }
                    catch (Exception ex)
                    {
                        log.WriteLine("\tError reading INFO results: {0}", ex.Message);
                    }
                }

                if (newMaster == null)
                {
                    switch (masters.Count)
                    {
                    case 0:
                        switch (slaves.Count)
                        {
                        case 0:
                            log.WriteLine("No masters or slaves found");
                            break;

                        case 1:
                            log.WriteLine("No masters found; selecting single slave");
                            preferred = slaves[0];
                            break;

                        default:
                            log.WriteLine("No masters found; considering {0} slaves...", slaves.Count);
                            preferred = SelectWithTieBreak(log, slaves, breakerScores);
                            break;
                        }
                        if (preferred != null)
                        {
                            if (autoMaster)
                            {
                                //LogException("Promoting redis SLAVE to MASTER");
                                log.WriteLine("Promoting slave to master...");
                                if (allowAdmin)
                                {
                                    // can do on this connection
                                    preferred.Wait(preferred.Server.MakeMaster());
                                }
                                else
                                {
                                    // need an admin connection for this
                                    using (
                                        var adminPreferred = new RedisConnection(preferred.Host, preferred.Port,
                                                                                 allowAdmin: true,
                                                                                 syncTimeout: syncTimeout))
                                    {
                                        adminPreferred.Open();
                                        adminPreferred.Wait(adminPreferred.Server.MakeMaster());
                                    }
                                }
                            }
                            else
                            {
                                log.WriteLine("Slave should be promoted to master (but not done yet)...");
                            }
                        }
                        break;

                    case 1:
                        log.WriteLine("One master found; selecting");
                        preferred = masters[0];
                        break;

                    default:
                        log.WriteLine("Considering {0} masters...", masters.Count);
                        preferred = SelectWithTieBreak(log, masters, breakerScores);
                        break;
                    }
                }
                else
                {
                    // we have been instructed to change master server
                    preferred = masters.Concat(slaves)
                                .FirstOrDefault(conn => (conn.Host + ":" + conn.Port) == newMaster);
                    if (preferred == null)
                    {
                        log.WriteLine("Selected new master not available: {0}", newMaster);
                    }
                    else
                    {
                        int errorCount = 0;
                        try
                        {
                            log.WriteLine("Promoting to master: {0}:{1}...", preferred.Host, preferred.Port);
                            preferred.Wait(preferred.Server.MakeMaster());
                            // if this is a master, we expect set/publish to work, even on 2.6
                            preferred.Strings.Set(0, tieBreakerKey, newMaster);
                            preferred.Wait(preferred.Publish(RedisMasterChangedChannel, newMaster));
                        }
                        catch (Exception ex)
                        {
                            log.WriteLine("\t{0}", ex.Message);
                            errorCount++;
                        }

                        if (errorCount == 0) // only make slaves if the master was happy
                        {
                            foreach (RedisConnection conn in masters.Concat(slaves))
                            {
                                if (conn == preferred)
                                {
                                    continue;                    // can't make self a slave!
                                }
                                try
                                {
                                    log.WriteLine("Enslaving: {0}:{1}...", conn.Host, conn.Port);

                                    // try to set the tie-breaker **first** in case of problems
                                    Task didSet = conn.Strings.Set(0, tieBreakerKey, newMaster);
                                    // and broadcast to anyone who thinks this is the master
                                    Task <long> didPublish = conn.Publish(RedisMasterChangedChannel, newMaster);
                                    // now make it a slave
                                    Task didEnslave = conn.Server.MakeSlave(preferred.Host, preferred.Port);
                                    // these are best-effort only; from 2.6, readonly slave servers may reject these commands
                                    try
                                    {
                                        conn.Wait(didSet);
                                    }
                                    catch
                                    {
                                    }
                                    try
                                    {
                                        conn.Wait(didPublish);
                                    }
                                    catch
                                    {
                                    }
                                    // but this one we'll log etc
                                    conn.Wait(didEnslave);
                                }
                                catch (Exception ex)
                                {
                                    log.WriteLine("\t{0}", ex.Message);
                                    errorCount++;
                                }
                            }
                        }
                        if (errorCount != 0)
                        {
                            log.WriteLine("Things didn't go smoothly; CHECK WHAT HAPPENED!");
                        }

                        // want the connection disposed etc
                        preferred = null;
                    }
                }

                if (preferred == null)
                {
                    selectedConfiguration = null;
                }
                else
                {
                    selectedConfiguration = preferred.Host + ":" + preferred.Port;
                    log.WriteLine("Selected server {0}", selectedConfiguration);
                }

                availableEndpoints = (from conn in masters.Concat(slaves)
                                      select conn.Host + ":" + conn.Port).ToArray();
                return(preferred);
            }
            finally
            {
                foreach (RedisConnection conn in connections)
                {
                    if (conn != null && conn != preferred)
                    {
                        try
                        {
                            conn.Dispose();
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }
Esempio n. 22
0
 public void TestLockOpCountByVersion(RedisConnection conn, int expected, bool existFirst)
 {
     const int DB = 0, LockDuration = 30;
     const string Key = "TestOpCountByVersion";
     conn.Wait(conn.Open());
     conn.Keys.Remove(DB, Key);
     var newVal = "us:" + Config.CreateUniqueName();
     string expectedVal = newVal;
     if (existFirst)
     {
         expectedVal = "other:" + Config.CreateUniqueName();
         conn.Strings.Set(DB, Key, expectedVal, LockDuration);
     }
     int countBefore = conn.GetCounters().MessagesSent;
     var taken = conn.Wait(conn.Strings.TakeLock(DB, Key, newVal, LockDuration));
     int countAfter = conn.GetCounters().MessagesSent;
     var valAfter = conn.Wait(conn.Strings.GetString(DB, Key));
     Assert.AreEqual(!existFirst, taken, "lock taken");
     Assert.AreEqual(expectedVal, valAfter, "taker");
     Assert.AreEqual(expected, (countAfter - countBefore) - 1, "expected ops (including ping)");
     // note we get a ping from GetCounters
 }
Esempio n. 23
0
        private static RedisConnection SelectAndCreateConnection(string configuration, TextWriter log, out string selectedConfiguration, out string[] availableEndpoints, bool autoMaster, string newMaster = null)
        {
            int syncTimeout;
            bool allowAdmin;
            if(log == null) log = new StringWriter();
            var arr = GetConfigurationOptions(configuration, out syncTimeout, out allowAdmin);
            if (!string.IsNullOrWhiteSpace(newMaster)) allowAdmin = true; // need this to diddle the slave/master config

            log.WriteLine("{0} unique nodes specified", arr.Length);
            log.WriteLine("sync timeout: {0}ms, admin commands: {1}", syncTimeout,
                          allowAdmin ? "enabled" : "disabled");
            if (arr.Length == 0)
            {
                log.WriteLine("No nodes to consider");
                selectedConfiguration = null;
                availableEndpoints = new string[0];
                return null;
            }
            var connections = new List<RedisConnection>(arr.Length);
            RedisConnection preferred = null;

            try
            {
                var infos = new List<Task<string>>(arr.Length);
                var tiebreakers = new List<Task<string>>(arr.Length);
                foreach (var option in arr)
                {
                    if (string.IsNullOrWhiteSpace(option)) continue;

                    RedisConnection conn = null;
                    try
                    {

                        var parts = option.Split(':');
                        if (parts.Length == 0) continue;

                        string host = parts[0].Trim();
                        int port = 6379, tmp;
                        if (parts.Length > 1 && int.TryParse(parts[1].Trim(), out tmp)) port = tmp;
                        conn = new RedisConnection(host, port, syncTimeout: syncTimeout, allowAdmin: allowAdmin);

                        log.WriteLine("Opening connection to {0}:{1}...", host, port);
                        conn.Open();
                        var info = conn.GetInfo();
                        var tiebreak = conn.Strings.GetString(0, TieBreakerKey);
                        connections.Add(conn);
                        infos.Add(info);
                        tiebreakers.Add(tiebreak);
                    }
                    catch (Exception ex)
                    {
                        if (conn == null)
                        {
                            log.WriteLine("Error parsing option \"{0}\": {1}", option, ex.Message);
                        }
                        else
                        {
                            log.WriteLine("Error connecting: {0}", ex.Message);
                        }
                    }
                }
                List<RedisConnection> masters = new List<RedisConnection>(), slaves = new List<RedisConnection>();
                var breakerScores = new Dictionary<string, int>();
                foreach (var tiebreak in tiebreakers)
                {
                    try
                    {
                        if (tiebreak.Wait(syncTimeout))
                        {
                            string key = tiebreak.Result;
                            if (string.IsNullOrWhiteSpace(key)) continue;
                            int score;
                            if (breakerScores.TryGetValue(key, out score)) breakerScores[key] = score + 1;
                            else breakerScores.Add(key, 1);
                        }
                    }
                    catch { /* if a node is down, that's fine too */ }
                }
                // check for tie-breakers (i.e. when we store which is the master)
                switch (breakerScores.Count)
                {
                    case 0:
                        log.WriteLine("No tie-breakers found");
                        break;
                    case 1:
                        log.WriteLine("Tie-breaker is unanimous: {0}", breakerScores.Keys.Single());
                        break;
                    default:
                        log.WriteLine("Ambiguous tie-breakers:");
                        foreach (var kvp in breakerScores.OrderByDescending(x => x.Value))
                        {
                            log.WriteLine("\t{0}: {1}", kvp.Key, kvp.Value);
                        }
                        break;
                }

                for (int i = 0; i < connections.Count; i++)
                {
                    log.WriteLine("Reading configuration from {0}:{1}...", connections[i].Host, connections[i].Port);
                    try
                    {
                        if (!infos[i].Wait(syncTimeout))
                        {
                            log.WriteLine("\tTimeout fetching INFO");
                            continue;
                        }
                        var infoPairs = new StringDictionary();
                        using (var sr = new StringReader(infos[i].Result))
                        {
                            string line;
                            while ((line = sr.ReadLine()) != null)
                            {
                                int idx = line.IndexOf(':');
                                if (idx < 0) continue;
                                string key = line.Substring(0, idx).Trim(),
                                       value = line.Substring(idx + 1, line.Length - (idx + 1)).Trim();
                                infoPairs[key] = value;
                            }
                        }
                        string role = infoPairs["role"];
                        switch (role)
                        {
                            case "slave":
                                log.WriteLine("\tServer is SLAVE of {0}:{1}",
                                          infoPairs["master_host"], infoPairs["master_port"]);
                                log.Write("\tLink is {0}, seen {1} seconds ago",
                                                 infoPairs["master_link_status"], infoPairs["master_last_io_seconds_ago"]);
                                if (infoPairs["master_sync_in_progress"] == "1") log.Write(" (sync is in progress)");
                                log.WriteLine();
                                slaves.Add(connections[i]);
                                break;
                            case "master":
                                log.WriteLine("\tServer is MASTER, with {0} slaves", infoPairs["connected_slaves"]);
                                masters.Add(connections[i]);
                                break;
                            default:
                                log.WriteLine("\tUnknown role: {0}", role);
                                break;
                        }
                        string tmp = infoPairs["connected_clients"];
                        int clientCount, channelCount, patternCount;
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out clientCount)) clientCount = -1;
                        tmp = infoPairs["pubsub_channels"];
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out channelCount)) channelCount = -1;
                        tmp = infoPairs["pubsub_patterns"];
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out patternCount)) patternCount = -1;
                        log.WriteLine("\tClients: {0}; channels: {1}; patterns: {2}", clientCount, channelCount, patternCount);
                    }
                    catch (Exception ex)
                    {
                        log.WriteLine("\tError reading INFO results: {0}", ex.Message);
                    }
                }

                if (newMaster == null)
                {
                    switch (masters.Count)
                    {
                        case 0:
                            switch (slaves.Count)
                            {
                                case 0:
                                    log.WriteLine("No masters or slaves found");
                                    break;
                                case 1:
                                    log.WriteLine("No masters found; selecting single slave");
                                    preferred = slaves[0];
                                    break;
                                default:
                                    log.WriteLine("No masters found; considering {0} slaves...", slaves.Count);
                                    preferred = SelectWithTieBreak(log, slaves, breakerScores);
                                    break;
                            }
                            if (preferred != null)
                            {
                                if (autoMaster)
                                {
                                    //LogException("Promoting redis SLAVE to MASTER");
                                    log.WriteLine("Promoting slave to master...");
                                    if (allowAdmin)
                                    { // can do on this connection
                                        preferred.Wait(preferred.Server.MakeMaster());
                                    }
                                    else
                                    { // need an admin connection for this
                                        using (var adminPreferred = new RedisConnection(preferred.Host, preferred.Port, allowAdmin: true, syncTimeout: syncTimeout))
                                        {
                                            adminPreferred.Open();
                                            adminPreferred.Wait(adminPreferred.Server.MakeMaster());
                                        }
                                    }
                                }
                                else
                                {
                                    log.WriteLine("Slave should be promoted to master (but not done yet)...");
                                }
                            }
                            break;
                        case 1:
                            log.WriteLine("One master found; selecting");
                            preferred = masters[0];
                            break;
                        default:
                            log.WriteLine("Considering {0} masters...", masters.Count);
                            preferred = SelectWithTieBreak(log, masters, breakerScores);
                            break;
                    }

                }
                else
                { // we have been instructed to change master server
                    preferred = masters.Concat(slaves).FirstOrDefault(conn => (conn.Host + ":" + conn.Port) == newMaster);
                    if (preferred == null)
                    {
                        log.WriteLine("Selected new master not available: {0}", newMaster);
                    }
                    else
                    {
                        int errorCount = 0;
                        try
                        {
                            log.WriteLine("Promoting to master: {0}:{1}...", preferred.Host, preferred.Port);
                            preferred.Wait(preferred.Server.MakeMaster());
                            preferred.Strings.Set(0, TieBreakerKey, newMaster);
                            preferred.Wait(preferred.Publish(RedisMasterChangedChannel, newMaster));
                        }
                        catch (Exception ex)
                        {
                            log.WriteLine("\t{0}", ex.Message);
                            errorCount++;
                        }

                        if (errorCount == 0) // only make slaves if the master was happy
                        {
                            foreach (var conn in masters.Concat(slaves))
                            {
                                if (conn == preferred) continue; // can't make self a slave!

                                try
                                {
                                    log.WriteLine("Enslaving: {0}:{1}...", conn.Host, conn.Port);
                                    // set the tie-breaker **first** in case of problems
                                    conn.Strings.Set(0, TieBreakerKey, newMaster);
                                    // and broadcast to anyone who thinks this is the master
                                    conn.Publish(RedisMasterChangedChannel, newMaster);
                                    // now make it a slave
                                    conn.Wait(conn.Server.MakeSlave(preferred.Host, preferred.Port));
                                }
                                catch (Exception ex)
                                {
                                    log.WriteLine("\t{0}",ex.Message);
                                    errorCount++;
                                }
                            }
                        }
                        if (errorCount != 0)
                        {
                            log.WriteLine("Things didn't go smoothly; CHECK WHAT HAPPENED!");
                        }

                        // want the connection disposed etc
                        preferred = null;
                    }
                }

                if (preferred == null)
                {
                    selectedConfiguration = null;
                }
                else
                {
                    selectedConfiguration = preferred.Host + ":" + preferred.Port;
                    log.WriteLine("Selected server {0}", selectedConfiguration);
                }

                availableEndpoints = (from conn in masters.Concat(slaves)
                                      select conn.Host + ":" + conn.Port).ToArray();
                return preferred;
            }
            finally
            {
                foreach (var conn in connections)
                {
                    if (conn != null && conn != preferred) try { conn.Dispose(); }
                        catch { }
                }
            }
        }
Esempio n. 24
0
        internal static RedisConnection SelectAndCreateConnection(string configuration, TextWriter log, out string selectedConfiguration, out string[] availableEndpoints, bool autoMaster, string newMaster = null, string tieBreakerKey = null)
        {
            TraceWriteTime("Start: " + configuration);
            if (tieBreakerKey == null) tieBreakerKey = "__Booksleeve_TieBreak"; // default tie-breaker key
            int syncTimeout;
            int keepAlive;
            bool allowAdmin;
            string serviceName;
            string clientName;
            if(log == null) log = new StringWriter();
            var arr = GetConfigurationOptions(configuration, out syncTimeout, out allowAdmin, out serviceName, out clientName, out keepAlive);
            if (!string.IsNullOrWhiteSpace(newMaster)) allowAdmin = true; // need this to diddle the slave/master config

            log.WriteLine("{0} unique nodes specified", arr.Length);
            log.WriteLine("sync timeout: {0}ms, admin commands: {1}", syncTimeout,
                          allowAdmin ? "enabled" : "disabled");
            if (!string.IsNullOrEmpty(serviceName)) log.WriteLine("service: {0}", serviceName);
            if (!string.IsNullOrEmpty(clientName)) log.WriteLine("client: {0}", clientName);
            if (arr.Length == 0)
            {
                log.WriteLine("No nodes to consider");
                selectedConfiguration = null;
                availableEndpoints = new string[0];
                return null;
            }
            var connections = new List<RedisConnection>(arr.Length);
            RedisConnection preferred = null;

            try
            {
                Task<string>[] infos, tiebreakers;
                List<RedisConnection> masters = new List<RedisConnection>(arr.Length);
                List<RedisConnection> slaves = new List<RedisConnection>(arr.Length);
                Dictionary<string, int> breakerScores = new Dictionary<string, int>(arr.Length);

                ConnectToNodes(log, tieBreakerKey, syncTimeout, keepAlive, allowAdmin, clientName, arr, connections, out infos, out tiebreakers, AuxMode.TieBreakers);

                for (int i = 0; i < tiebreakers.Length; i++ )
                {
                    var tiebreak = tiebreakers[i];
                    try
                    {
                        if (tiebreak.IsCompleted)
                        {
                            string key = tiebreak.Result;
                            if (string.IsNullOrWhiteSpace(key)) continue;
                            int score;
                            if (breakerScores.TryGetValue(key, out score)) breakerScores[key] = score + 1;
                            else breakerScores.Add(key, 1);
                        }
                        else
                        {
                            infos[i] = null; // forget it; took too long

                            if (tiebreak.IsFaulted)
                            {
                                GC.KeepAlive(tiebreak.Exception); // just an opaque method to show we've looked
                            }
                        }
                    }
                    catch { /* if a node is down, that's fine too */ }
                }

                TraceWriteTime("Check for sentinels");
                // see if any of our nodes are sentinels that know about the named service
                List<Tuple<RedisConnection, Task<Tuple<string, int>>>> sentinelNodes = null;
                foreach (var conn in connections)
                { // the "wait" we did during tie-breaker detection means we should now know what each server is
                    if (conn.ServerType == ServerType.Sentinel)
                    {
                        if (string.IsNullOrEmpty(serviceName))
                        {
                            log.WriteLine("Sentinel discovered, but no serviceName was specified; ignoring {0}:{1}", conn.Host, conn.Port);
                        }
                        else
                        {
                            log.WriteLine("Querying sentinel {0}:{1} for {2}...", conn.Host, conn.Port, serviceName);
                            if (sentinelNodes == null) sentinelNodes = new List<Tuple<RedisConnection, Task<Tuple<string, int>>>>();
                            sentinelNodes.Add(Tuple.Create(conn, conn.QuerySentinelMaster(serviceName)));
                        }
                    }
                }

                // wait for sentinel results, if any
                if(sentinelNodes != null)
                {
                    var discoveredPairs = new Dictionary<Tuple<string, int>, int>();
                    foreach(var pair in sentinelNodes)
                    {
                        var conn = pair.Item1;
                        try {
                            var master = conn.Wait(pair.Item2);
                            if(master == null)
                            {
                                log.WriteLine("Sentinel {0}:{1} is not configured for {2}", conn.Host, conn.Port, serviceName);
                            }
                            else
                            {
                                log.WriteLine("Sentinel {0}:{1} nominates {2}:{3}", conn.Host, conn.Port, master.Item1, master.Item2);
                                int count;
                                if (discoveredPairs.TryGetValue(master, out count)) count = 0;
                                discoveredPairs[master] = count + 1;
                            }
                        } catch (Exception ex) {
                            log.WriteLine("Error from sentinel {0}:{1} - {2}", conn.Host, conn.Port, ex.Message);
                        }
                    }
                    Tuple<string, int> finalChoice;
                    switch (discoveredPairs.Count)
                    {
                        case 0:
                            log.WriteLine("No sentinels nominated a master; unable to connect");
                            finalChoice = null;
                            break;
                        case 1:
                            finalChoice = discoveredPairs.Single().Key;
                            log.WriteLine("Sentinels nominated unanimous master: {0}:{1}", finalChoice.Item1, finalChoice.Item2);
                            break;
                        default:
                            finalChoice = discoveredPairs.OrderByDescending(kvp => kvp.Value).First().Key;
                            log.WriteLine("Sentinels nominated multiple masters; choosing arbitrarily: {0}:{1}", finalChoice.Item1, finalChoice.Item2);
                            break;
                    }

                    if (finalChoice != null)
                    {
                        RedisConnection toBeDisposed = null;
                        try
                        { // good bet that in this scenario the input didn't specify any actual redis servers, so we'll assume open a new one
                            log.WriteLine("Opening nominated master: {0}:{1}...", finalChoice.Item1, finalChoice.Item2);
                            toBeDisposed = new RedisConnection(finalChoice.Item1, finalChoice.Item2, allowAdmin: allowAdmin, syncTimeout: syncTimeout);
                            if (keepAlive >= 0) toBeDisposed.SetKeepAlive(keepAlive);
                            toBeDisposed.Wait(toBeDisposed.Open());
                            if (toBeDisposed.ServerType == ServerType.Master)
                            {
                                var tmp = toBeDisposed;
                                toBeDisposed = null; // so we don't dispose it
                                selectedConfiguration = tmp.Host + ":" + tmp.Port;
                                availableEndpoints = new string[] { selectedConfiguration };
                                return tmp;
                            }
                            else
                            {
                                log.WriteLine("Server is {0} instead of a master", toBeDisposed.ServerType);
                            }
                        }
                        catch (Exception ex)
                        {
                            log.WriteLine("Error: {0}", ex.Message);
                        }
                        finally
                        { // dispose if something went sour
                            using (toBeDisposed) { }
                        }
                    }
                    // something went south; BUT SENTINEL WINS TRUMPS; quit now
                    selectedConfiguration = null;
                    availableEndpoints = new string[0];
                    return null;
                }

                TraceWriteTime("Check tie-breakers");
                // check for tie-breakers (i.e. when we store which is the master)
                switch (breakerScores.Count)
                {
                    case 0:
                        log.WriteLine("No tie-breakers found ({0})", tieBreakerKey);
                        break;
                    case 1:
                        log.WriteLine("Tie-breaker ({0}) is unanimous: {1}", tieBreakerKey, breakerScores.Keys.Single());
                        break;
                    default:
                        log.WriteLine("Ambiguous tie-breakers ({0}):", tieBreakerKey);
                        foreach (var kvp in breakerScores.OrderByDescending(x => x.Value))
                        {
                            log.WriteLine("\t{0}: {1}", kvp.Key, kvp.Value);
                        }
                        break;
                }

                TraceWriteTime("Check connections");
                for (int i = 0; i < connections.Count; i++)
                {
                    if (infos[i] == null)
                    {
                        log.WriteLine("Server did not respond - {0}:{1}...", connections[i].Host, connections[i].Port);
                        connections[i].Close(abort:true);
                        continue;
                    }
                    log.WriteLine("Reading configuration from {0}:{1}...", connections[i].Host, connections[i].Port);
                    try
                    {
                        if (!infos[i].Wait(syncTimeout))
                        {
                            log.WriteLine("\tTimeout fetching INFO");
                            continue;
                        }
                        var infoPairs = new StringDictionary();
                        using (var sr = new StringReader(infos[i].Result))
                        {
                            string line;
                            while ((line = sr.ReadLine()) != null)
                            {
                                int idx = line.IndexOf(':');
                                if (idx < 0) continue;
                                string key = line.Substring(0, idx).Trim(),
                                       value = line.Substring(idx + 1, line.Length - (idx + 1)).Trim();
                                infoPairs[key] = value;
                            }
                        }
                        string role = infoPairs["role"];
                        switch (role)
                        {
                            case "slave":
                                log.WriteLine("\tServer is SLAVE of {0}:{1}",
                                          infoPairs["master_host"], infoPairs["master_port"]);
                                log.Write("\tLink is {0}, seen {1} seconds ago",
                                                 infoPairs["master_link_status"], infoPairs["master_last_io_seconds_ago"]);
                                if (infoPairs["master_sync_in_progress"] == "1") log.Write(" (sync is in progress)");
                                log.WriteLine();
                                slaves.Add(connections[i]);
                                break;
                            case "master":
                                log.WriteLine("\tServer is MASTER, with {0} slaves", infoPairs["connected_slaves"]);
                                masters.Add(connections[i]);
                                break;
                            default:
                                if (!string.IsNullOrWhiteSpace(role))
                                {
                                    log.WriteLine("\tUnknown role: {0}", role);
                                }
                                break;
                        }
                        string tmp = infoPairs["connected_clients"];
                        int clientCount, channelCount, patternCount;
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out clientCount)) clientCount = -1;
                        tmp = infoPairs["pubsub_channels"];
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out channelCount)) channelCount = -1;
                        tmp = infoPairs["pubsub_patterns"];
                        if (string.IsNullOrWhiteSpace(tmp) || !int.TryParse(tmp, out patternCount)) patternCount = -1;
                        log.WriteLine("\tClients: {0}; channels: {1}; patterns: {2}", clientCount, channelCount, patternCount);
                    }
                    catch (Exception ex)
                    {
                        log.WriteLine("\tError reading INFO results: {0}", ex.Message);
                    }
                }

                TraceWriteTime("Check masters");
                if (newMaster == null)
                {
                    switch (masters.Count)
                    {
                        case 0:
                            switch (slaves.Count)
                            {
                                case 0:
                                    log.WriteLine("No masters or slaves found");
                                    break;
                                case 1:
                                    log.WriteLine("No masters found; selecting single slave");
                                    preferred = slaves[0];
                                    break;
                                default:
                                    log.WriteLine("No masters found; considering {0} slaves...", slaves.Count);
                                    preferred = SelectWithTieBreak(log, slaves, breakerScores);
                                    break;
                            }
                            if (preferred != null)
                            {
                                if (autoMaster)
                                {
                                    //LogException("Promoting redis SLAVE to MASTER");
                                    log.WriteLine("Promoting slave to master...");
                                    if (allowAdmin)
                                    { // can do on this connection
                                        preferred.Wait(preferred.Server.MakeMaster());
                                    }
                                    else
                                    { // need an admin connection for this
                                        using (var adminPreferred = new RedisConnection(preferred.Host, preferred.Port, allowAdmin: true, syncTimeout: syncTimeout))
                                        {
                                            adminPreferred.Open();
                                            adminPreferred.Wait(adminPreferred.Server.MakeMaster());
                                        }
                                    }
                                }
                                else
                                {
                                    log.WriteLine("Slave should be promoted to master (but not done yet)...");
                                }
                            }
                            break;
                        case 1:
                            log.WriteLine("One master found; selecting");
                            preferred = masters[0];
                            break;
                        default:
                            log.WriteLine("Considering {0} masters...", masters.Count);
                            preferred = SelectWithTieBreak(log, masters, breakerScores);
                            break;
                    }

                }
                else
                { // we have been instructed to change master server
                    preferred = masters.Concat(slaves).FirstOrDefault(conn => (conn.Host + ":" + conn.Port) == newMaster);
                    if (preferred == null)
                    {
                        log.WriteLine("Selected new master not available: {0}", newMaster);
                    }
                    else
                    {
                        int errorCount = 0;
                        try
                        {
                            log.WriteLine("Promoting to master: {0}:{1}...", preferred.Host, preferred.Port);
                            preferred.Wait(preferred.Server.MakeMaster());
                            // if this is a master, we expect set/publish to work, even on 2.6
                            preferred.Strings.Set(0, tieBreakerKey, newMaster);
                            preferred.Wait(preferred.Publish(RedisMasterChangedChannel, newMaster));
                        }
                        catch (Exception ex)
                        {
                            log.WriteLine("\t{0}", ex.Message);
                            errorCount++;
                        }

                        if (errorCount == 0) // only make slaves if the master was happy
                        {
                            foreach (var conn in masters.Concat(slaves))
                            {
                                if (conn == preferred) continue; // can't make self a slave!

                                try
                                {
                                    log.WriteLine("Enslaving: {0}:{1}...", conn.Host, conn.Port);

                                    // try to set the tie-breaker **first** in case of problems
                                    var didSet = conn.Strings.Set(0, tieBreakerKey, newMaster);
                                    // and broadcast to anyone who thinks this is the master
                                    var didPublish = conn.Publish(RedisMasterChangedChannel, newMaster);
                                    // now make it a slave
                                    var didEnslave = conn.Server.MakeSlave(preferred.Host, preferred.Port);
                                    // these are best-effort only; from 2.6, readonly slave servers may reject these commands
                                    try { conn.Wait(didSet); } catch {}
                                    try { conn.Wait(didPublish); } catch {}
                                    // but this one we'll log etc
                                    conn.Wait(didEnslave);
                                }
                                catch (Exception ex)
                                {
                                    log.WriteLine("\t{0}",ex.Message);
                                    errorCount++;
                                }
                            }
                        }
                        if (errorCount != 0)
                        {
                            log.WriteLine("Things didn't go smoothly; CHECK WHAT HAPPENED!");
                        }

                        // want the connection disposed etc
                        preferred = null;
                    }
                }

                TraceWriteTime("Outro");
                if (preferred == null)
                {
                    selectedConfiguration = null;
                }
                else
                {
                    selectedConfiguration = preferred.Host + ":" + preferred.Port;
                    log.WriteLine("Selected server {0}", selectedConfiguration);
                }

                availableEndpoints = (from conn in masters.Concat(slaves)
                                      select conn.Host + ":" + conn.Port).ToArray();
                TraceWriteTime("Return");
                return preferred;
            }
            finally
            {
                TraceWriteTime("Start cleanup");
                foreach (var conn in connections)
                {
                    if (conn != null && conn != preferred) try { conn.Dispose(); }
                        catch { }
                }
                TraceWriteTime("End cleanup");
            }
        }
Esempio n. 25
0
        /// <summary>
        /// Prompt all clients to reconnect.
        /// </summary>
        public static void BroadcastReconnectMessage(RedisConnection connection)
        {
            if(connection == null) throw new ArgumentNullException("connection");

            connection.Wait(connection.Publish(RedisMasterChangedChannel, "*"));
        }