Exemple #1
0
        private static IProfilingLogger GetTestProfilingLogger()
        {
            var logger   = new DebugDiagnosticsLogger();
            var profiler = new TestProfiler();

            return(new ProfilingLogger(logger, profiler));
        }
        public void Simple()
        {
            using (var conn = Create())
            {
                var profiler = new TestProfiler();

                conn.RegisterProfiler(profiler);
                conn.BeginProfiling(profiler.MyContext);
                var db = conn.GetDatabase(4);
                db.StringSet("hello", "world");
                var val = db.StringGet("hello");
                Assert.Equal("world", (string)val);
                var result = db.ScriptEvaluate(LuaScript.Prepare("return redis.call('get', @key)"), new { key = (RedisKey)"hello" });
                Assert.Equal("world", result.AsString());

                var cmds = conn.FinishProfiling(profiler.MyContext);
                Assert.Equal(3, cmds.Count());

                var set = cmds.SingleOrDefault(cmd => cmd.Command == "SET");
                Assert.NotNull(set);
                var get = cmds.SingleOrDefault(cmd => cmd.Command == "GET");
                Assert.NotNull(get);
                var eval = cmds.SingleOrDefault(cmd => cmd.Command == "EVAL");
                Assert.NotNull(eval);

                Assert.True(set.CommandCreated <= get.CommandCreated);
                Assert.True(get.CommandCreated <= eval.CommandCreated);

                AssertProfiledCommandValues(set, conn);

                AssertProfiledCommandValues(get, conn);

                AssertProfiledCommandValues(eval, conn);
            }
        }
        private static IProfilingLogger GetTestProfilingLogger()
        {
            ILogger <ProfilingLogger> logger = NullLoggerFactory.Instance.CreateLogger <ProfilingLogger>();
            var profiler = new TestProfiler();

            return(new ProfilingLogger(logger, profiler));
        }
        public void ManyThreads()
        {
            using (var conn = Create())
            {
                var profiler = new TestProfiler();

                conn.RegisterProfiler(profiler);
                conn.BeginProfiling(profiler.MyContext);

                var threads = new List<Thread>();

                for (var i = 0; i < 16; i++)
                {
                    var db = conn.GetDatabase(i);

                    threads.Add(
                        new Thread(
                            delegate()
                            {
                                var threadTasks = new List<Task>();

                                for (var j = 0; j < 1000; j++)
                                {
                                    var task = db.StringSetAsync("" + j, "" + j);
                                    threadTasks.Add(task);
                                }

                                Task.WaitAll(threadTasks.ToArray());
                            }
                        )
                    );
                }

                threads.ForEach(thread => thread.Start());
                threads.ForEach(thread => thread.Join());

                var allVals = conn.FinishProfiling(profiler.MyContext);

                var kinds = allVals.Select(cmd => cmd.Command).Distinct().ToList();
                Assert.IsTrue(kinds.Count <= 2);
                Assert.IsTrue(kinds.Contains("SET"));
                if (kinds.Count == 2 && !kinds.Contains("SELECT"))
                {
                    Assert.Fail("Non-SET, Non-SELECT command seen");
                }

                Assert.AreEqual(16 * 1000, allVals.Count());
                Assert.AreEqual(16, allVals.Select(cmd => cmd.Db).Distinct().Count());

                for (var i = 0; i < 16; i++)
                {
                    var setsInDb = allVals.Where(cmd => cmd.Db == i && cmd.Command == "SET").Count();
                    Assert.AreEqual(1000, setsInDb);
                }
            }
        }
        public void ManyThreads()
        {
            using (var conn = Create())
            {
                var profiler = new TestProfiler();

                conn.RegisterProfiler(profiler);
                conn.BeginProfiling(profiler.MyContext);

                var threads = new List <Thread>();

                for (var i = 0; i < 16; i++)
                {
                    var db = conn.GetDatabase(i);

                    threads.Add(
                        new Thread(
                            delegate()
                    {
                        var threadTasks = new List <Task>();

                        for (var j = 0; j < 1000; j++)
                        {
                            var task = db.StringSetAsync("" + j, "" + j);
                            threadTasks.Add(task);
                        }

                        Task.WaitAll(threadTasks.ToArray());
                    }
                            )
                        );
                }

                threads.ForEach(thread => thread.Start());
                threads.ForEach(thread => thread.Join());

                var allVals = conn.FinishProfiling(profiler.MyContext);

                var kinds = allVals.Select(cmd => cmd.Command).Distinct().ToList();
                Assert.IsTrue(kinds.Count <= 2);
                Assert.IsTrue(kinds.Contains("SET"));
                if (kinds.Count == 2 && !kinds.Contains("SELECT"))
                {
                    Assert.Fail("Non-SET, Non-SELECT command seen");
                }

                Assert.AreEqual(16 * 1000, allVals.Count());
                Assert.AreEqual(16, allVals.Select(cmd => cmd.Db).Distinct().Count());

                for (var i = 0; i < 16; i++)
                {
                    var setsInDb = allVals.Where(cmd => cmd.Db == i && cmd.Command == "SET").Count();
                    Assert.AreEqual(1000, setsInDb);
                }
            }
        }
        public void LowAllocationEnumerable()
        {
            const int OuterLoop = 10000;

            using (var conn = Create())
            {
                var profiler = new TestProfiler();
                conn.RegisterProfiler(profiler);

                conn.BeginProfiling(profiler.MyContext);

                var db = conn.GetDatabase();

                var allTasks = new List <Task <string> >();

                foreach (var i in Enumerable.Range(0, OuterLoop))
                {
                    var t =
                        db.StringSetAsync("foo" + i, "bar" + i)
                        .ContinueWith(
                            async _ =>
                    {
                        return((string)(await db.StringGetAsync("foo" + i)));
                    }
                            );

                    var finalResult = t.Unwrap();
                    allTasks.Add(finalResult);
                }

                conn.WaitAll(allTasks.ToArray());

                var res = conn.FinishProfiling(profiler.MyContext);
                Assert.IsTrue(res.GetType().IsValueType);

                using (var e = res.GetEnumerator())
                {
                    Assert.IsTrue(e.GetType().IsValueType);

                    Assert.IsTrue(e.MoveNext());
                    var i = e.Current;

                    e.Reset();
                    Assert.IsTrue(e.MoveNext());
                    var j = e.Current;

                    Assert.IsTrue(object.ReferenceEquals(i, j));
                }

                Assert.AreEqual(OuterLoop * 2, res.Count());
                Assert.AreEqual(OuterLoop, res.Count(r => r.Command == "GET"));
                Assert.AreEqual(OuterLoop, res.Count(r => r.Command == "SET"));
            }
        }
