Пример #1
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="ContentStoreConfiguration"/> class.
        /// </summary>
        public ContentStoreConfiguration
        (
            MaxSizeQuota maxSizeQuota = null,
            DiskFreePercentQuota diskFreePercentQuota = null,
            DenyWriteAttributesOnContentSetting denyWriteAttributesOnContent = DenyWriteAttributesOnContentSetting.Disable,
            int singleInstanceTimeoutSeconds = DefaultSingleInstanceTimeoutSeconds,
            bool enableElasticity            = false,
            MaxSizeQuota initialElasticSize  = null,
            int?historyBufferSize            = default(int?),
            int?historyWindowSize            = default(int?)
        )
        {
            Contract.Requires(singleInstanceTimeoutSeconds > 0);

            MaxSizeQuota                 = maxSizeQuota;
            DiskFreePercentQuota         = diskFreePercentQuota;
            DenyWriteAttributesOnContent = denyWriteAttributesOnContent;
            SingleInstanceTimeoutSeconds = singleInstanceTimeoutSeconds;
            EnableElasticity             = enableElasticity;
            InitialElasticSize           = initialElasticSize;
            HistoryBufferSize            = historyBufferSize;
            HistoryWindowSize            = historyWindowSize;

            Initialize();
        }
Пример #2
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="ElasticSizeRule" /> class.
        /// </summary>
        public ElasticSizeRule(
            int?historyWindowSize,
            MaxSizeQuota?initialElasticSize,
            Func <long> getCurrentSizeFunc,
            Func <int, PinSizeHistory.ReadHistoryResult> getPinnedSizeHistoryFunc,
            IAbsFileSystem fileSystem,
            AbsolutePath rootPath,
            double?calibrationCoefficient = default(double?))
            : base(OnlyUnlinkedValue)
        {
            Contract.Requires(!historyWindowSize.HasValue || historyWindowSize.Value >= 0);
            Contract.Requires(getCurrentSizeFunc != null);
            Contract.Requires(getPinnedSizeHistoryFunc != null);
            Contract.Requires(fileSystem != null);
            Contract.Requires(rootPath != null);
            Contract.Requires(!calibrationCoefficient.HasValue || calibrationCoefficient.Value > 1.0);

            _historyWindowSize        = historyWindowSize ?? DefaultHistoryWindowSize;
            _calibrationCoefficient   = calibrationCoefficient ?? DefaultCalibrationCoefficient;
            _getPinnedSizeHistoryFunc = getPinnedSizeHistoryFunc;
            _getCurrentSizeFunc       = getCurrentSizeFunc;
            _fileSystem   = fileSystem;
            _rootPath     = rootPath;
            _initialQuota = initialElasticSize ?? SmallQuota;

            var loadQuotaResult = LoadOrCreateNew(_fileSystem, _initialQuota, _rootPath);

            _quota = loadQuotaResult.Quota;
            _historyTimestampInTick = loadQuotaResult.HistoryTimestampInTick;

            // TODO: CalibrateAsync method fails in tests all the time. Bug #1331905
            CalibrateAsync().GetAwaiter().GetResult().IgnoreFailure();
            Contract.Assert(IsInsideHardLimit(0, checkIfQuotaEnabled: false).Succeeded);
        }
Пример #3
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="MaxSizeRule"/> class.
        /// </summary>
        public MaxSizeRule(MaxSizeQuota quota, Func <long> getCurrentSizeFunc)
            : base(OnlyUnlinkedValue)
        {
            Contract.Requires(quota != null);
            Contract.Requires(getCurrentSizeFunc != null);

            _quota = quota;
            _getCurrentSizeFunc = getCurrentSizeFunc;
        }
Пример #4
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="MaxSizeRule"/> class.
        /// </summary>
        public MaxSizeRule(MaxSizeQuota quota, EvictAsync evictAsync, Func <long> getCurrentSizeFunc, DistributedEvictionSettings distributedEvictionSettings = null)
            : base(evictAsync, OnlyUnlinkedValue, distributedEvictionSettings)
        {
            Contract.Requires(quota != null);
            Contract.Requires(evictAsync != null);
            Contract.Requires(getCurrentSizeFunc != null);

            _quota = quota;
            _getCurrentSizeFunc = getCurrentSizeFunc;
        }
Пример #5
0
        private LoadQuotaResult CreateNew(IAbsFileSystem fileSystem, MaxSizeQuota initialElasticQuota, AbsolutePath rootPath)
        {
            var currentSize = _getCurrentSizeFunc();

            if (initialElasticQuota.Hard < currentSize)
            {
                // If current size is larger than the initial quota, then throw away initial quota, and use current size.
                // The quota is set by taking into account the current size and hard limit ratio used during shrinkage.
                // If the quota is set to the current size, then the very first reservation may potentially be blocking.
                initialElasticQuota = new MaxSizeQuota((long)(currentSize / CurrentSizeHardLimitRatio));
            }

            // Set the timestamp tick to -1 so that it can consume pre-existing history window upon calibration during construction.
            var loadQuotaResult = new LoadQuotaResult(initialElasticQuota, -1);

            SaveQuota(fileSystem, rootPath, loadQuotaResult.Quota, loadQuotaResult.HistoryTimestampInTick).ThrowIfFailure();

            return(loadQuotaResult);
        }
