/// <summary> /// Allocates a handle for data, you MUST call Write to commit the handle, otherwise the handle /// may be reallocated after closing and re-opening this file. If you do not intend to commit /// the handle by writing to it, you should still call Delete() so that it may be reused. /// </summary> public uint Create() { uint handle = 0; lock (_sync) { while (handle == 0) { foreach (int i in _freeHandles.EnumerateFrom(_prevFreeHandle)) { _freeHandles.Remove(i); _prevFreeHandle = i + 1; handle = (uint)i; break; } if (handle == 0) { AddSection(); } } } HandleRef href = new HandleRef(handle, BlockSize); uint blockId = _sections[href.Section][href.Offset]; if (blockId != 0) { throw new InvalidDataException(); } return(handle); }
private uint TakeBlocks(int blocksNeeded) { lock (_sync) { bool resized = false; while (true) { int found = 0; int last = int.MinValue; int first = int.MaxValue; foreach (int free in _freeBlocks.EnumerateFrom(_prevFreeBlock)) { if (_reservedBlocks.Contains(free)) { continue; } first = Math.Min(first, free); found = (last + 1 != free) ? 1 : found + 1; last = free; if (found == blocksNeeded) { _prevFreeBlock = first; 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"); } resized = true; AddSection(); } } }