Пример #1
0
        public async Task EvictionAnnouncesHash()
        {
            bool batchProcessWasCalled = false;
            var  nagleQueue            = NagleQueue <ContentHash> .Create(
                hashes => { batchProcessWasCalled = true; return(Task.FromResult(42)); },
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMinutes(1),
                batchSize : 1);

            await TestStore(
                _context,
                _clock,
                async store =>
            {
                var cas      = store as IContentStoreInternal;
                var blobSize = BlobSizeToStartSoftPurging(2);

                using (var stream1 = new MemoryStream(ThreadSafeRandom.GetBytes(blobSize)))
                    using (var stream2 = new MemoryStream(ThreadSafeRandom.GetBytes(blobSize)))
                    {
                        await cas.PutStreamAsync(_context, stream1, ContentHashType).ShouldBeSuccess();
                        _clock.Increment();
                        await cas.PutStreamAsync(_context, stream2, ContentHashType).ShouldBeSuccess();
                        _clock.Increment();
                        await store.SyncAsync(_context);
                    }
            },
                nagleQueue);

            batchProcessWasCalled.Should().BeTrue();
        }
Пример #2
0
        /// <nodoc />
        public VsoSymbolClient(IIpcLogger logger, SymbolConfig config, Client apiClient)
        {
            m_logger    = logger;
            m_apiClient = apiClient;
            m_config    = config;
            m_debugEntryCreateBehavior = config.DebugEntryCreateBehavior;
            m_cancellationSource       = new CancellationTokenSource();

            m_counters = new CounterCollection <SymbolClientCounter>();

            m_logger.Info(I($"[{nameof(VsoSymbolClient)}] Using symbol config: {JsonConvert.SerializeObject(m_config)}"));

            m_credentialFactory = new VssCredentialsFactory(pat: null, new CredentialProviderHelper(m => m_logger.Verbose(m)), m => m_logger.Verbose(m));

            m_symbolClient = new ReloadingSymbolClient(
                logger: logger,
                clientConstructor: CreateSymbolServiceClient);

            m_nagleQueue = NagleQueue <BatchedSymbolFile> .Create(
                maxDegreeOfParallelism : m_config.MaxParallelUploads,
                batchSize : m_config.BatchSize,
                interval : m_config.NagleTime,
                processBatch : ProcessBatchedFilesAsync);

            m_fileUploadQueue = new ActionQueue(m_config.MaxParallelUploads);
        }
Пример #3
0
        public void TestExceptionHandling()
        {
            int callbackCount = 0;
            var queue         = NagleQueue <int> .CreateUnstarted(
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMilliseconds(10),
                batchSize : 2);

            queue.Start(
                processBatch: async data =>
            {
                callbackCount++;
                await Task.Yield();
                var e = new InvalidOperationException(string.Join(", ", data.Select(n => n.ToString())));
                throw e;
            });
            queue.Enqueue(1);
            queue.Enqueue(2);
            queue.Enqueue(3);

            // And if callback fails, the queue itself moves to a faulted state.
            // This will manifest itself in an error during Dispose invocation.
            // This is actually quite problematic, because Dispose method can be called
            // from the finally block (explicitly, or implicitly via using block)
            // and in this case the original exception that caused the finally block invocation
            // will be masked by the exception from Dispose method.
            // Work item: 1741215

            // Dispose method propagates the error thrown in the callback.
            Assert.Throws <InvalidOperationException>(() => queue.Dispose());

            // Once callback fails, it won't be called any more
            callbackCount.Should().Be(1);
        }
Пример #4
0
        private RuntimeCacheMissAnalyzer(
            FingerprintStoreExecutionLogTarget logTarget,
            LoggingContext loggingContext,
            PipExecutionContext context,
            FingerprintStore previousFingerprintStore,
            IReadonlyDirectedGraph graph,
            IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance,
            IConfiguration configuration,
            string downLoadedPreviousFingerprintStoreSavedPath,
            FingerprintStoreTestHooks testHooks = null)
        {
            m_loggingContext         = loggingContext;
            m_logTarget              = logTarget;
            m_context                = context;
            PreviousFingerprintStore = previousFingerprintStore;
            m_visitor                = new NodeVisitor(graph);
            m_changedPips            = new VisitationTracker(graph);
            m_pipCacheMissesDict     = new ConcurrentDictionary <PipId, PipCacheMissInfo>();
            m_runnablePipPerformance = runnablePipPerformance;

            m_batchLoggingQueue = configuration.Logging.CacheMissBatch ? NagleQueue <JProperty> .Create(
                BatchLogging,
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMinutes(5),
                batchSize : 100) : null;


            m_testHooks = testHooks;
            m_testHooks?.InitRuntimeCacheMisses();
            m_configuration = configuration;
            m_downLoadedPreviousFingerprintStoreSavedPath = downLoadedPreviousFingerprintStoreSavedPath;
        }
