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.
        }
        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.
        }
        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);
        }
Exemple #4
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);
            }
        }
Exemple #5
0
        /// <nodoc />
        public DistributedContentStore(
            byte[] localMachineLocation,
            Func <NagleQueue <ContentHash>, DistributedEvictionSettings, ContentStoreSettings, TrimBulkAsync, IContentStore> innerContentStoreFunc,
            IContentLocationStoreFactory contentLocationStoreFactory,
            IFileExistenceChecker <T> fileExistenceChecker,
            IFileCopier <T> fileCopier,
            IPathTransformer <T> pathTransform,
            ICopyRequester copyRequester,
            ReadOnlyDistributedContentSession <T> .ContentAvailabilityGuarantee contentAvailabilityGuarantee,
            AbsolutePath tempFolderForCopies,
            IAbsFileSystem fileSystem,
            int locationStoreBatchSize,
            DistributedContentStoreSettings settings,
            int?replicaCreditInMinutes = null,
            IClock clock = null,
            bool enableRepairHandling    = false,
            TimeSpan?contentHashBumpTime = null,
            ContentStoreSettings contentStoreSettings = null)
        {
            Contract.Requires(settings != null);

            LocalMachineLocation          = new MachineLocation(localMachineLocation);
            _enableRepairHandling         = enableRepairHandling;
            _contentLocationStoreFactory  = contentLocationStoreFactory;
            _contentAvailabilityGuarantee = contentAvailabilityGuarantee;
            _locationStoreBatchSize       = locationStoreBatchSize;

            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,
                _locationStoreBatchSize);

            _distributedCopierFactory = (contentLocationStore) =>
            {
                return(new DistributedContentCopier <T>(
                           tempFolderForCopies,
                           _settings,
                           fileSystem,
                           fileCopier,
                           fileExistenceChecker,
                           copyRequester,
                           pathTransform,
                           contentLocationStore));
            };

            _enableDistributedEviction = replicaCreditInMinutes != null;
            var distributedEvictionSettings = _enableDistributedEviction ? SetUpDistributedEviction(replicaCreditInMinutes, locationStoreBatchSize) : null;

            var enableTouch = contentHashBumpTime.HasValue;

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

            TrimBulkAsync trimBulkAsync = null;

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

            if (settings.PinConfiguration?.UsePinCache == true)
            {
                _pinCache = new PinCache(clock: clock);
            }
        }
Exemple #6
0
 private NagleQueue <ContentHash> EmptyNagleQueue()
 {
     return(NagleQueue <ContentHash> .CreateUnstarted(1, TimeSpan.MaxValue, 42));
 }