Exemple #7
0
        public void LowAllocationEnumerable()
        {
            const int OuterLoop = 10000;

            using(var conn = Create())
            {
                var profiler = new TestProfiler();
                conn.RegisterProfiler(profiler);

                conn.BeginProfiling(profiler.MyContext);

                var db = conn.GetDatabase();

                var allTasks = new List<Task<string>>();

                foreach (var i in Enumerable.Range(0, OuterLoop))
                {
                    var t =
                        db.StringSetAsync("foo" + i, "bar" + i)
                          .ContinueWith(
                            async _ =>
                            {
                                return (string)(await db.StringGetAsync("foo" + i));
                            }
                          );

                    var finalResult = t.Unwrap();
                    allTasks.Add(finalResult);
                }

                conn.WaitAll(allTasks.ToArray());

                var res = conn.FinishProfiling(profiler.MyContext);
                Assert.IsTrue(res.GetType().IsValueType);

                using(var e = res.GetEnumerator())
                {
                    Assert.IsTrue(e.GetType().IsValueType);

                    Assert.IsTrue(e.MoveNext());
                    var i = e.Current;

                    e.Reset();
                    Assert.IsTrue(e.MoveNext());
                    var j = e.Current;

                    Assert.IsTrue(object.ReferenceEquals(i, j));
                }

                Assert.AreEqual(OuterLoop * 2, res.Count());
                Assert.AreEqual(OuterLoop, res.Count(r => r.Command == "GET"));
                Assert.AreEqual(OuterLoop, res.Count(r => r.Command == "SET"));
            }
        }
        public void Simple()
        {
            using (var conn = Create())
            {
                var profiler = new TestProfiler();

                conn.RegisterProfiler(profiler);
                conn.BeginProfiling(profiler.MyContext);
                var db = conn.GetDatabase(4);
                db.StringSet("hello", "world");
                var val = db.StringGet("hello");
                Assert.AreEqual("world", (string)val);

                var cmds = conn.FinishProfiling(profiler.MyContext);
                Assert.AreEqual(2, cmds.Count());

                var set = cmds.SingleOrDefault(cmd => cmd.Command == "SET");
                Assert.IsNotNull(set);
                var get = cmds.SingleOrDefault(cmd => cmd.Command == "GET");
                Assert.IsNotNull(get);

                Assert.IsTrue(set.CommandCreated <= get.CommandCreated);

                Assert.AreEqual(4, set.Db);
                Assert.AreEqual(conn.GetEndPoints()[0], set.EndPoint);
                Assert.IsTrue(set.CreationToEnqueued > TimeSpan.Zero);
                Assert.IsTrue(set.EnqueuedToSending > TimeSpan.Zero);
                Assert.IsTrue(set.SentToResponse > TimeSpan.Zero);
                Assert.IsTrue(set.ResponseToCompletion > TimeSpan.Zero);
                Assert.IsTrue(set.ElapsedTime > TimeSpan.Zero);
                Assert.IsTrue(set.ElapsedTime > set.CreationToEnqueued && set.ElapsedTime > set.EnqueuedToSending && set.ElapsedTime > set.SentToResponse);
                Assert.IsTrue(set.RetransmissionOf == null);
                Assert.IsTrue(set.RetransmissionReason == null);

                Assert.AreEqual(4, get.Db);
                Assert.AreEqual(conn.GetEndPoints()[0], get.EndPoint);
                Assert.IsTrue(get.CreationToEnqueued > TimeSpan.Zero);
                Assert.IsTrue(get.EnqueuedToSending > TimeSpan.Zero);
                Assert.IsTrue(get.SentToResponse > TimeSpan.Zero);
                Assert.IsTrue(get.ResponseToCompletion > TimeSpan.Zero);
                Assert.IsTrue(get.ElapsedTime > TimeSpan.Zero);
                Assert.IsTrue(get.ElapsedTime > get.CreationToEnqueued && get.ElapsedTime > get.EnqueuedToSending && get.ElapsedTime > get.SentToResponse);
                Assert.IsTrue(get.RetransmissionOf == null);
                Assert.IsTrue(get.RetransmissionReason == null);
            }
        }
        public void Simple()
        {
            using (var conn = Create())
            {
                var profiler = new TestProfiler();

                conn.RegisterProfiler(profiler);
                conn.BeginProfiling(profiler.MyContext);
                var db = conn.GetDatabase(4);
                db.StringSet("hello", "world");
                var val = db.StringGet("hello");
                Assert.AreEqual("world", (string)val);

                var cmds = conn.FinishProfiling(profiler.MyContext);
                Assert.AreEqual(2, cmds.Count());

                var set = cmds.SingleOrDefault(cmd => cmd.Command == "SET");
                Assert.IsNotNull(set);
                var get = cmds.SingleOrDefault(cmd => cmd.Command == "GET");
                Assert.IsNotNull(get);

                Assert.IsTrue(set.CommandCreated <= get.CommandCreated);

                Assert.AreEqual(4, set.Db);
                Assert.AreEqual(conn.GetEndPoints()[0], set.EndPoint);
                Assert.IsTrue(set.CreationToEnqueued > TimeSpan.Zero);
                Assert.IsTrue(set.EnqueuedToSending > TimeSpan.Zero);
                Assert.IsTrue(set.SentToResponse > TimeSpan.Zero);
                Assert.IsTrue(set.ResponseToCompletion > TimeSpan.Zero);
                Assert.IsTrue(set.ElapsedTime > TimeSpan.Zero);
                Assert.IsTrue(set.ElapsedTime > set.CreationToEnqueued && set.ElapsedTime > set.EnqueuedToSending && set.ElapsedTime > set.SentToResponse);
                Assert.IsTrue(set.RetransmissionOf == null);
                Assert.IsTrue(set.RetransmissionReason == null);

                Assert.AreEqual(4, get.Db);
                Assert.AreEqual(conn.GetEndPoints()[0], get.EndPoint);
                Assert.IsTrue(get.CreationToEnqueued > TimeSpan.Zero);
                Assert.IsTrue(get.EnqueuedToSending > TimeSpan.Zero);
                Assert.IsTrue(get.SentToResponse > TimeSpan.Zero);
                Assert.IsTrue(get.ResponseToCompletion > TimeSpan.Zero);
                Assert.IsTrue(get.ElapsedTime > TimeSpan.Zero);
                Assert.IsTrue(get.ElapsedTime > get.CreationToEnqueued && get.ElapsedTime > get.EnqueuedToSending && get.ElapsedTime > get.SentToResponse);
                Assert.IsTrue(get.RetransmissionOf == null);
                Assert.IsTrue(get.RetransmissionReason == null);
            }
        }