Пример #5
0
        private RuntimeCacheMissAnalyzer(
            FingerprintStoreExecutionLogTarget logTarget,
            LoggingContext loggingContext,
            PipExecutionContext context,
            FingerprintStore previousFingerprintStore,
            IReadonlyDirectedGraph graph,
            IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance,
            CacheMissDiffFormat cacheMissDiffFormat,
            bool cacheMissBatch,
            FingerprintStoreTestHooks testHooks = null)
        {
            m_loggingContext         = loggingContext;
            m_logTarget              = logTarget;
            m_context                = context;
            PreviousFingerprintStore = previousFingerprintStore;
            m_visitor                = new NodeVisitor(graph);
            m_changedPips            = new VisitationTracker(graph);
            m_pipCacheMissesDict     = new ConcurrentDictionary <PipId, PipCacheMissInfo>();
            m_runnablePipPerformance = runnablePipPerformance;
            m_cacheMissDiffFormat    = cacheMissDiffFormat;
            m_maxCacheMissCanPerform = cacheMissBatch ? EngineEnvironmentSettings.MaxNumPipsForCacheMissAnalysis.Value * EngineEnvironmentSettings.MaxMessagesPerBatch : EngineEnvironmentSettings.MaxNumPipsForCacheMissAnalysis.Value;

            m_batchLoggingQueue = cacheMissBatch ? NagleQueue <JProperty> .Create(
                BatchLogging,
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMinutes(1),
                batchSize : EngineEnvironmentSettings.MaxMessagesPerBatch) : null;


            m_testHooks = testHooks;
            m_testHooks?.InitRuntimeCacheMisses();
        }
Пример #6
0
        public AzureBlobStorageLog(AzureBlobStorageLogConfiguration configuration, OperationContext context, IClock clock, IAbsFileSystem fileSystem, ITelemetryFieldsProvider telemetryFieldsProvider, AzureBlobStorageCredentials credentials)
        {
            _configuration = configuration;

            _context    = context;
            _clock      = clock;
            _fileSystem = fileSystem;
            _telemetryFieldsProvider = telemetryFieldsProvider;

            var cloudBlobClient = credentials.CreateCloudBlobClient();

            _container = cloudBlobClient.GetContainerReference(configuration.ContainerName);

            _writeQueue = NagleQueue <string> .CreateUnstarted(
                configuration.WriteMaxDegreeOfParallelism,
                configuration.WriteMaxInterval,
                configuration.WriteMaxBatchSize);

            _uploadQueue = NagleQueue <LogFile> .CreateUnstarted(
                configuration.UploadMaxDegreeOfParallelism,
                configuration.UploadMaxInterval,
                1);

            // TODO: this component doesn't have a quota, which could potentially be useful. If Azure Blob Storage
            // becomes unavailable for an extended period of time, we might cause disk space issues.
        }
Пример #7
0
        public TestFileSystemContentStoreInternal(
            IAbsFileSystem fileSystem,
            IClock clock,
            AbsolutePath rootPath,
            ContentStoreConfiguration configuration,
            Action <ContentHashWithSize> onContentAdded   = null,
            Action <ContentHashWithSize> onContentEvicted = null,
            NagleQueue <ContentHash> nagleQueue           = null,
            ContentStoreSettings settings = null,
            DistributedEvictionSettings distributedEvictionSettings = null)
            : base(fileSystem, clock, rootPath, new ConfigurationModel(configuration), nagleQueue: nagleQueue, settings: settings, distributedEvictionSettings: distributedEvictionSettings)
        {
            Contract.Requires(fileSystem != null);
            Contract.Requires(clock != null);
            Contract.Requires(rootPath != null);
            Contract.Requires(configuration != null);

            _onContentAdded   = onContentAdded;
            _onContentEvicted = onContentEvicted;

            if (_onContentAdded != null || _onContentEvicted != null)
            {
                Announcer = this;
            }
        }
