public void two() { var l = new AppendList <int>(); l.Append(10); l.Append(42); Assert.Equal(2, l.Count); Assert.Equal(10, l[0]); Assert.Equal(42, l[1]); }
public async Task smoke_test() { // Append and read repeatedly, trying to cause an // access violation. for (var c = 0; c < 1000; ++c) { var l = new AppendList <int>(); var t1 = Task.Run(() => { for (var i = 0; i < 100000; ++i) { l.Append(i * 3); } }); var t2 = Task.Run(() => { for (var i = 0; i < 100000; ++i) { while (i >= l.Count) { Thread.Yield(); } Assert.Equal(i * 3, l[i]); } }); await t1; await t2; } }
/// <summary> Construct from a read-only file. </summary> /// <remarks> /// Used when recovering files written by a previous program /// instance from their locations. /// </remarks> public BlockFile(IFileMemory file, uint fileId) { _pinner = new Pinner(); _file = file ?? throw new ArgumentNullException(nameof(file)); FileId = fileId; _flags = new AppendList <ReadFlag>(); var offset = 0L; while (offset < _file.Length) { var block = AtOffset(offset); ref var header = ref block.Header; if (header.Rank != _flags.Count || header.ContentLength < 0 || header.ContentLength + BlockHeader.Size > _file.Length) { // The header of the block appears broken. Do not include // it in the list, and stop scanning (since we don't know // how far to jump ahead). break; } var thisOffset = offset; _flags.Append(ReadFlag.Triggered(() => VerifyAtOffset(thisOffset))); offset += block.RelativeOffsetToNextBlock; }
/// <summary> /// Attempts to schedule a write of the specified length into the file. /// </summary> /// <returns> /// A valid block address representing the location where the written /// block will be found, or a 'None' address if the file does not /// currently have enough room for this. /// </returns> /// <remarks> /// The provided writer will be invoked at some point in the future. /// /// Thread-safe. /// </remarks> public BlockAddress TryScheduleWrite( uint realm, Hash hash, int length, WithSpan.ReadWrite writer) { if (length < 0) { throw new ArgumentException($"Negative length: {length}", nameof(length)); } int rank; long offset; lock (_syncRoot) { offset = _offset; _offset = BlockAddress.Ceiling(offset + BlockHeader.Size + length); if (_offset > _file.Length) { // Since this file is about to be flushed and closed, // because it's "full enough", we prevent additional writes. _offset = _file.Length; return(BlockAddress.None); } rank = _flags.Count; _flags.Append(ReadFlag.Triggered(() => PerformWrite(offset, writer))); } // We touched '_offset' and '_flags' in the critical section, the remaining // work on the actual byte span can be done without mutex. var span = _file.AsMemory(offset, BlockHeader.Size).Span; ref var header = ref MemoryMarshal.Cast <byte, BlockHeader>(span)[0];
public void one() { var l = new AppendList <int>(); l.Append(10); Assert.Equal(1, l.Count); Assert.Equal(10, l[0]); }