Exemple #10
0
        public void SimpleProfiling()
        {
            using (var conn = Create())
            {
                var profiler = new TestProfiler();

                conn.RegisterProfiler(profiler);
                conn.BeginProfiling(profiler.MyContext);
                var db = conn.GetDatabase();
                db.StringSet("hello", "world");
                var val = db.StringGet("hello");
                Assert.AreEqual("world", (string)val);

                var msgs = conn.FinishProfiling(profiler.MyContext);
                Assert.AreEqual(2, msgs.Count());
                Assert.IsTrue(msgs.Any(m => m.Command == "GET"));
                Assert.IsTrue(msgs.Any(m => m.Command == "SET"));
            }
        }
Exemple #11
0
        public void MovedProfiling()
        {
            const string Key   = "redirected-key";
            const string Value = "redirected-value";

            var profiler = new TestProfiler();

            using (var conn = Create())
            {
                conn.RegisterProfiler(profiler);

                var endpoints = conn.GetEndPoints();
                var servers   = endpoints.Select(e => conn.GetServer(e));

                conn.BeginProfiling(profiler.MyContext);
                var db = conn.GetDatabase();
                db.KeyDelete(Key);
                db.StringSet(Key, Value);
                var config = servers.First().ClusterConfiguration;
                Assert.IsNotNull(config);

                int slot            = conn.HashSlot(Key);
                var rightMasterNode = config.GetBySlot(Key);
                Assert.IsNotNull(rightMasterNode);

                string a = conn.GetServer(rightMasterNode.EndPoint).StringGet(db.Database, Key);
                Assert.AreEqual(Value, a, "right master");

                var wrongMasterNode = config.Nodes.FirstOrDefault(x => !x.IsSlave && x.NodeId != rightMasterNode.NodeId);
                Assert.IsNotNull(wrongMasterNode);

                string b = conn.GetServer(wrongMasterNode.EndPoint).StringGet(db.Database, Key);
                Assert.AreEqual(Value, b, "wrong master, allow redirect");

                var msgs = conn.FinishProfiling(profiler.MyContext).ToList();

                // verify that things actually got recorded properly, and the retransmission profilings are connected as expected
                {
                    // expect 1 DEL, 1 SET, 1 GET (to right master), 1 GET (to wrong master) that was responded to by an ASK, and 1 GET (to right master or a slave of it)
                    Assert.AreEqual(5, msgs.Count);
                    Assert.AreEqual(1, msgs.Count(c => c.Command == "DEL"));
                    Assert.AreEqual(1, msgs.Count(c => c.Command == "SET"));
                    Assert.AreEqual(3, msgs.Count(c => c.Command == "GET"));

                    var toRightMasterNotRetransmission = msgs.Where(m => m.Command == "GET" && m.EndPoint.Equals(rightMasterNode.EndPoint) && m.RetransmissionOf == null);
                    Assert.AreEqual(1, toRightMasterNotRetransmission.Count());

                    var toWrongMasterWithoutRetransmission = msgs.Where(m => m.Command == "GET" && m.EndPoint.Equals(wrongMasterNode.EndPoint) && m.RetransmissionOf == null);
                    Assert.AreEqual(1, toWrongMasterWithoutRetransmission.Count());

                    var toRightMasterOrSlaveAsRetransmission = msgs.Where(m => m.Command == "GET" && (m.EndPoint.Equals(rightMasterNode.EndPoint) || rightMasterNode.Children.Any(c => m.EndPoint.Equals(c.EndPoint))) && m.RetransmissionOf != null);
                    Assert.AreEqual(1, toRightMasterOrSlaveAsRetransmission.Count());

                    var originalWrongMaster   = toWrongMasterWithoutRetransmission.Single();
                    var retransmissionToRight = toRightMasterOrSlaveAsRetransmission.Single();

                    Assert.IsTrue(object.ReferenceEquals(originalWrongMaster, retransmissionToRight.RetransmissionOf));
                }

                foreach (var msg in msgs)
                {
                    Assert.IsTrue(msg.CommandCreated != default(DateTime));
                    Assert.IsTrue(msg.CreationToEnqueued > TimeSpan.Zero);
                    Assert.IsTrue(msg.EnqueuedToSending > TimeSpan.Zero);
                    Assert.IsTrue(msg.SentToResponse > TimeSpan.Zero);
                    Assert.IsTrue(msg.ResponseToCompletion > TimeSpan.Zero);
                    Assert.IsTrue(msg.ElapsedTime > TimeSpan.Zero);

                    if (msg.RetransmissionOf != null)
                    {
                        // imprecision of DateTime.UtcNow makes this pretty approximate
                        Assert.IsTrue(msg.RetransmissionOf.CommandCreated <= msg.CommandCreated);
                        Assert.AreEqual(RetransmissionReasonType.Moved, msg.RetransmissionReason.Value);
                    }
                    else
                    {
                        Assert.IsFalse(msg.RetransmissionReason.HasValue);
                    }
                }
            }
        }
        public void Retrieving_All_Content_In_Site()
        {
            //NOTE: Doing this the old 1 by 1 way and based on the results of the ContentServicePerformanceTest.Retrieving_All_Content_In_Site
            // the old way takes 143795ms, the new above way takes:
            // 14249ms
            //
            // ... NOPE, made some new changes, it is now....
            // 5290ms  !!!!!!
            //
            // that is a 96% savings of processing and sql calls!
            //
            // ... NOPE, made even more nice changes, it is now...
            // 4452ms !!!!!!!

            var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "test1");
            var contentType2 = MockedContentTypes.CreateTextpageContentType("test2", "test2");
            var contentType3 = MockedContentTypes.CreateTextpageContentType("test3", "test3");

            ServiceContext.ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 });
            contentType1.AllowedContentTypes = new[]
            {
                new ContentTypeSort(new Lazy <int>(() => contentType2.Id), 0, contentType2.Alias),
                new ContentTypeSort(new Lazy <int>(() => contentType3.Id), 1, contentType3.Alias)
            };
            contentType2.AllowedContentTypes = new[]
            {
                new ContentTypeSort(new Lazy <int>(() => contentType1.Id), 0, contentType1.Alias),
                new ContentTypeSort(new Lazy <int>(() => contentType3.Id), 1, contentType3.Alias)
            };
            contentType3.AllowedContentTypes = new[]
            {
                new ContentTypeSort(new Lazy <int>(() => contentType1.Id), 0, contentType1.Alias),
                new ContentTypeSort(new Lazy <int>(() => contentType2.Id), 1, contentType2.Alias)
            };
            ServiceContext.ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 });

            var roots = MockedContent.CreateTextpageContent(contentType1, -1, 10);

            ServiceContext.ContentService.Save(roots);
            foreach (var root in roots)
            {
                var item1 = MockedContent.CreateTextpageContent(contentType1, root.Id, 10);
                var item2 = MockedContent.CreateTextpageContent(contentType2, root.Id, 10);
                var item3 = MockedContent.CreateTextpageContent(contentType3, root.Id, 10);

                ServiceContext.ContentService.Save(item1.Concat(item2).Concat(item3));
            }

            var total = new List <IContent>();

            using (DisposableTimer.TraceDuration <ContentServicePerformanceTest>("Getting all content in site"))
            {
                TestProfiler.Enable();
                total.AddRange(ServiceContext.ContentService.GetRootContent());
                foreach (var content in total.ToArray())
                {
                    total.AddRange(ServiceContext.ContentService.GetDescendants(content));
                }
                TestProfiler.Disable();
                LogHelper.Info <ContentServicePerformanceTest>("Returned " + total.Count + " items");
            }
        }
