/// <summary> /// Adds blocks and all data. /// </summary> void AddBlock(object op, ulong address, List <ulong> freeBlocks, List <AllocationBlockInfo> blocksLocked, ref uint count) { // We could add any. AllocationBlockInfo info = ScanBlock(address); if ((info.LockingOperation != null && info.LockingOperation != op) || info.FreeBlocks.Count == 0) { return; } // We add all we can (max count), info.LockingOperation = op; blocksLocked.Add(info); // We remove those used. int c = info.FreeBlocks.Count > (int)count ? (int)count : info.FreeBlocks.Count; for (int i = 0; i < c; i++) { ulong addrToAdd = address + (ulong)info.FreeBlocks[i]; if (addrToAdd == 103) { addrToAdd = 103; } freeBlocks.Add(addrToAdd); } // Remove used indices. count -= (uint)c; info.FreeBlocks.RemoveRange(0, c); }
/// <summary> /// Scans one allocation block. /// </summary> /// <param name="address">The allocation block address.</param> /// <returns></returns> AllocationBlockInfo ScanBlock(ulong address) { AllocationBlockInfo value; if (inspectedFreeBlocks.TryGetValue(address, out value)) { return(value); } BoolArray array = new BoolArray(provider.Read(BlockType.AllocationBlock, address)); // We first check for all written (fast). if (array.IsAllTrue) { value = new AllocationBlockInfo(address, new List <uint>()); inspectedFreeBlocks.Add(address, value); return(value); } List <uint> freeBlocks = new List <uint>(); // We search through all (optimized search, may optimize even better in future. // If this will be a bottle neck, we can fix the array outside and than search // through it using ulong* pointer (no need to repeat this every time)). for (uint i = 0; i < provider.BlockSize / 8; i++) { // We chaeck 8-bytes at one for all full. if (array.IsULongFull(i)) { continue; } // For all free. if (array.IsULongFree(i)) { for (uint j = i * 64; j < (i + 1) * 64; j++) { freeBlocks.Add(j + 1); } continue; } // We now check by byte. for (uint j = i * 64; j < (i + 1) * 64; j++) { if (!array[j]) { freeBlocks.Add(j + 1); } } } value = new AllocationBlockInfo(address, freeBlocks); inspectedFreeBlocks.Add(address, value); return(value); }
/// <summary> /// Returns allocations (not commited). Must return even if there is nothing /// to return because operation is still blocking the allocation block. /// </summary> /// <param name="returned"></param> public void ReturnAllocations(object returning, List <ulong> returned) { lock (syncRoot) { Console.WriteLine("{0} operation returned {1} : {2} blocks returned.", returning, returned.Count, Common.ArrayToString <ulong>(returned)); Console.Out.Flush(); // We first return blocks. for (int i = 0; i < returned.Count;) { ulong block = returned[i]; // We find the block. uint offset; ulong allocBlock = BlockHelper.GetAllocationBlock(provider.BlockSize, block, out offset); AllocationBlockInfo blockInfo = inspectedFreeBlocks[allocBlock]; // We return the address. blockInfo.FreeBlocks.Add(offset); // We check all further (they are sorted so there is a big chance it is in the same block). i++; for (; i < returned.Count; i++) { block = returned[i]; // We exit if not in the same block. if (BlockHelper.GetAllocationBlock(provider.BlockSize, block, out offset) != allocBlock) { break; } blockInfo.FreeBlocks.Add(offset); } // Must be sorted. blockInfo.FreeBlocks.Sort(); } // We free all allocation blocks locks. List <AllocationBlockInfo> all = lockingList.Find( delegate(OperationLockData data2) { return(data2.Key == returning); }).Info; all.ForEach(delegate(AllocationBlockInfo info) { info.LockingOperation = null; }); // We remove the operation. lockingList.RemoveAll(delegate(OperationLockData data3) { return(data3.Key == returning); }); } }