private void Flood(CommandProcessorContext context, 
                           string eventStreamId, 
                           int clientsCnt, 
                           int minPerSecond, 
                           int maxPerSecond, 
                           int runTimeMinutes,
                           int dataSize)
        {
            context.IsAsync();

            var threads = new List<Thread>();
            var doneEvent = new ManualResetEvent(false);

            var succ = 0;
            var fail = 0;

            var requestsCnt = 0;

            var watchLockRoot = new object();
            var sw = Stopwatch.StartNew();
            for (int i = 0; i < clientsCnt; i++)
            {
                int sent = 0;
                int received = 0;

                threads.Add(new Thread(() =>
                {
                    var esId = eventStreamId ?? "Stream-" + Thread.CurrentThread.ManagedThreadId % 3;

                    var client = new HttpAsyncClient();

                    Action<HttpResponse> succHandler = response =>
                    {
                        if (response.HttpStatusCode == HttpStatusCode.Created)
                        {
                            var succDone = Interlocked.Increment(ref succ);
                            if (succDone % maxPerSecond == 0)
                                Console.Write(".");
                        }
                        else
                        {
                            if (Interlocked.Increment(ref fail) % 10 == 0)
                            {
                                context.Log.Info("ANOTHER 10th WRITE FAILED. [{0}] - [{1}]", response.HttpStatusCode, response.StatusDescription);
                            }
                        }

                        Interlocked.Increment(ref requestsCnt);
                        Interlocked.Increment(ref received);
                    };

                    var sentCount = 0;
                    var sleepTime = 0;

                    var dataSizeCoefficient = 1;
                    var currentMinute = -1;

                    while (true)
                    {
                        TimeSpan elapsed;
                        lock (watchLockRoot)
                            elapsed = sw.Elapsed;

                        if (elapsed.TotalMinutes > runTimeMinutes)
                        {
                            doneEvent.Set();
                            break;
                        }

                        if (sentCount == 0)
                        {
                            int elapsedMinutesInt = (int)elapsed.TotalMinutes;

                            lock (_randomLockRoot)
                            {
                                sentCount = minPerSecond == maxPerSecond
                                            ? maxPerSecond : _random.Next(minPerSecond, maxPerSecond);
                                dataSizeCoefficient = _random.Next(8, 256);
                            }

                            if (currentMinute != elapsedMinutesInt)
                            {
                                currentMinute = elapsedMinutesInt;
                                context.Log.Info("\nElapsed {0} of {1} minutes, sent {2}; next block coef. {3}",
                                                 elapsedMinutesInt,
                                                 runTimeMinutes,
                                                 sent,
                                                 dataSizeCoefficient);
                            }

                            sleepTime = 1000 / sentCount;
                        }

                        var url = context.Client.HttpEndpoint.ToHttpUrl("/streams/{0}", esId);

                        var dataResultingSize = dataSizeCoefficient * dataSize;
                        var write = new HttpClientMessageDto.WriteEventsText(
                            ExpectedVersion.Any,
                            new[] {
                                new HttpClientMessageDto.ClientEventText(
                            Guid.NewGuid(),
                            "type",
                            "DATA" + dataResultingSize.ToString(" 00000 ") + new string('*', dataResultingSize),
                                    "METADATA" + new string('$', 100))
                            });
                        var request = Codec.Xml.To(write);
                        client.Post(url,
                                    request,
                                    Codec.Xml.ContentType,
                                    succHandler,
                                    exc =>
                                        {
                                            Interlocked.Increment(ref fail);
                                            Interlocked.Increment(ref requestsCnt);
                                            context.Log.ErrorException(exc, "Error during POST.");
                                        });

                        Interlocked.Increment(ref sent);

                        Thread.Sleep(sleepTime);
                        sentCount -= 1;

                        while (sent - received > context.Client.Options.WriteWindow)
                            Thread.Sleep(1);
                    }
                }));
            }

            foreach (var thread in threads)
            {
                thread.IsBackground = true;
                thread.Start();
            }

            doneEvent.WaitOne();

            sw.Stop();

            context.Log.Info("Completed. Successes: {0}, failures: {1}", succ, fail);

            var reqPerSec = (requestsCnt + 0.0)/sw.ElapsedMilliseconds*1000;
            context.Log.Info("{0} requests completed in {1}ms ({2:0.00} reqs per sec).",
                             requestsCnt,
                             sw.ElapsedMilliseconds,
                             reqPerSec);

            PerfUtils.LogData(
                    Keyword,
                    PerfUtils.Row(PerfUtils.Col("clientsCnt", clientsCnt),
                         PerfUtils.Col("requestsCnt", requestsCnt),
                         PerfUtils.Col("ElapsedMilliseconds", sw.ElapsedMilliseconds)),
                    PerfUtils.Row(PerfUtils.Col("successes", succ), PerfUtils.Col("failures", fail))
            );

            PerfUtils.LogTeamCityGraphData(string.Format("{0}-{1}-{2}-{3}-{4}-reqPerSec",
                                                   Keyword,
                                                   clientsCnt,
                                                   minPerSecond,
                                                   maxPerSecond,
                                                   runTimeMinutes),
                        (int)reqPerSec);

            PerfUtils.LogTeamCityGraphData(
                string.Format("{0}-{1}-{2}-failureSuccessRate", Keyword, clientsCnt, requestsCnt),
                100 * fail / (fail + succ));

            if (succ < fail)
                context.Fail(reason: "Number of failures is greater than number of successes");
            else
                context.Success();
        }
        private void WriteFlood(CommandProcessorContext context, int clientsCnt, int requestsCnt)
        {
            context.IsAsync();

            var threads = new List<Thread>();
            var autoResetEvent = new AutoResetEvent(false);

            var succ = 0;
            var fail = 0;
            var all = 0;

            var sw = Stopwatch.StartNew();
            for (int i = 0; i < clientsCnt; i++)
            {
                var count = requestsCnt / clientsCnt + ((i == clientsCnt - 1) ? requestsCnt % clientsCnt : 0);

                threads.Add(new Thread(() =>
                {
                    var autoEvent = new AutoResetEvent(false);
                    var eventStreamId = "es" + Guid.NewGuid();

                    var client = new HttpAsyncClient();
                    var url = context.Client.HttpEndpoint.ToHttpUrl("/streams/{0}", eventStreamId);

                    Action<HttpResponse> succHandler = response =>
                    {
                        if (response.HttpStatusCode == HttpStatusCode.Created)
                        {
                            if (Interlocked.Increment(ref succ) % 1000 == 0)
                                Console.Write(".");
                        }
                        else
                        {
                            if (Interlocked.Increment(ref fail) % 10 == 0)
                            {
                                context.Log.Info("ANOTHER 10th WRITE FAILED. [{0}] - [{1}]", response.HttpStatusCode, response.StatusDescription);
                            }
                        }

                        if (Interlocked.Increment(ref all) == requestsCnt)
                            autoResetEvent.Set();
                        autoEvent.Set();
                    };

                    for (int j = 0; j < count; ++j)
                    {
                        var write = new HttpClientMessageDto.WriteEventsText(
                            ExpectedVersion.Any,
                            new[] 
                            { 
                                new HttpClientMessageDto.ClientEventText(Guid.NewGuid(), 
                                                               "type",
                                                               "DATA" + new string('*', 256),
                                                               "METADATA" + new string('$', 100))
                            });
                        var request = Codec.Xml.To(write);
                        client.Post(url, 
                                    request, 
                                    Codec.Xml.ContentType,
                                    succHandler, 
                                    exc => 
                                    {
                                        context.Log.ErrorException(exc, "Error during POST.");
                                        Interlocked.Increment(ref fail);
                                        if (Interlocked.Increment(ref all) == requestsCnt)
                                            autoResetEvent.Set();
                                        autoEvent.Set();
                                    });
                        autoEvent.WaitOne();
                    }
                }));
            }

            foreach (var thread in threads)
            {
                thread.IsBackground = true;
                thread.Start();
            }

            autoResetEvent.WaitOne();
            sw.Stop();

            context.Log.Info("Completed. Successes: {0}, failures: {1}", succ, fail);

            var reqPerSec = (requestsCnt + 0.0)/sw.ElapsedMilliseconds*1000;
            context.Log.Info("{0} requests completed in {1}ms ({2:0.00} reqs per sec).",
                             requestsCnt,
                             sw.ElapsedMilliseconds,
                             reqPerSec);

            PerfUtils.LogData(
                        Keyword,
                        PerfUtils.Row(PerfUtils.Col("clientsCnt", clientsCnt),
                             PerfUtils.Col("requestsCnt", requestsCnt),
                             PerfUtils.Col("ElapsedMilliseconds", sw.ElapsedMilliseconds)),
                        PerfUtils.Row(PerfUtils.Col("successes", succ), PerfUtils.Col("failures", fail)));

            PerfUtils.LogTeamCityGraphData(string.Format("{0}-{1}-{2}-reqPerSec", Keyword, clientsCnt, requestsCnt),
                                           (int) reqPerSec);

            PerfUtils.LogTeamCityGraphData(
                string.Format("{0}-{1}-{2}-failureSuccessRate", Keyword, clientsCnt, requestsCnt),
                100*fail/(fail + succ));
        
            PerfUtils.LogTeamCityGraphData(string.Format("{0}-latency-ms", Keyword),
                                           (int)(sw.ElapsedMilliseconds / requestsCnt));

            context.Success();
        }