Exemple #13
0
        public void Retrieving_All_Content_In_Site()
        {
            // NOTE: Doing this the old 1 by 1 way and based on the results of the ContentServicePerformanceTest.Retrieving_All_Content_In_Site
            // the old way takes 143795ms, the new above way takes:
            // 14249ms
            //
            // ... NOPE, made some new changes, it is now....
            // 5290ms  !!!!!!
            //
            // that is a 96% savings of processing and sql calls!
            //
            // ... NOPE, made even more nice changes, it is now...
            // 4452ms !!!!!!!
            Template template = TemplateBuilder.CreateTextPageTemplate();

            FileService.SaveTemplate(template);

            ContentType contentType1 = ContentTypeBuilder.CreateTextPageContentType("test1", "test1", defaultTemplateId: template.Id);
            ContentType contentType2 = ContentTypeBuilder.CreateTextPageContentType("test2", "test2", defaultTemplateId: template.Id);
            ContentType contentType3 = ContentTypeBuilder.CreateTextPageContentType("test3", "test3", defaultTemplateId: template.Id);

            ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 });
            contentType1.AllowedContentTypes = new[]
            {
                new ContentTypeSort(new Lazy <int>(() => contentType2.Id), 0, contentType2.Alias),
                new ContentTypeSort(new Lazy <int>(() => contentType3.Id), 1, contentType3.Alias)
            };
            contentType2.AllowedContentTypes = new[]
            {
                new ContentTypeSort(new Lazy <int>(() => contentType1.Id), 0, contentType1.Alias),
                new ContentTypeSort(new Lazy <int>(() => contentType3.Id), 1, contentType3.Alias)
            };
            contentType3.AllowedContentTypes = new[]
            {
                new ContentTypeSort(new Lazy <int>(() => contentType1.Id), 0, contentType1.Alias),
                new ContentTypeSort(new Lazy <int>(() => contentType2.Id), 1, contentType2.Alias)
            };
            ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 });

            IEnumerable <Content> roots = ContentBuilder.CreateTextpageContent(contentType1, -1, 10);

            ContentService.Save(roots);
            foreach (Content root in roots)
            {
                IEnumerable <Content> item1 = ContentBuilder.CreateTextpageContent(contentType1, root.Id, 10);
                IEnumerable <Content> item2 = ContentBuilder.CreateTextpageContent(contentType2, root.Id, 10);
                IEnumerable <Content> item3 = ContentBuilder.CreateTextpageContent(contentType3, root.Id, 10);

                ContentService.Save(item1.Concat(item2).Concat(item3));
            }

            var total = new List <IContent>();

            using (GetTestProfilingLogger().TraceDuration <ContentServicePerformanceTest>("Getting all content in site"))
            {
                TestProfiler.Enable();
                total.AddRange(ContentService.GetRootContent());
                foreach (IContent content in total.ToArray())
                {
                    total.AddRange(ContentService.GetPagedDescendants(content.Id, 0, int.MaxValue, out long _));
                }

                TestProfiler.Disable();
                StaticApplicationLogging.Logger.LogInformation("Returned {Total} items", total.Count);
            }
        }
