private async Task UpdateNonInlinedPagesAsync( HiveType hive, IReadOnlyList <HiveType> replicaHives, string id, IndexInfo indexInfo, CatalogCommit registrationCommit, HiveMergeResult mergeResult) { var taskFactories = new ConcurrentBag <Func <Task> >(); for (var pageIndex = 0; pageIndex < indexInfo.Items.Count; pageIndex++) { var pageInfo = indexInfo.Items[pageIndex]; if (pageInfo.IsInlined) { _logger.LogInformation( "Moving page {PageNumber}/{PageCount} [{Lower}, {Upper}] from being inlined to having its own blob.", pageIndex + 1, indexInfo.Items.Count, pageInfo.Lower.ToNormalizedString(), pageInfo.Upper.ToNormalizedString()); pageInfo = await pageInfo.CloneToNonInlinedAsync(); indexInfo.RemoveAt(pageIndex); indexInfo.Insert(pageIndex, pageInfo); } else if (!mergeResult.ModifiedPages.Contains(pageInfo)) { _logger.LogInformation( "Skipping unmodified page {PageNumber}/{PageCount} [{Lower}, {Upper}].", pageIndex + 1, indexInfo.Items.Count, pageInfo.Lower.ToNormalizedString(), pageInfo.Upper.ToNormalizedString()); continue; } Guard.Assert(!pageInfo.IsInlined, "The page should not be inlined at this point."); var page = await pageInfo.GetPageAsync(); _entityBuilder.UpdateNonInlinedPageItem(pageInfo.PageItem, hive, id, pageInfo.Count, pageInfo.Lower, pageInfo.Upper); _entityBuilder.UpdateCommit(pageInfo.PageItem, registrationCommit); _entityBuilder.UpdatePage(page, hive, id, pageInfo.Count, pageInfo.Lower, pageInfo.Upper); _entityBuilder.UpdateCommit(page, registrationCommit); var pageNumber = pageIndex + 1; taskFactories.Add(async() => { _logger.LogInformation( "Updating page {PageNumber}/{PageCount} [{Lower}, {Upper}].", pageNumber, indexInfo.Items.Count, pageInfo.Lower.ToNormalizedString(), pageInfo.Upper.ToNormalizedString()); await _storage.WritePageAsync(hive, replicaHives, id, pageInfo.Lower, pageInfo.Upper, page); }); } await ParallelAsync.Repeat( async() => { await Task.Yield(); while (taskFactories.TryTake(out var taskFactory)) { await taskFactory(); } }, _options.Value.MaxConcurrentOperationsPerHive); }