Пример #8
0
        public void ResumeShouldTriggerBatchOnTime()
        {
            bool processBatchIsCalled = false;
            var  queue = NagleQueue <int> .Create(
                processBatch : data =>
            {
                processBatchIsCalled = true;
                return(Task.FromResult(42));
            },
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMilliseconds(1),
                batchSize : 10);

            var suspender = queue.Suspend();

            Thread.Sleep(1000);
            queue.Enqueue(42);
            suspender.Dispose(); // This should resume the queue and restart the timer

            Thread.Sleep(1000);  // Definitely longer than the configured interval provided to NagleQueue

            // It means that the queue should call the callback and we can rely on that.

            Assert.True(processBatchIsCalled);
        }
Пример #9
0
        public void TwoItemsAreProcessedInParallel()
        {
            var threads = new List <int>();

            using (var queue = NagleQueue <int> .Create(
                       processBatch: async data =>
            {
                lock (threads)
                {
                    threads.Add(Thread.CurrentThread.ManagedThreadId);
                }

                await Task.Delay(1);
            },
                       maxDegreeOfParallelism: 2,
                       interval: TimeSpan.FromSeconds(1),
                       batchSize: 2))
            {
                queue.Enqueue(1);
                queue.Enqueue(2);
                queue.Enqueue(3);
                queue.Enqueue(4);
            }

            Assert.Equal(2, threads.Count);
        }
Пример #10
0
        public void ItemsInEagerBlocksAreProcessedEagerly()
        {
            int dataLength            = 0;
            var processBatchWasCalled = false;
            var processBatchEvent     = new ManualResetEvent(false);

            using (var queue = NagleQueue <int> .Create(
                       processBatch: data =>
            {
                dataLength = data.Length;
                processBatchWasCalled = true;
                processBatchEvent.Set();
                return(Task.FromResult(42));
            },
                       maxDegreeOfParallelism: 1,
                       interval: TimeSpan.FromMinutes(1),
                       // batchSize is one, so the processing is eager.
                       batchSize: 1))
            {
                queue.Enqueue(42);
                processBatchEvent.WaitOne(5000);
                Assert.True(processBatchWasCalled, "processBatch should be called eagerly.");
                Assert.Equal(1, dataLength);
            }
        }
Пример #11
0
        /// <nodoc />
        public VsoClient(IIpcLogger logger, DropDaemon dropDaemon)
        {
            Contract.Requires(dropDaemon?.DropConfig != null);

            m_logger             = logger;
            m_dropDaemon         = dropDaemon;
            m_config             = dropDaemon.DropConfig;
            m_cancellationSource = new CancellationTokenSource();

            logger.Info("Using drop config: " + JsonConvert.SerializeObject(m_config));

            Stats = new DropStatistics();

            // instantiate drop client
            m_dropClient = new ReloadingDropServiceClient(
                logger: logger,
                clientConstructor: CreateDropServiceClient);

            m_nagleQueue = NagleQueue <AddFileItem> .Create(
                maxDegreeOfParallelism : m_config.MaxParallelUploads,
                batchSize : m_config.BatchSize,
                interval : m_config.NagleTime,
                processBatch : ProcessAddFilesAsync);

            if (m_config.ArtifactLogName != null)
            {
                DropAppTraceSource.SingleInstance.SetSourceLevel(System.Diagnostics.SourceLevels.Verbose);
                Tracer.AddFileTraceListener(Path.Combine(m_config.LogDir, m_config.ArtifactLogName));
            }
        }
Пример #12
0
        public AzureBlobStorageLog(
            AzureBlobStorageLogConfiguration configuration,
            OperationContext context,
            IClock clock,
            IAbsFileSystem fileSystem,
            ITelemetryFieldsProvider telemetryFieldsProvider,
            CloudBlobContainer container,
            IReadOnlyDictionary <string, string> additionalBlobMetadata)
        {
            _configuration = configuration;

            _context    = context;
            _clock      = clock;
            _fileSystem = fileSystem;
            _telemetryFieldsProvider = telemetryFieldsProvider;
            _container = container;
            _additionalBlobMetadata = additionalBlobMetadata;

            _writeQueue = NagleQueue <string> .CreateUnstarted(
                configuration.WriteMaxDegreeOfParallelism,
                configuration.WriteMaxInterval,
                configuration.WriteMaxBatchSize);

            _uploadQueue = NagleQueue <LogFile> .CreateUnstarted(
                configuration.UploadMaxDegreeOfParallelism,
                configuration.UploadMaxInterval,
                1);

            // TODO: this component doesn't have a quota, which could potentially be useful. If Azure Blob Storage
            // becomes unavailable for an extended period of time, we might cause disk space issues.
        }