Exemple #14
0
        private static IProfilingLogger GetTestProfilingLogger()
        {
            var profiler = new TestProfiler();

            return(new ProfilingLogger(new NullLogger <ProfilingLogger>(), profiler));
        }
        public void MovedProfiling()
        {
            const string Key = "redirected-key";
            const string Value = "redirected-value";

            var profiler = new TestProfiler();

            using (var conn = Create())
            {
                conn.RegisterProfiler(profiler);

                var endpoints = conn.GetEndPoints();
                var servers = endpoints.Select(e => conn.GetServer(e));

                conn.BeginProfiling(profiler.MyContext);
                var db = conn.GetDatabase();
                db.KeyDelete(Key);
                db.StringSet(Key, Value);
                var config = servers.First().ClusterConfiguration;
                Assert.IsNotNull(config);

                int slot = conn.HashSlot(Key);
                var rightMasterNode = config.GetBySlot(Key);
                Assert.IsNotNull(rightMasterNode);

                string a = conn.GetServer(rightMasterNode.EndPoint).StringGet(db.Database, Key);
                Assert.AreEqual(Value, a, "right master");

                var wrongMasterNode = config.Nodes.FirstOrDefault(x => !x.IsSlave && x.NodeId != rightMasterNode.NodeId);
                Assert.IsNotNull(wrongMasterNode);

                string b = conn.GetServer(wrongMasterNode.EndPoint).StringGet(db.Database, Key);
                Assert.AreEqual(Value, b, "wrong master, allow redirect");

                var msgs = conn.FinishProfiling(profiler.MyContext).ToList();
                
                // verify that things actually got recorded properly, and the retransmission profilings are connected as expected
                {
                    // expect 1 DEL, 1 SET, 1 GET (to right master), 1 GET (to wrong master) that was responded to by an ASK, and 1 GET (to right master or a slave of it)
                    Assert.AreEqual(5, msgs.Count);
                    Assert.AreEqual(1, msgs.Count(c => c.Command == "DEL"));
                    Assert.AreEqual(1, msgs.Count(c => c.Command == "SET"));
                    Assert.AreEqual(3, msgs.Count(c => c.Command == "GET"));

                    var toRightMasterNotRetransmission = msgs.Where(m => m.Command == "GET" && m.EndPoint.Equals(rightMasterNode.EndPoint) && m.RetransmissionOf == null);
                    Assert.AreEqual(1, toRightMasterNotRetransmission.Count());

                    var toWrongMasterWithoutRetransmission = msgs.Where(m => m.Command == "GET" && m.EndPoint.Equals(wrongMasterNode.EndPoint) && m.RetransmissionOf == null);
                    Assert.AreEqual(1, toWrongMasterWithoutRetransmission.Count());

                    var toRightMasterOrSlaveAsRetransmission = msgs.Where(m => m.Command == "GET" && (m.EndPoint.Equals(rightMasterNode.EndPoint) || rightMasterNode.Children.Any(c => m.EndPoint.Equals(c.EndPoint))) && m.RetransmissionOf != null);
                    Assert.AreEqual(1, toRightMasterOrSlaveAsRetransmission.Count());

                    var originalWrongMaster = toWrongMasterWithoutRetransmission.Single();
                    var retransmissionToRight = toRightMasterOrSlaveAsRetransmission.Single();

                    Assert.IsTrue(object.ReferenceEquals(originalWrongMaster, retransmissionToRight.RetransmissionOf));
                }

                foreach(var msg in msgs)
                {
                    Assert.IsTrue(msg.CommandCreated != default(DateTime));
                    Assert.IsTrue(msg.CreationToEnqueued > TimeSpan.Zero);
                    Assert.IsTrue(msg.EnqueuedToSending > TimeSpan.Zero);
                    Assert.IsTrue(msg.SentToResponse > TimeSpan.Zero);
                    Assert.IsTrue(msg.ResponseToCompletion > TimeSpan.Zero);
                    Assert.IsTrue(msg.ElapsedTime > TimeSpan.Zero);

                    if (msg.RetransmissionOf != null)
                    {
                        // imprecision of DateTime.UtcNow makes this pretty approximate
                        Assert.IsTrue(msg.RetransmissionOf.CommandCreated <= msg.CommandCreated);
                        Assert.AreEqual(RetransmissionReasonType.Moved, msg.RetransmissionReason.Value);
                    }
                    else
                    {
                        Assert.IsFalse(msg.RetransmissionReason.HasValue);
                    }
                }
            }
        }
        public void SimpleProfiling()
        {
            using (var conn = Create())
            {
                var profiler = new TestProfiler();

                conn.RegisterProfiler(profiler);
                conn.BeginProfiling(profiler.MyContext);
                var db = conn.GetDatabase();
                db.StringSet("hello", "world");
                var val = db.StringGet("hello");
                Assert.AreEqual("world", (string)val);

                var msgs = conn.FinishProfiling(profiler.MyContext);
                Assert.AreEqual(2, msgs.Count());
                Assert.IsTrue(msgs.Any(m => m.Command == "GET"));
                Assert.IsTrue(msgs.Any(m => m.Command == "SET"));
            }
        }