Esempio n. 1
0
        internal static void Run()
        {
            if (string.IsNullOrEmpty(Endpoints))
            {
                throw new ArgumentException("FhirEndpoints value is empty");
            }

            endpoints = Endpoints.Split(";", StringSplitOptions.RemoveEmptyEntries).ToList();

            var globalPrefix = $"RequestedBlobRange=[{NumberOfBlobsToSkip + 1}-{MaxBlobIndexForImport}]";

            Console.WriteLine($"{globalPrefix}: Starting...");
            var blobContainerClient = GetContainer(ConnectionString, ContainerName);
            var blobs = blobContainerClient.GetBlobs().OrderBy(_ => _.Name).Where(_ => _.Name.EndsWith(".ndjson", StringComparison.OrdinalIgnoreCase)).ToList();

            Console.WriteLine($"Found ndjson blobs={blobs.Count} in {ContainerName}.");
            var take = MaxBlobIndexForImport == 0 ? blobs.Count : MaxBlobIndexForImport - NumberOfBlobsToSkip;

            blobs = blobs.Skip(NumberOfBlobsToSkip).Take(take).ToList();
            var swWrites          = Stopwatch.StartNew();
            var swReport          = Stopwatch.StartNew();
            var currentBlobRanges = new Tuple <int, int> [ReadThreads];

            BatchExtensions.ExecuteInParallelBatches(blobs, ReadThreads, BlobRangeSize, (reader, blobRangeInt) =>
            {
                var localSw               = Stopwatch.StartNew();
                var writes                = 0L;
                var blobRangeIndex        = blobRangeInt.Item1;
                var blobsInt              = blobRangeInt.Item2;
                var firstBlob             = NumberOfBlobsToSkip + (blobRangeIndex * BlobRangeSize) + 1;
                var lastBlob              = NumberOfBlobsToSkip + (blobRangeIndex * BlobRangeSize) + blobsInt.Count;
                currentBlobRanges[reader] = Tuple.Create(firstBlob, lastBlob);
                var prefix                = $"Reader={reader}.BlobRange=[{firstBlob}-{lastBlob}]";
                var incrementor           = new IndexIncrementor(endpoints.Count);
                Console.WriteLine($"{prefix}: Starting...");

                // 100 below is a compromise between processing with maximum available threads (value 1) and inefficiency in wrapping single resource in a list.
                BatchExtensions.ExecuteInParallelBatches(GetLinesInBlobRange(blobsInt, prefix), WriteThreads / ReadThreads, 100, (thread, lineBatch) =>
                {
                    Interlocked.Increment(ref writers);
                    foreach (var line in lineBatch.Item2)
                    {
                        Interlocked.Increment(ref totalWrites);
                        Interlocked.Increment(ref writes);
                        PutResource(line, incrementor);
                        if (swReport.Elapsed.TotalSeconds > ReportingPeriodSec)
                        {
                            lock (swReport)
                            {
                                if (swReport.Elapsed.TotalSeconds > ReportingPeriodSec)
                                {
                                    var currWrites = Interlocked.Read(ref totalWrites);
                                    var currReads  = Interlocked.Read(ref totalReads);
                                    var minBlob    = currentBlobRanges.Min(_ => _.Item1);
                                    var maxBlob    = currentBlobRanges.Max(_ => _.Item2);
                                    Console.WriteLine($"{globalPrefix}.WorkingBlobRange=[{minBlob}-{maxBlob}].Readers=[{Interlocked.Read(ref readers)}/{ReadThreads}].Writers=[{Interlocked.Read(ref writers)}].EndPointCalls=[{Interlocked.Read(ref epCalls)}].Waits=[{Interlocked.Read(ref waits)}]: reads={currReads} writes={currWrites} secs={(int)swWrites.Elapsed.TotalSeconds} read-speed={(int)(currReads / swReads.Elapsed.TotalSeconds)} lines/sec write-speed={(int)(currWrites / swWrites.Elapsed.TotalSeconds)} res/sec");
                                    swReport.Restart();
                                }
                            }
                        }
                    }

                    Interlocked.Decrement(ref writers);
                });
                Console.WriteLine($"{prefix}: Completed writes. Total={writes} secs={(int)localSw.Elapsed.TotalSeconds} speed={(int)(writes / localSw.Elapsed.TotalSeconds)} res/sec");
            });
            Console.WriteLine($"{globalPrefix}.Readers=[{readers}/{ReadThreads}].Writers=[{writers}].EndPointCalls=[{epCalls}].Waits=[{waits}]: total reads={totalReads} total writes={totalWrites} secs={(int)swWrites.Elapsed.TotalSeconds} read-speed={(int)(totalReads / swReads.Elapsed.TotalSeconds)} lines/sec write-speed={(int)(totalWrites / swWrites.Elapsed.TotalSeconds)} res/sec");
        }
Esempio n. 2
0
        private static void PutResource(string jsonString, IndexIncrementor incrementor)
        {
            var(resourceType, resourceId) = ParseJson(jsonString);
            using var content             = new StringContent(jsonString, Encoding.UTF8, "application/json");
            var    maxRetries   = MaxRetries;
            var    retries      = 0;
            var    networkError = false;
            var    bad          = false;
            string endpoint;

            do
            {
                endpoint = endpoints[incrementor.Next()];
                var uri = new Uri(endpoint + "/" + resourceType + "/" + resourceId);
                bad = false;
                Interlocked.Increment(ref epCalls);
                try
                {
                    Thread.Sleep(40);
                    var response = HttpClient.PutAsync(uri, content).Result;
                    switch (response.StatusCode)
                    {
                    case HttpStatusCode.OK:
                    case HttpStatusCode.Created:
                        break;

                    default:
                        bad = true;
                        var statusString = response.StatusCode.ToString();
                        if (response.StatusCode != HttpStatusCode.BadGateway || retries > 0)     // too many bad gateway messages in the log
                        {
                            Console.WriteLine($"Retries={retries} Endpoint={endpoint} HttpStatusCode={statusString} ResourceType={resourceType} ResourceId={resourceId}");
                        }

                        if (response.StatusCode == HttpStatusCode.TooManyRequests)     // retry overload errors forever
                        {
                            maxRetries++;
                        }

                        break;
                    }
                }
                catch (Exception e)
                {
                    networkError = IsNetworkError(e);
                    if (!networkError)
                    {
                        Console.WriteLine($"Retries={retries} Endpoint={endpoint} ResourceType={resourceType} ResourceId={resourceId} Error={(networkError ? "network" : e.Message)}");
                    }

                    bad = true;
                    if (networkError) // retry network errors forever
                    {
                        maxRetries++;
                    }
                }
                finally
                {
                    Interlocked.Decrement(ref epCalls);
                }

                if (bad && retries < maxRetries)
                {
                    retries++;
                    Interlocked.Increment(ref waits);
                    Thread.Sleep(networkError ? 1000 : 200 * retries);
                    Interlocked.Decrement(ref waits);
                }
            }while (bad && retries < maxRetries);
            if (bad)
            {
                Console.WriteLine($"Failed writing ResourceType={resourceType} ResourceId={resourceId}. Retries={retries} Endpoint={endpoint}");
            }
        }