Exemplo n.º 1
0
        public virtual TValue Next <TValue>([NotNull] Func <long> getNewLowValue)
        {
            Check.NotNull(getNewLowValue, nameof(getNewLowValue));

            var poolIndexToUse = _poolIndex;

            _poolIndex = (_poolIndex + 1) % _pool.Length;

            var newValue = GetNextValue(poolIndexToUse);

            // If the chosen value is outside of the current block then we need a new block.
            // It is possible that other threads will use all of the new block before this thread
            // gets a chance to use the new new value, so use a while here to do it all again.
            while (newValue.Low >= newValue.High)
            {
                lock (_locks[_poolIndex])
                {
                    // Once inside the lock check to see if another thread already got a new block, in which
                    // case just get a value out of the new block instead of requesting one.
                    if (newValue.High == _pool[poolIndexToUse].High)
                    {
                        var newCurrent = getNewLowValue();
                        newValue = new HiLoValue(newCurrent, newCurrent + _blockSize);
                        _pool[poolIndexToUse] = newValue;
                    }
                    else
                    {
                        newValue = GetNextValue(poolIndexToUse);
                    }
                }
            }

            return((TValue)Convert.ChangeType(newValue.Low, typeof(TValue)));
        }
        /// <summary>
        ///     Gets a value to be assigned to a property.
        /// </summary>
        /// <typeparam name="TValue"> The type of values being generated. </typeparam>
        /// <param name="getNewLowValue">
        ///     A function to get the next low value if needed.
        /// </param>
        /// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
        /// <returns> The value to be assigned to a property. </returns>
        public virtual async Task <TValue> NextAsync <TValue>(
            [NotNull] Func <CancellationToken, Task <long> > getNewLowValue,
            CancellationToken cancellationToken = default)
        {
            Check.NotNull(getNewLowValue, nameof(getNewLowValue));

            var newValue = GetNextValue();

            // If the chosen value is outside of the current block then we need a new block.
            // It is possible that other threads will use all of the new block before this thread
            // gets a chance to use the new new value, so use a while here to do it all again.
            while (newValue.Low >= newValue.High)
            {
                using (await _asyncLock.LockAsync())
                {
                    // Once inside the lock check to see if another thread already got a new block, in which
                    // case just get a value out of the new block instead of requesting one.
                    if (newValue.High == _currentValue.High)
                    {
                        var newCurrent = await getNewLowValue(cancellationToken);

                        newValue      = new HiLoValue(newCurrent, newCurrent + _blockSize);
                        _currentValue = newValue;
                    }
                    else
                    {
                        newValue = GetNextValue();
                    }
                }
            }

            return(ConvertResult <TValue>(newValue));
        }
        /// <summary>
        ///     Gets a value to be assigned to a property.
        /// </summary>
        /// <typeparam name="TValue"> The type of values being generated. </typeparam>
        /// <param name="getNewLowValue">
        ///     A function to get the next low value if needed.
        /// </param>
        /// <returns> The value to be assigned to a property. </returns>
        public virtual TValue Next <TValue>([NotNull] Func <long> getNewLowValue)
        {
            Check.NotNull(getNewLowValue, nameof(getNewLowValue));

            var newValue = GetNextValue();

            // If the chosen value is outside of the current block then we need a new block.
            // It is possible that other threads will use all of the new block before this thread
            // gets a chance to use the new value, so use a while here to do it all again.
            while (newValue.Low >= newValue.High)
            {
                _semaphoreSlim.Wait();
                try
                {
                    // Once inside the lock check to see if another thread already got a new block, in which
                    // case just get a value out of the new block instead of requesting one.
                    if (newValue.High == _currentValue.High)
                    {
                        var newCurrent = getNewLowValue();
                        newValue      = new HiLoValue(newCurrent, newCurrent + _blockSize);
                        _currentValue = newValue;
                    }
                    else
                    {
                        newValue = GetNextValue();
                    }
                }
                finally
                {
                    _semaphoreSlim.Release();
                }
            }

            return(ConvertResult <TValue>(newValue));
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="HiLoValueGeneratorState" /> class.
        /// </summary>
        /// <param name="blockSize">
        ///     The number of sequential values that can be used, starting from the low value, before
        ///     a new low value must be fetched from the database.
        /// </param>
        public HiLoValueGeneratorState(int blockSize)
        {
            if (blockSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(blockSize), CoreStrings.HiLoBadBlockSize);
            }

            _blockSize    = blockSize;
            _currentValue = new HiLoValue(-1, 0);
        }
Exemplo n.º 5
0
        public HiLoValueGeneratorState(int blockSize, int poolSize)
        {
            _blockSize = blockSize;

            _pool  = new HiLoValue[poolSize];
            _locks = new object[poolSize];
            for (var i = 0; i < poolSize; i++)
            {
                _pool[i]  = new HiLoValue(-1, 0);
                _locks[i] = new object();
            }
        }
        public HiLoValueGeneratorState(int blockSize, int poolSize)
        {
            if (blockSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(blockSize), Strings.HiLoBadBlockSize);
            }

            if (poolSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(poolSize), Strings.HiLoBadPoolSize);
            }

            _blockSize = blockSize;

            _pool  = new HiLoValue[poolSize];
            _locks = new object[poolSize];
            for (var i = 0; i < poolSize; i++)
            {
                _pool[i]  = new HiLoValue(-1, 0);
                _locks[i] = new object();
            }
        }
 private static TValue ConvertResult <TValue>(HiLoValue newValue)
 => (TValue)Convert.ChangeType(newValue.Low, typeof(TValue), CultureInfo.InvariantCulture);