Пример #6
0
        private LoadQuotaResult LoadOrCreateNew(IAbsFileSystem fileSystem, MaxSizeQuota initialElasticQuota, AbsolutePath rootPath)
        {
            var filePath = rootPath / BinaryFileName;

            try
            {
                if (!fileSystem.FileExists(filePath))
                {
                    return(CreateNew(fileSystem, initialElasticQuota, rootPath));
                }

                using (var stream = fileSystem.OpenReadOnly(filePath, FileShare.Delete))
                {
                    using (var reader = new BinaryReader(stream))
                    {
                        return(new LoadQuotaResult(new MaxSizeQuota(reader.ReadInt64(), reader.ReadInt64()), reader.ReadInt64()));
                    }
                }
            }
            catch (IOException)
            {
                return(CreateNew(fileSystem, initialElasticQuota, rootPath));
            }
        }
Пример #7
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="LoadQuotaResult"/> class.
 /// </summary>
 public LoadQuotaResult(MaxSizeQuota quota, long historyTimestampInTick)
 {
     Quota = quota;
     HistoryTimestampInTick = historyTimestampInTick;
 }
Пример #8
0
        /// <inheritdoc />
        public override Task <CalibrateResult> CalibrateAsync()
        {
            // Calibration should be done in atomic way.
            return(Task.FromResult(
                       _locker.WithWriteLock(() =>
            {
                /*
                 *                o (Case A)
                 *
                 * ---------------------------------------------  Hard limit
                 *
                 *                o (Case B)
                 *
                 * ---------------------------------------------  Soft limit
                 *
                 *                o (Case C)
                 */

                bool isCalibrated = false;
                string reason = string.Empty;

                if (!IsInsideHardLimit(0, false).Succeeded)
                {
                    // Case A.
                    _quota = new MaxSizeQuota((long)(_getCurrentSizeFunc() * _calibrationCoefficient));
                    isCalibrated = true;
                }
                else
                {
                    // Case B & C.
                    // Try bring hard limit closer to the current size based on history of pinned sizes.

                    // Constraint 1: newHardLimit >= currentSize.
                    long newHardLimit = (long)(_getCurrentSizeFunc() / CurrentSizeHardLimitRatio);

                    if (newHardLimit < _initialQuota.Hard)
                    {
                        newHardLimit = _initialQuota.Hard;
                    }

                    // Constraint 2: window.Max * CalibrateUpCoefficient <= newHardLimit.
                    var history = _getPinnedSizeHistoryFunc(_historyWindowSize);

                    if (newHardLimit >= _quota.Hard)
                    {
                        // Candidate new hard limit is larger than or equal to the current hard limit.
                        reason = $"New hard limit, {newHardLimit}, is larger than or equal to the current hard limit, {_quota.Hard}";
                    }
                    else if (history.Window.Count <= 0)
                    {
                        // No entries in the history window.
                        // Note that we allow to consume history which is smaller than the specified history window size.
                        // This allows smaller history to cause calibration downward.
                        reason = "History window is empty";
                    }
                    else if (history.TimestampInTick <= _historyTimestampInTick)
                    {
                        // History timestamp is older than the current timestamp.
                        reason = $"History timestamp, {history.TimestampInTick}, is older than the current timestamp, {_historyTimestampInTick}";
                    }
                    else if (history.Window.Max() * _calibrationCoefficient >= newHardLimit)
                    {
                        // Max value in the calibration window, times the calibration coefficient, is larger than the new hard limit.
                        reason =
                            $"Max history window, {history.Window.Max()}, with calibration coefficient {_calibrationCoefficient}, exceeds candidate hard limit {newHardLimit}";
                    }
                    else
                    {
                        _quota = new MaxSizeQuota(newHardLimit);
                        _historyTimestampInTick = history.TimestampInTick;
                        isCalibrated = true;
                    }
                }

                _isQuotaEnabled = true;

                if (!isCalibrated)
                {
                    return new CalibrateResult(reason);
                }

                var saveResult = SaveQuota();

                return !saveResult.Succeeded ? new CalibrateResult(saveResult.ErrorMessage !) : new CalibrateResult(_quota.Hard);
            })));
        }
Пример #9
0
        private static BoolResult SaveQuota(IAbsFileSystem fileSystem, AbsolutePath rootPath, MaxSizeQuota quota, long historyTimestampInTick)
        {
            var filePath = rootPath / BinaryFileName;

            try
            {
                fileSystem.DeleteFile(filePath);

                using (var stream = fileSystem.Open(filePath, FileAccess.Write, FileMode.CreateNew, FileShare.Delete))
                {
                    using (var writer = new BinaryWriter(stream))
                    {
                        writer.Write(quota.Hard);
                        writer.Write(quota.Soft);
                        writer.Write(historyTimestampInTick);
                    }
                }

                return(BoolResult.Success);
            }
            catch (Exception e)
            {
                // When failed, clean up so that it is not used in the next load.
                fileSystem.DeleteFile(filePath);

                return(new BoolResult(e));
            }
        }