Exemple #1
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);
Exemple #2
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)
 {
 }
Exemple #3
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 #4
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 })
 {
 }
        /// <summary>
        ///     Initializes a new instance of the <see cref="FileSystemContentStore" /> class.
        /// </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)
        {
            Contract.Requires(fileSystem != null);
            Contract.Requires(clock != null);
            Contract.Requires(rootPath != null);

            int singleInstanceTimeoutSeconds = ContentStoreConfiguration.DefaultSingleInstanceTimeoutSeconds;

            if (configurationModel?.InProcessConfiguration != null)
            {
                // TODO: Stop using the configurationModel's SingleInstanceTimeout (bug 1365340)
                // because FileSystemContentStore doesn't respect the config file's value
                singleInstanceTimeoutSeconds = configurationModel.InProcessConfiguration.SingleInstanceTimeoutSeconds;
            }

            // FileSystemContentStore implicitly uses a null component name for compatibility with older versions' directory locks.
            _directoryLock = new DirectoryLock(rootPath, fileSystem, TimeSpan.FromSeconds(singleInstanceTimeoutSeconds));

            Store = new FileSystemContentStoreInternal(
                fileSystem,
                clock,
                rootPath,
                configurationModel,
                nagleQueue,
                distributedEvictionSettings,
                settings);

            _trimBulkAsync = trimBulkAsync;
        }