Пример #13
0
 /// <summary>
 /// Creates a <see cref="FileSystemContentStore"/> at <see cref="rootPath"/>
 /// </summary>
 public static IContentStore CreateContentStore(
     IAbsFileSystem fileSystem,
     AbsolutePath rootPath,
     NagleQueue <ContentHash> evictionAnnouncer,
     DistributedEvictionSettings distributedEvictionSettings,
     ContentStoreSettings contentStoreSettings,
     TrimBulkAsync trimBulkAsync,
     ConfigurationModel configurationModel = null)
 => new FileSystemContentStore(
     fileSystem, SystemClock.Instance, rootPath, configurationModel, evictionAnnouncer, distributedEvictionSettings, trimBulkAsync, contentStoreSettings);
Пример #14
0
        /// <nodoc />
        protected override Task <BoolResult> StartupCoreAsync(OperationContext context)
        {
            TouchNagleQueue = NagleQueue <ContentHashWithSize> .Create(
                hashes => BackgroundTouchBulkAsync(context, hashes),
                RedisContentLocationStoreConstants.BatchDegreeOfParallelism,
                RedisContentLocationStoreConstants.BatchInterval,
                RedisContentLocationStoreConstants.DefaultBatchSize);

            return(BoolResult.SuccessTask);
        }
 protected Task TestStore
 (
     Context context,
     ITestClock clock,
     Func <TestFileSystemContentStoreInternal, Task> func,
     NagleQueue <ContentHash> nagleBlock
 )
 {
     return(TestStoreImpl(context, clock, func, nagleBlock: nagleBlock));
 }
Пример #16
0
 /// <summary>
 /// Backward-compat constructor.
 /// </summary>
 public FileSystemContentStore(
     IAbsFileSystem fileSystem,
     IClock clock,
     AbsolutePath rootPath,
     ConfigurationModel?configurationModel = null,
     NagleQueue <ContentHash>?nagleQueue   = null,
     DistributedEvictionSettings?distributedEvictionSettings = null,
     TrimBulkAsync?trimBulkAsync   = null,
     ContentStoreSettings?settings = null)
     : this(fileSystem, clock, rootPath, configurationModel, distributedEvictionSettings?.DistributedStore, settings)
 {
 }
Пример #17
0
        public void PostAfterDispose()
        {
            var queue = NagleQueue <int> .Create(
                processBatch : data =>
            {
                return(Task.FromResult(42));
            },
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMinutes(1),
                batchSize : 10);

            queue.Dispose();
            Assert.Throws <ObjectDisposedException>(() => queue.Enqueue(42));
        }
        protected virtual TestFileSystemContentStoreInternal CreateElastic(
            AbsolutePath rootPath,
            ITestClock clock,
            NagleQueue <ContentHash> nagleBlock = null,
            MaxSizeQuota initialQuota           = null,
            int?windowSize = default(int?))
        {
            var maxSizeQuota = initialQuota ?? new MaxSizeQuota(MaxSizeHard, MaxSizeSoft);

            // Some tests rely on maxSizeQuota being set in the configuration although it is ignored if elasticity is enabled.
            var config = new ContentStoreConfiguration(maxSizeQuota: maxSizeQuota, enableElasticity: true, initialElasticSize: maxSizeQuota, historyWindowSize: windowSize);

            return(new TestFileSystemContentStoreInternal(FileSystem, clock, rootPath, config, nagleQueue: nagleBlock, settings: ContentStoreSettings));
        }
