private async Task LoadAsync(TimeSpan timeout, bool shouldReload, CancellationToken token) { var acquired = false; try { acquired = await _lock.WaitAsync(timeout, token); if (!acquired) { _logger.LogInformation("Another thread is already reloading the auxiliary data."); } else { if (!shouldReload && Initialized) { return; } _logger.LogInformation("Starting the reload of auxiliary data."); var stopwatch = Stopwatch.StartNew(); // Load the auxiliary files in parallel. const string downloadsName = nameof(_data.Downloads); const string verifiedPackagesName = nameof(_data.VerifiedPackages); var downloadsTask = LoadAsync(_data?.Downloads, _downloadDataClient.ReadLatestIndexedAsync); var verifiedPackagesTask = LoadAsync(_data?.VerifiedPackages, _verifiedPackagesDataClient.ReadLatestAsync); await Task.WhenAll(downloadsTask, verifiedPackagesTask); var downloads = await downloadsTask; var verifiedPackages = await verifiedPackagesTask; // Keep track of what was actually reloaded and what didn't change. var reloadedNames = new List <string>(); var notModifiedNames = new List <string>(); (ReferenceEquals(_data?.Downloads, downloads) ? notModifiedNames : reloadedNames).Add(downloadsName); (ReferenceEquals(_data?.VerifiedPackages, verifiedPackages) ? notModifiedNames : reloadedNames).Add(verifiedPackagesName); // Reference assignment is atomic, so this is what makes the data available for readers. _data = new AuxiliaryData( DateTimeOffset.UtcNow, downloads, verifiedPackages); // Track the counts regarding the string cache status. _telemetryService.TrackAuxiliaryFilesStringCache( _stringCache.StringCount, _stringCache.CharCount, _stringCache.RequestCount, _stringCache.HitCount); _stringCache.ResetCounts(); stopwatch.Stop(); _telemetryService.TrackAuxiliaryFilesReload(reloadedNames, notModifiedNames, stopwatch.Elapsed); _logger.LogInformation( "Done reloading auxiliary data. Took {Duration}. Reloaded: {Reloaded}. Not modified: {NotModified}", stopwatch.Elapsed, reloadedNames, notModifiedNames); } } finally { if (acquired) { _lock.Release(); } } }