Exemple #6
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);
            }
        }
        public IContentStore CreateContentStore(
            AbsolutePath localCacheRoot,
            NagleQueue <ContentHash> evictionAnnouncer              = null,
            ProactiveReplicationArgs replicationSettings            = null,
            DistributedEvictionSettings distributedEvictionSettings = null,
            bool checkLocalFiles        = true,
            TrimBulkAsync trimBulkAsync = null)
        {
            var redisContentLocationStoreConfiguration = new RedisContentLocationStoreConfiguration
            {
                RedisBatchPageSize    = _distributedSettings.RedisBatchPageSize,
                BlobExpiryTimeMinutes = _distributedSettings.BlobExpiryTimeMinutes,
                MaxBlobCapacity       = _distributedSettings.MaxBlobCapacity,
                MaxBlobSize           = _distributedSettings.MaxBlobSize,
                EvictionWindowSize    = _distributedSettings.EvictionWindowSize
            };

            ApplyIfNotNull(_distributedSettings.ReplicaCreditInMinutes, v => redisContentLocationStoreConfiguration.ContentLifetime = TimeSpan.FromMinutes(v));
            ApplyIfNotNull(_distributedSettings.MachineRisk, v => redisContentLocationStoreConfiguration.MachineRisk = v);
            ApplyIfNotNull(_distributedSettings.LocationEntryExpiryMinutes, v => redisContentLocationStoreConfiguration.LocationEntryExpiry = TimeSpan.FromMinutes(v));
            ApplyIfNotNull(_distributedSettings.MachineExpiryMinutes, v => redisContentLocationStoreConfiguration.MachineExpiry             = TimeSpan.FromMinutes(v));

            redisContentLocationStoreConfiguration.ReputationTrackerConfiguration.Enabled = _distributedSettings.IsMachineReputationEnabled;

            if (_distributedSettings.IsContentLocationDatabaseEnabled)
            {
                var dbConfig = new RocksDbContentLocationDatabaseConfiguration(localCacheRoot / "LocationDb")
                {
                    StoreClusterState = _distributedSettings.StoreClusterStateInDatabase
                };

                redisContentLocationStoreConfiguration.Database = dbConfig;
                if (_distributedSettings.ContentLocationDatabaseGcIntervalMinutes != null)
                {
                    dbConfig.LocalDatabaseGarbageCollectionInterval = TimeSpan.FromMinutes(_distributedSettings.ContentLocationDatabaseGcIntervalMinutes.Value);
                }

                ApplyIfNotNull(_distributedSettings.ContentLocationDatabaseCacheEnabled, v => dbConfig.CacheEnabled = v);
                ApplyIfNotNull(_distributedSettings.ContentLocationDatabaseFlushDegreeOfParallelism, v => dbConfig.FlushDegreeOfParallelism         = v);
                ApplyIfNotNull(_distributedSettings.ContentLocationDatabaseFlushSingleTransaction, v => dbConfig.FlushSingleTransaction             = v);
                ApplyIfNotNull(_distributedSettings.ContentLocationDatabaseFlushPreservePercentInMemory, v => dbConfig.FlushPreservePercentInMemory = v);
                ApplyIfNotNull(_distributedSettings.ContentLocationDatabaseCacheMaximumUpdatesPerFlush, v => dbConfig.CacheMaximumUpdatesPerFlush   = v);
                ApplyIfNotNull(_distributedSettings.ContentLocationDatabaseCacheFlushingMaximumInterval, v => dbConfig.CacheFlushingMaximumInterval = v);

                ApplySecretSettingsForLlsAsync(redisContentLocationStoreConfiguration, localCacheRoot).GetAwaiter().GetResult();
            }

            if (_distributedSettings.IsRedisGarbageCollectionEnabled)
            {
                redisContentLocationStoreConfiguration.GarbageCollectionConfiguration = new RedisGarbageCollectionConfiguration()
                {
                    MaximumEntryLastAccessTime = TimeSpan.FromMinutes(30)
                };
            }
            else
            {
                redisContentLocationStoreConfiguration.GarbageCollectionConfiguration = null;
            }

            var localMachineLocation = _arguments.PathTransformer.GetLocalMachineLocation(localCacheRoot);
            var contentHashBumpTime  = TimeSpan.FromMinutes(_distributedSettings.ContentHashBumpTimeMinutes);

            // RedisContentSecretName and RedisMachineLocationsSecretName can be null. HostConnectionStringProvider won't fail in this case.
            IConnectionStringProvider contentConnectionStringProvider          = TryCreateRedisConnectionStringProvider(_redisContentSecretNames.RedisContentSecretName);
            IConnectionStringProvider machineLocationsConnectionStringProvider = TryCreateRedisConnectionStringProvider(_redisContentSecretNames.RedisMachineLocationsSecretName);

            var redisContentLocationStoreFactory = new RedisContentLocationStoreFactory(
                contentConnectionStringProvider,
                machineLocationsConnectionStringProvider,
                SystemClock.Instance,
                contentHashBumpTime,
                _keySpace,
                localMachineLocation,
                configuration: redisContentLocationStoreConfiguration
                );

            ReadOnlyDistributedContentSession <AbsolutePath> .ContentAvailabilityGuarantee contentAvailabilityGuarantee;
            if (string.IsNullOrEmpty(_distributedSettings.ContentAvailabilityGuarantee))
            {
                contentAvailabilityGuarantee =
                    ReadOnlyDistributedContentSession <AbsolutePath> .ContentAvailabilityGuarantee
                    .FileRecordsExist;
            }
            else if (!Enum.TryParse(_distributedSettings.ContentAvailabilityGuarantee, true, out contentAvailabilityGuarantee))
            {
                throw new ArgumentException($"Unable to parse {nameof(_distributedSettings.ContentAvailabilityGuarantee)}: [{_distributedSettings.ContentAvailabilityGuarantee}]");
            }

            PinConfiguration pinConfiguration = null;

            if (_distributedSettings.IsPinBetterEnabled)
            {
                pinConfiguration = new PinConfiguration();
                if (_distributedSettings.PinRisk.HasValue)
                {
                    pinConfiguration.PinRisk = _distributedSettings.PinRisk.Value;
                }
                if (_distributedSettings.MachineRisk.HasValue)
                {
                    pinConfiguration.MachineRisk = _distributedSettings.MachineRisk.Value;
                }
                if (_distributedSettings.FileRisk.HasValue)
                {
                    pinConfiguration.FileRisk = _distributedSettings.FileRisk.Value;
                }
                if (_distributedSettings.MaxIOOperations.HasValue)
                {
                    pinConfiguration.MaxIOOperations = _distributedSettings.MaxIOOperations.Value;
                }
                pinConfiguration.UsePinCache = _distributedSettings.IsPinCachingEnabled;
                if (_distributedSettings.PinCacheReplicaCreditRetentionMinutes.HasValue)
                {
                    pinConfiguration.PinCacheReplicaCreditRetentionMinutes = _distributedSettings.PinCacheReplicaCreditRetentionMinutes.Value;
                }
                if (_distributedSettings.PinCacheReplicaCreditRetentionDecay.HasValue)
                {
                    pinConfiguration.PinCacheReplicaCreditRetentionDecay = _distributedSettings.PinCacheReplicaCreditRetentionDecay.Value;
                }
            }

            var lazyTouchContentHashBumpTime = _distributedSettings.IsTouchEnabled ? (TimeSpan?)contentHashBumpTime : null;

            if (redisContentLocationStoreConfiguration.ReadMode == ContentLocationMode.LocalLocationStore)
            {
                // LocalLocationStore has its own internal notion of lazy touch/registration. We disable the lazy touch in distributed content store
                // because it can conflict with behavior of the local location store.
                lazyTouchContentHashBumpTime = null;
            }

            var contentStoreSettings = FromDistributedSettings(_distributedSettings);

            ConfigurationModel configurationModel = null;

            if (_arguments.Configuration.LocalCasSettings.CacheSettingsByCacheName.TryGetValue(_arguments.Configuration.LocalCasSettings.CasClientSettings.DefaultCacheName, out var namedCacheSettings))
            {
                configurationModel = new ConfigurationModel(new ContentStoreConfiguration(new MaxSizeQuota(namedCacheSettings.CacheSizeQuotaString)));
            }

            _logger.Debug("Creating a distributed content store for Autopilot");
            var contentStore =
                new DistributedContentStore <AbsolutePath>(
                    localMachineLocation,
                    (announcer, evictionSettings, checkLocal, trimBulk) =>
                    ContentStoreFactory.CreateContentStore(_fileSystem, localCacheRoot, announcer, distributedEvictionSettings: evictionSettings,
                                                           contentStoreSettings: contentStoreSettings, trimBulkAsync: trimBulk, configurationModel: configurationModel),
                    redisContentLocationStoreFactory,
                    _arguments.Copier,
                    _arguments.Copier,
                    _arguments.PathTransformer,
                    contentAvailabilityGuarantee,
                    localCacheRoot,
                    _fileSystem,
                    _distributedSettings.RedisBatchPageSize,
                    new DistributedContentStoreSettings()
            {
                UseTrustedHash                  = _distributedSettings.UseTrustedHash,
                CleanRandomFilesAtRoot          = _distributedSettings.CleanRandomFilesAtRoot,
                TrustedHashFileSizeBoundary     = _distributedSettings.TrustedHashFileSizeBoundary,
                ParallelHashingFileSizeBoundary = _distributedSettings.ParallelHashingFileSizeBoundary,
                MaxConcurrentCopyOperations     = _distributedSettings.MaxConcurrentCopyOperations,
                PinConfiguration                = pinConfiguration,
                EmptyFileHashShortcutEnabled    = _distributedSettings.EmptyFileHashShortcutEnabled,
                RetryIntervalForCopies          = _distributedSettings.RetryIntervalForCopies,
            },
                    replicaCreditInMinutes: _distributedSettings.IsDistributedEvictionEnabled?_distributedSettings.ReplicaCreditInMinutes: null,
                    enableRepairHandling: _distributedSettings.IsRepairHandlingEnabled,
                    contentHashBumpTime: lazyTouchContentHashBumpTime,
                    contentStoreSettings: contentStoreSettings);

            _logger.Debug("Created Distributed content store.");
            return(contentStore);
        }