Пример #19
0
        /// <inheritdoc />
        protected override async Task <BoolResult> StartupCoreAsync(OperationContext context)
        {
            // NOTE: We create and start the content location store before the inner content store just in case the
            // inner content store starts background eviction after startup. We need the content store to be initialized
            // so that it can be queried and used to unregister content.
            await _contentLocationStoreFactory.StartupAsync(context).ThrowIfFailure();

            _contentLocationStore = await _contentLocationStoreFactory.CreateAsync();

            _distributedCopier = _distributedCopierFactory(_contentLocationStore);
            await _distributedCopier.StartupAsync(context).ThrowIfFailure();

            if (_contentLocationStore is TransitioningContentLocationStore tcs)
            {
                tcs.LocalLocationStore.PreStartupInitialize(context, InnerContentStore as ILocalContentStore, _distributedCopier);
            }

            // Initializing inner store before initializing LocalLocationStore because
            // LocalLocationStore may use inner store for reconciliation purposes
            await InnerContentStore.StartupAsync(context).ThrowIfFailure();

            await _contentLocationStore.StartupAsync(context).ThrowIfFailure();

            Func <ContentHash[], Task> evictionHandler;
            var localContext = new Context(context);

            if (_enableDistributedEviction)
            {
                evictionHandler = hashes => EvictContentAsync(localContext, hashes);
            }
            else
            {
                evictionHandler = hashes => DistributedGarbageCollectionAsync(localContext, hashes);
            }

            // Queue is created in unstarted state because the eviction function
            // requires the context passed at startup. So we start the queue here.
            _evictionNagleQueue.Start(evictionHandler);

            var touchContext = new Context(context);

            _touchNagleQueue = NagleQueue <ContentHashWithSize> .Create(
                hashes => TouchBulkAsync(touchContext, hashes),
                Redis.RedisContentLocationStoreConstants.BatchDegreeOfParallelism,
                Redis.RedisContentLocationStoreConstants.BatchInterval,
                batchSize : _locationStoreBatchSize);

            return(BoolResult.Success);
        }
Пример #20
0
        /// <inheritdoc />
        public void Start(OperationContext context)
        {
            // Using nagle queues to "batch" messages together and to avoid writing them to the logs one by one.
            var outputMessagesNagleQueue = NagleQueue <string> .Create(
                messages =>
            {
                _tracer.Debug(context, $"Service Output: {string.Join(Environment.NewLine, messages)}");
                return(Task.CompletedTask);
            },
                maxDegreeOfParallelism : 1, interval : TimeSpan.FromSeconds(1), batchSize : 1024);

            var errorMessagesNagleQueue = NagleQueue <string> .Create(
                messages =>
            {
                _tracer.Error(context, $"Service Error: {string.Join(Environment.NewLine, messages)}");
                return(Task.CompletedTask);
            },
                maxDegreeOfParallelism : 1, interval : TimeSpan.FromSeconds(1), batchSize : 1024);

            _process.OutputDataReceived += (s, e) =>
            {
                if (!string.IsNullOrEmpty(e.Data))
                {
                    outputMessagesNagleQueue.Enqueue(e.Data);
                }
            };

            _process.ErrorDataReceived += (s, e) =>
            {
                if (!string.IsNullOrEmpty(e.Data))
                {
                    errorMessagesNagleQueue.Enqueue(e.Data);
                }
            };

            _process.Exited += (sender, args) =>
            {
                // Dispose will drain all the existing items from the message queues.
                outputMessagesNagleQueue.Dispose();
                errorMessagesNagleQueue.Dispose();
            };

            _process.Start();

            _process.BeginOutputReadLine();
            _process.BeginErrorReadLine();
            _started = true;
        }
