// protected override void LogItemToConsole(JsonDocumentMergerQueueItem workItem)
        // {
        //    // don't log here
        // }

        /// <summary>
        /// The add to json object.
        /// </summary>
        /// <param name="queryId">
        /// The query id.
        /// </param>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <param name="propertyName">
        /// The property name.
        /// </param>
        /// <param name="newJObjects">
        /// The new j objects.
        /// </param>
        /// <param name="batchNumber">
        /// The batch number.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task AddToJsonObjectAsync(string queryId, string id, string propertyName, JObject[] newJObjects, int batchNumber)
        {
            // BlockIfMaxSizeReached(id);

            // lock on id so multiple threads cannot update the same document at the same time
            var semaphoreSlim = this.locks.GetOrAdd(id, s => new SemaphoreSlim(1, 1));

            // Asynchronously wait to enter the Semaphore. If no-one has been granted access to the Semaphore, code execution will proceed, otherwise this thread waits here until the semaphore is released
            await semaphoreSlim.WaitAsync();

            try
            {
                JObject document;
                if (!this.documentDictionary.ContainsKey(id))
                {
                    document = new JObject {
                        { this.Config.TopLevelKeyColumn, id }
                    };
                    var jsonObjectCacheItem = new JsonObjectQueueItem
                    {
                        BatchNumber = batchNumber,
                        Id          = id,
                        Document    = document
                    };


                    this.documentDictionary.Add(id, jsonObjectCacheItem);

                    Interlocked.Increment(ref this.numDocumentsModified);

                    this.MyLogger.Verbose($"AddToJsonObject: id:{id} _numDocumentsModified={this.numDocumentsModified:N0} _documentDictionary.Count={this.documentDictionary.Count:N0}");
                    await this.entityJsonWriter.SetPropertiesByMergeAsync(propertyName, newJObjects, document);
                }
                else
                {
                    document = this.documentDictionary.GetById(id).Document;

                    this.MyLogger.Verbose($"UpdatedJsonObject: id:{id}  _numDocumentsModified={this.numDocumentsModified:N0} _documentDictionary.Count={this.documentDictionary.Count:N0}");
                    await this.entityJsonWriter.SetPropertiesByMergeAsync(propertyName, newJObjects, document);
                }
            }
            finally
            {
                // When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked.
                // This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution
                semaphoreSlim.Release();
            }

            var minimum = SequenceBarrier.UpdateMinimumEntityIdProcessed(queryId, id);

            // Console.Write($"\r{LoggerName} Id:{id} Remaining: {_inQueue.Count:N0} queryId:{queryId} Minimum id:{minimum}");
            this.MyLogger.Verbose($"Processed id: {id} for queryId:{queryId} Minimum id:{minimum}");

            // AddDocumentsToOutQueue(minimum);

            // AddDocumentToOutputQueueByKey(id);
        }
Example #2
0
        public async Task TestSuccess()
        {
            // Arrange
            var job = new Job
            {
                Config = new QueryConfig
                {
                    LocalSaveFolder       = Path.GetTempPath(),
                    EntitiesPerUploadFile = 1
                }
            };

            var queueManager = new QueueManager();

            var logger = new LoggerConfiguration()
                         .WriteTo.Console()
                         .CreateLogger();

            using (var cancellationTokenSource = new CancellationTokenSource())
            {
                var createBatchItemsQueueProcessor = new CreateBatchItemsPipelineStep(
                    job.Config,
                    logger,
                    queueManager,
                    new MockProgressMonitor(),
                    cancellationTokenSource.Token);

                var stepNumber = 1;
                queueManager.CreateInputQueue <IJsonObjectQueueItem>(stepNumber);

                createBatchItemsQueueProcessor.CreateOutQueue(stepNumber);

                createBatchItemsQueueProcessor.InitializeWithStepNumber(stepNumber);

                string queryId = "1";

                var jsonObjectQueueItem1 = new JsonObjectQueueItem
                {
                    Document     = JObject.Parse(@"{test:'ff'}"),
                    PropertyName = "foo",
                    QueryId      = queryId
                };

                await createBatchItemsQueueProcessor.InternalHandleAsync(jsonObjectQueueItem1);

                var jsonObjectQueueItem2 = new JsonObjectQueueItem
                {
                    Document     = JObject.Parse(@"{test2:'ff'}"),
                    PropertyName = "foo2",
                    QueryId      = queryId
                };

                // Act
                await createBatchItemsQueueProcessor.InternalHandleAsync(jsonObjectQueueItem2);

                // Assert
                var queues = queueManager.Queues;

                Assert.AreEqual(2, queues.Count);

                var meteredBlockingCollection = queues.First(queue => queue.Key == "SaveBatchQueueItem2").Value;
                var outputQueue = meteredBlockingCollection as IQueue <SaveBatchQueueItem>;

                Assert.IsNotNull(outputQueue);

                Assert.AreEqual(1, outputQueue.Count);

                var saveBatchQueueItem = outputQueue.Take(cancellationTokenSource.Token);

                Assert.AreEqual(0, outputQueue.Count);

                Assert.AreEqual(1, saveBatchQueueItem.ItemsToSave.Count);

                var jsonObjectQueueItem = saveBatchQueueItem.ItemsToSave.First();

                Assert.AreEqual(jsonObjectQueueItem1, jsonObjectQueueItem);

                Assert.AreEqual(jsonObjectQueueItem1.PropertyName, jsonObjectQueueItem.PropertyName);

                // Act
                // now complete the queue
                createBatchItemsQueueProcessor.TestComplete(queryId, true);

                // Assert
                Assert.AreEqual(1, outputQueue.Count);

                saveBatchQueueItem = outputQueue.Take(cancellationTokenSource.Token);

                Assert.AreEqual(0, outputQueue.Count);

                Assert.AreEqual(1, saveBatchQueueItem.ItemsToSave.Count);

                jsonObjectQueueItem = saveBatchQueueItem.ItemsToSave.First();

                Assert.AreEqual(jsonObjectQueueItem2, jsonObjectQueueItem);

                Assert.AreEqual(jsonObjectQueueItem2.PropertyName, jsonObjectQueueItem.PropertyName);
            }
        }