Exemplo n.º 1
0
        private uint TakeBlocks(int blocksNeeded)
        {
            lock (_sync)
            {
                bool rescan       = false;
                bool resized      = false;
                int  startingFrom = _prevFreeBlock;
                int  endingBefore = int.MaxValue;
                while (true)
                {
                    int found = 0;
                    int last  = int.MinValue;
                    int first = int.MaxValue;
                    foreach (int free in _freeBlocks.EnumerateRange(startingFrom, endingBefore))
                    {
                        if (_reservedBlocks.Contains(free))
                        {
                            continue;
                        }

                        if (found == 0)
                        {
                            _prevFreeBlock = free;
                            if (!resized && rescan)
                            {
                                _firstFreeBlock = free;
                            }
                        }

                        first = Math.Min(first, free);
                        found = (last + 1 != free) ? 1 : found + 1;
                        last  = free;
                        if (found == blocksNeeded)
                        {
                            int start = free - (blocksNeeded - 1);
                            for (int i = start; i <= free; i++)
                            {
                                _freeBlocks.Remove(i);
                            }

                            uint blockId = (uint)start;
                            blockId |= ((uint)Math.Min(16, blocksNeeded) - 1 << 28) & 0xF0000000u;
                            return(blockId);
                        }
                    }
                    if (resized)
                    {
                        throw new ArgumentOutOfRangeException("length");
                    }

                    if (!rescan && _firstFreeBlock < startingFrom)
                    {
                        rescan       = true;
                        endingBefore = startingFrom + blocksNeeded - 1;
                        startingFrom = _firstFreeBlock;
                    }
                    else
                    {
                        resized      = true;
                        startingFrom = AddSection();
                        endingBefore = int.MaxValue;
                    }
                }
            }
        }