Пример #21
0
        /// <nodoc />
        public DistributedContentStore(
            MachineLocation localMachineLocation,
            AbsolutePath localCacheRoot,
            Func <NagleQueue <ContentHash>, DistributedEvictionSettings, ContentStoreSettings, TrimBulkAsync, IContentStore> innerContentStoreFunc,
            IContentLocationStoreFactory contentLocationStoreFactory,
            DistributedContentStoreSettings settings,
            DistributedContentCopier <T> distributedCopier,
            IClock clock = null,
            ContentStoreSettings contentStoreSettings = null)
        {
            Contract.Requires(settings != null);

            LocalMachineLocation         = localMachineLocation;
            _contentLocationStoreFactory = contentLocationStoreFactory;
            _clock                  = clock;
            _distributedCopier      = distributedCopier;
            _copierWorkingDirectory = new DisposableDirectory(distributedCopier.FileSystem, localCacheRoot / "Temp");

            contentStoreSettings = contentStoreSettings ?? ContentStoreSettings.DefaultSettings;
            _settings            = settings;

            // Queue is created in unstarted state because the eviction function
            // requires the context passed at startup.
            _evictionNagleQueue = NagleQueue <ContentHash> .CreateUnstarted(
                Redis.RedisContentLocationStoreConstants.BatchDegreeOfParallelism,
                Redis.RedisContentLocationStoreConstants.BatchInterval,
                _settings.LocationStoreBatchSize);

            _enableDistributedEviction = _settings.ReplicaCreditInMinutes != null;
            var distributedEvictionSettings = _enableDistributedEviction ? SetUpDistributedEviction(_settings.ReplicaCreditInMinutes, _settings.LocationStoreBatchSize) : null;

            var enableTouch = _settings.ContentHashBumpTime.HasValue;

            if (enableTouch)
            {
                _contentTrackerUpdater = new ContentTrackerUpdater(ScheduleBulkTouch, _settings.ContentHashBumpTime.Value, clock: _clock);
            }

            TrimBulkAsync trimBulkAsync = null;

            InnerContentStore = innerContentStoreFunc(_evictionNagleQueue, distributedEvictionSettings, contentStoreSettings, trimBulkAsync);

            if (settings.PinConfiguration?.IsPinCachingEnabled == true)
            {
                _pinCache = new PinCache(clock: _clock);
            }
        }
Пример #22
0
        /// <summary>
        /// Finish setting up distributed eviction.
        /// </summary>
        public void InitializeDistributedEviction(
            UpdateContentWithLastAccessTimeAsync updateMetadataFunc,
            Tracer tracer,
            PinnedSizeChecker pinnedSizeChecker,
            NagleQueue <ContentHash> reregisterHashQueue)
        {
            Contract.Assert(updateMetadataFunc != null);
            Contract.Assert(pinnedSizeChecker != null);
            Contract.Assert(tracer != null);
            Contract.Assert(reregisterHashQueue != null);

            UpdateContentWithLastAccessTimeAsync = updateMetadataFunc;
            Tracer              = tracer;
            PinnedSizeChecker   = pinnedSizeChecker;
            ReregisterHashQueue = reregisterHashQueue;
            IsInitialized       = true;
        }
Пример #23
0
        public void PendingItemsAreProcessedOnDispose()
        {
            bool processBatchWasCalled = false;
            var  queue = NagleQueue <int> .Create(
                processBatch : data =>
            {
                processBatchWasCalled = true;
                return(Task.FromResult(42));
            },
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMinutes(1),
                batchSize : 10);

            queue.Enqueue(42);
            Assert.False(processBatchWasCalled, "processBatch should not be called yet.");

            queue.Dispose();
            Assert.True(processBatchWasCalled, "processBatch should be called during disposal");
        }
Пример #24
0
        public KustoNotifier(Configuration configuration, ILogger logger, IKustoIngestClient kustoIngestClient)
        {
            _configuration     = configuration;
            _logger            = logger;
            _kustoIngestClient = kustoIngestClient;

            _kustoIngestionProperties = new KustoIngestionProperties(_configuration.KustoDatabaseName, _configuration.KustoTableName)
            {
                Format = DataSourceFormat.json,
            };

            Contract.RequiresNotNullOrEmpty(_configuration.KustoTableIngestionMappingName,
                                            "Kusto ingestion will fail to authenticate without a proper ingestion mapping.");
            _kustoIngestionProperties.JSONMappingReference = _configuration.KustoTableIngestionMappingName;

            _queue = NagleQueue <T> .Create(FlushAsync,
                                            _configuration.MaxDegreeOfParallelism,
                                            _configuration.FlushInterval,
                                            _configuration.BatchSize);
        }
Пример #25
0
        public void ItemsAreProcessedInBatches()
        {
            int batchSize = 0;

            using (var queue = NagleQueue <int> .Create(
                       processBatch: data =>
            {
                batchSize = data.Length;
                return(Task.FromResult(42));
            },
                       maxDegreeOfParallelism: 1,
                       interval: TimeSpan.FromMilliseconds(10),
                       batchSize: 2))
            {
                queue.Enqueue(1);
                queue.Enqueue(2);
            }

            Assert.Equal(2, batchSize);
        }
Пример #26
0
 /// <summary>
 /// Backward-compat constructor.
 /// </summary>
 public FileSystemContentStore(
     IAbsFileSystem fileSystem,
     IClock clock,
     AbsolutePath rootPath,
     ConfigurationModel configurationModel,
     NagleQueue <ContentHash> nagleQueue,
     RefCountdown sensitiveSessionCount,
     DistributedEvictionSettings distributedEvictionSettings,
     bool checkFiles,
     TrimBulkAsync trimBulkAsync)
     : this(
         fileSystem,
         clock,
         rootPath,
         configurationModel,
         nagleQueue,
         distributedEvictionSettings,
         trimBulkAsync,
         settings : new ContentStoreSettings() { CheckFiles = checkFiles })
 {
 }
        private async Task TestStoreImpl
        (
            Context context,
            ITestClock clock,
            Func <TestFileSystemContentStoreInternal, Task> func,
            DisposableDirectory testDirectory   = null,
            IContentChangeAnnouncer announcer   = null,
            NagleQueue <ContentHash> nagleBlock = null,
            Action <TestFileSystemContentStoreInternal> preStartupAction = null
        )
        {
            using (var tempTestDirectory = new DisposableDirectory(FileSystem))
            {
                DisposableDirectory disposableDirectory = testDirectory ?? tempTestDirectory;
                using (var store = Create(disposableDirectory.Path, clock, nagleBlock))
                {
                    if (announcer != null)
                    {
                        store.Announcer = announcer;
                    }

                    store.Should().NotBeNull();
                    try
                    {
                        preStartupAction?.Invoke(store);
                        var r = await store.StartupAsync(context);

                        r.ShouldBeSuccess();
                        await func(store);
                    }
                    finally
                    {
                        if (!store.ShutdownStarted)
                        {
                            await store.ShutdownAsync(context).ShouldBeSuccess();
                        }
                    }
                }
            }
        }
Пример #28
0
        public void ItemsAreProcessedBasedOnInterval()
        {
            var processBatchWasCalled = false;
            var processBatchEvent     = new ManualResetEvent(false);

            using (var queue = NagleQueue <int> .Create(
                       processBatch: data =>
            {
                processBatchWasCalled = true;
                processBatchEvent.Set();
                return(Task.FromResult(42));
            },
                       maxDegreeOfParallelism: 1,
                       interval: TimeSpan.FromMilliseconds(10),
                       batchSize: 2))
            {
                queue.Enqueue(1);
                Assert.False(processBatchWasCalled);
                processBatchEvent.WaitOne(5000);
                Assert.True(processBatchWasCalled);
            }
        }
Пример #29
0
        public void EnqueingItemsInfrequentlyShouldAlwaysTriggerCallbackOnTime()
        {
            int processBatchIsCalled = 0;
            var queue = NagleQueue <int> .Create(
                processBatch : data =>
            {
                processBatchIsCalled++;
                return(Task.FromResult(42));
            },
                maxDegreeOfParallelism : 1,
                interval : TimeSpan.FromMilliseconds(10),
                batchSize : 10);

            queue.Enqueue(42);

            Thread.Sleep(100);
            Assert.Equal(1, processBatchIsCalled);

            queue.Enqueue(42);

            Thread.Sleep(100);
            Assert.Equal(2, processBatchIsCalled);
        }
Пример #30
0
            static async Task testCore(int attempt)
            {
                var log = TestGlobal.Logger;

                TestGlobal.Logger.Debug($"Running {attempt} attempt.");
                Task task = null;

                using (var queue = NagleQueue <int> .Create(
                           processBatch: data => { return(Task.FromResult(42)); },
                           maxDegreeOfParallelism: 1,
                           interval: TimeSpan.FromMilliseconds(1),
                           batchSize: 100))
                {
                    var itemsEnqueuedSource = TaskSourceSlim.Create <object>();

                    task = Task.Run(
                        () =>
                    {
                        using (queue.Suspend())
                        {
                            for (int i = 0; i < 1_000_000; i++)
                            {
                                queue.Enqueue(i);
                            }

                            itemsEnqueuedSource.SetResult(null);
                        }
                    });

                    // The items are added to the queue and the suspender is about to push all the items to the queue
                    await itemsEnqueuedSource.Task;
                    // Meanwhile, the queue itself will be disposed at the end of the block.
                    // So we're introducing a race condition between the suspender and the dispose method of the queue
                }

                await task; // the task should not fail!
            }