public void PinAddReferenceReleaseTest() { var array = new byte[1024]; OwnedBuffer <byte> owned = array; var memory = owned.Buffer; Assert.False(owned.HasOutstandingReferences); var h = memory.Pin(); Assert.True(owned.HasOutstandingReferences); h.Free(); Assert.False(owned.HasOutstandingReferences); }
public void PinAddReferenceReleaseTest() { var array = new byte[1024]; OwnedBuffer <byte> owned = array; var memory = owned.Buffer; Assert.False(owned.IsRetained); var h = memory.Pin(); Assert.True(owned.IsRetained); h.Dispose(); Assert.False(owned.IsRetained); }
public void TestThrowOnAccessAfterDipose() { var array = new byte[1024]; OwnedBuffer <byte> owned = array; var span = owned.Span; Assert.Equal(array.Length, span.Length); owned.Dispose(); Assert.Throws <ObjectDisposedException>(() => { var spanDisposed = owned.Span; }); }
public void DangerousTryGetArray() { var array = new byte[] { 1, 2, 3, 4, 5 }; OwnedBuffer <byte> owned = array; ReadOnlyBuffer <byte> buffer = owned.ReadOnlyBuffer; Assert.True(buffer.DangerousTryGetArray(out var dangerousArray)); Assert.Equal(array.Length, dangerousArray.Count); for (int i = dangerousArray.Offset; i < dangerousArray.Count + dangerousArray.Offset; i++) { Assert.Equal(array[i], dangerousArray.Array[i]); } }
public void RacyAccess() { for (int k = 0; k < 1000; k++) { var owners = new OwnedBuffer <byte> [128]; var memories = new Buffer <byte> [owners.Length]; var reserves = new DisposableReservation <byte> [owners.Length]; var disposeSuccesses = new bool[owners.Length]; var reserveSuccesses = new bool[owners.Length]; for (int i = 0; i < owners.Length; i++) { var array = new byte[1024]; owners[i] = array; memories[i] = owners[i].Buffer; } var dispose_task = Task.Run(() => { for (int i = 0; i < owners.Length; i++) { try { owners[i].Dispose(); disposeSuccesses[i] = true; } catch (InvalidOperationException) { disposeSuccesses[i] = false; } } }); var reserve_task = Task.Run(() => { for (int i = owners.Length - 1; i >= 0; i--) { try { reserves[i] = memories[i].Reserve(); reserveSuccesses[i] = true; } catch (ObjectDisposedException) { reserveSuccesses[i] = false; } } }); Task.WaitAll(reserve_task, dispose_task); for (int i = 0; i < owners.Length; i++) { Assert.False(disposeSuccesses[i] && reserveSuccesses[i]); } } }
static void Pin(OwnedBuffer <byte> buffer) { var memory = buffer.Buffer; Assert.False(buffer.IsRetained); var handle = memory.Pin(); unsafe { Assert.NotEqual(0L, new IntPtr(handle.PinnedPointer).ToInt64()); } Assert.True(buffer.IsRetained); handle.Dispose(); Assert.False(buffer.IsRetained); }
static void MemoryHandleDoubleFree(OwnedBuffer <byte> buffer) { var memory = buffer.Buffer; var handle = memory.Pin(); Assert.True(buffer.IsRetained); buffer.Retain(); Assert.True(buffer.IsRetained); handle.Dispose(); Assert.True(buffer.IsRetained); handle.Dispose(); Assert.True(buffer.IsRetained); buffer.Release(); Assert.False(buffer.IsRetained); }
public void ReservationPerformance(int number, int size, int threads, ReferenceCountingMethod m) { var iterations = 1000000; var o = ReferenceCountingSettings.OwnedMemory; ReferenceCountingSettings.OwnedMemory = m; Benchmark.Iterate(() => { var owners = new OwnedBuffer <byte> [number]; var memories = new Buffer <byte> [owners.Length]; for (int i = 0; i < owners.Length; i++) { owners[i] = new AutoPooledMemory(size); memories[i] = owners[i].Buffer; } var tasks = new List <Task>(threads); for (int t = 0; t < threads; t++) { tasks.Add(Task.Run(() => { for (int k = 0; k < iterations / owners.Length; k++) { for (int i = 0; i < owners.Length; i++) { using (var reserve = memories[i].Reserve()) { var s = reserve.Span; for (int j = 0; j < owners.Length; j++) { s[j] = (byte)1; } } } } })); } Task.WaitAll(tasks.ToArray()); for (int i = 0; i < owners.Length; i++) { owners[i].Release(); } }); ReferenceCountingSettings.OwnedMemory = o; }
public Buffer(T[] array) { if (array == null) { BufferPrimitivesThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } if (default(T) == null && array.GetType() != typeof(T[])) { BufferPrimitivesThrowHelper.ThrowArrayTypeMismatchException(typeof(T)); } _array = array; _owner = null; _index = 0; _length = array.Length; }
public ReadOnlyBuffer(T[] array, int start, int length) { if (array == null) { BufferPrimitivesThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) { BufferPrimitivesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); } _array = array; _owner = null; _index = start; _length = length; }
public void MemoryHandleDoubleFree() { var array = new byte[1024]; OwnedBuffer <byte> owned = array; var memory = owned.Buffer; var h = memory.Pin(); Assert.True(owned.HasOutstandingReferences); owned.AddReference(); Assert.True(owned.HasOutstandingReferences); h.Free(); Assert.True(owned.HasOutstandingReferences); h.Free(); Assert.True(owned.HasOutstandingReferences); owned.Release(); Assert.False(owned.HasOutstandingReferences); }
private void ResizeDb() { var oldData = _scratchMemory.Span; var newScratch = _pool.Rent(_scratchMemory.Length * 2); int dbLength = newScratch.Length / 2; var newDb = newScratch.Buffer.Slice(0, dbLength); _db.Slice(0, _valuesIndex).Span.CopyTo(newDb.Span); _db = newDb; var newStackMemory = newScratch.Buffer.Slice(dbLength); _stack.Resize(newStackMemory); _scratchManager.Dispose(); _scratchManager = newScratch; }
public void MemoryHandleDoubleFree() { var array = new byte[1024]; OwnedBuffer <byte> owned = array; var memory = owned.Buffer; var h = memory.Pin(); Assert.True(owned.IsRetained); owned.Retain(); Assert.True(owned.IsRetained); h.Dispose(); Assert.True(owned.IsRetained); h.Dispose(); Assert.True(owned.IsRetained); owned.Release(); Assert.False(owned.IsRetained); }
// tests that OwnedBuffer.Buffer and OwnedBuffer.ReadOnlyBuffer point to the same memory static void Buffer(OwnedBuffer <byte> buffer) { var rwBuffer = buffer.Buffer; var rwSpan = rwBuffer.Span; var roBuffer = buffer.ReadOnlyBuffer; var roSpan = roBuffer.Span; Assert.Equal(roSpan.Length, rwSpan.Length); for (int i = 0; i < roSpan.Length; i++) { var value = roSpan[i]; byte newValue = (byte)(value + 1); rwSpan[i] = newValue; Assert.Equal(newValue, roSpan[i]); } }
public void ReleasedBlockWorks() { var pool = new MemoryPool(); var block = pool.Rent(1); block.Dispose(); OwnedBuffer <byte> block2 = null; // Lease-return until we get same block do { block2?.Dispose(); block2 = pool.Rent(1); } while (block != block2); Assert.True(block2.Span.Length > 0); }
public static ReadableBuffer CreateBuffer(params byte[][] inputs) { if (inputs == null || inputs.Length == 0) { throw new InvalidOperationException(); } var i = 0; BufferSegment last = null; BufferSegment first = null; do { var s = inputs[i]; var length = s.Length; var memoryOffset = length; var dataOffset = length * 2; var chars = new byte[length * 8]; for (int j = 0; j < length; j++) { chars[dataOffset + j] = s[j]; } // Create a segment that has offset relative to the OwnedBuffer and OwnedBuffer itself has offset relative to array var ownedBuffer = OwnedBuffer <byte> .Create(new ArraySegment <byte>(chars, memoryOffset, length * 3)); var current = new BufferSegment(ownedBuffer, length, length * 2); if (first == null) { first = current; last = current; } else { last.Next = current; last = current; } i++; } while (i < inputs.Length); return(new ReadableBuffer(new ReadCursor(first, first.Start), new ReadCursor(last, last.Start + last.ReadableBytes))); }
public void SimpleTestS() { { var array = new byte[1024]; OwnedBuffer <byte> owned = array; var span = owned.Span; span[10] = 10; Assert.Equal(10, array[10]); var memory = owned.Buffer; var toArrayResult = memory.ToArray(); Assert.Equal(owned.Length, array.Length); Assert.Equal(10, toArrayResult[10]); Span <byte> copy = new byte[20]; memory.Slice(10, 20).CopyTo(copy); Assert.Equal(10, copy[0]); } }
public BufferSegment(OwnedBuffer <byte> buffer, int start, int end) { _owned = buffer; Start = start; End = end; ReadOnly = true; // For unowned buffers, we need to make a copy here so that the caller can // give up the give this buffer back to the caller var unowned = buffer as UnownedBuffer; if (unowned != null) { _owned = unowned.MakeCopy(start, end - start, out Start, out End); } _owned.AddReference(); _buffer = _owned.Buffer; }
/// <summary> /// Create a <see cref="ReadableBuffer"/> over an OwnedBuffer. /// </summary> public static ReadableBuffer Create(OwnedBuffer <byte> data, int offset, int length) { if (data == null) { PipelinesThrowHelper.ThrowArgumentNullException(ExceptionArgument.data); } if (offset < 0) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offset); } if (length < 0 || length > data.Length - offset) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } return(CreateInternal(data, offset, length)); }
public Buffer(T[] array, int start, int length) { if (array == null) { BufferPrimitivesThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } if (default(T) == null && array.GetType() != typeof(T[])) { BufferPrimitivesThrowHelper.ThrowArrayTypeMismatchException(typeof(T)); } if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) { BufferPrimitivesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); } _array = array; _owner = null; _index = start; _length = length; }
public PreservedBuffer <T> PreserveBuffer(int length) { if (length <= _smallTreshhold) { if (_sharedBuffer == null) { _sharedBuffer = BufferPool <T> .RentOwnedBuffer(this._sharedBufferSize, false); // NB we must create a reference or the first PreservedBuffer could // dispose _sharedBuffer on PreservedBuffer disposal. _sharedBuffer.AddReference(); _sharedBufferOffset = 0; } var bufferSize = _sharedBuffer.Length; var newOffset = _sharedBufferOffset + length; if (newOffset > bufferSize) { // replace shared buffer, the old one will be disposed // when all ReservedMemory views on it are disposed var previous = _sharedBuffer; _sharedBuffer = BufferPool <T> .RentOwnedBuffer(_sharedBufferSize, false); _sharedBuffer.AddReference(); previous.Release(); _sharedBufferOffset = 0; newOffset = length; } var buffer = _sharedBuffer.Buffer.Slice(_sharedBufferOffset, length); _sharedBufferOffset = newOffset; return(new PreservedBuffer <T>(buffer)); } // NB here we exclusively own the buffer and disposal of PreservedBuffer will cause // disposal and returning to pool of the ownedBuffer instance, unless references were added via // PreservedBuffer.Close() or PreservedBuffer.Buffer.Reserve()/Pin() methods var ownedBuffer = BufferPool <T> .RentOwnedBuffer(length, false); var buffer2 = ownedBuffer.Buffer.Slice(0, length); return(new PreservedBuffer <T>(buffer2)); }
public void ReleasedBlockWorks() { using (var pool = new MemoryPool()) { var block1 = pool.Rent(1); block1.Retain(); block1.Release(); OwnedBuffer <byte> block2 = null; // Lease-return until we get same block while (block1 != block2) { block2 = pool.Rent(1); block2.Retain(); block2.Release(); } Assert.True(block2.AsSpan().Length > 0); } }
public void CanUseOwnedBufferBasedReadableBuffers() { var data = Encoding.ASCII.GetBytes("***abc|def|ghijk****"); // note sthe padding here - verifying that it is omitted correctly OwnedBuffer <byte> owned = data; var buffer = ReadableBuffer.Create(owned, 3, data.Length - 7); Assert.Equal(13, buffer.Length); var split = buffer.Split((byte)'|'); Assert.Equal(3, split.Count()); using (var iter = split.GetEnumerator()) { Assert.True(iter.MoveNext()); var current = iter.Current; Assert.Equal("abc", current.GetAsciiString()); using (var preserved = iter.Current.Preserve()) { Assert.Equal("abc", preserved.Buffer.GetAsciiString()); } Assert.True(iter.MoveNext()); current = iter.Current; Assert.Equal("def", current.GetAsciiString()); using (var preserved = iter.Current.Preserve()) { Assert.Equal("def", preserved.Buffer.GetAsciiString()); } Assert.True(iter.MoveNext()); current = iter.Current; Assert.Equal("ghijk", current.GetAsciiString()); using (var preserved = iter.Current.Preserve()) { Assert.Equal("ghijk", preserved.Buffer.GetAsciiString()); } Assert.False(iter.MoveNext()); } }
static void MemoryAccessBasics(OwnedBuffer <byte> buffer) { var span = buffer.AsSpan(); span[10] = 10; Assert.Equal(buffer.Length, span.Length); Assert.Equal(10, span[10]); var memory = buffer.Buffer; Assert.Equal(buffer.Length, memory.Length); Assert.Equal(10, memory.Span[10]); var array = memory.ToArray(); Assert.Equal(buffer.Length, array.Length); Assert.Equal(10, array[10]); Span <byte> copy = new byte[20]; memory.Slice(10, 20).CopyTo(copy); Assert.Equal(10, copy[0]); }
internal ReadOnlyBuffer(OwnedBuffer <T> owner, int index, int length) { _arrayOrOwnedBuffer = owner; _index = index | (1 << 31); // Before using _index, check if _index < 0, then 'and' it with bitMask _length = length; }
/// <summary> /// Writes a new buffer into the pipeline. The task returned by this operation only completes when the next /// Read has been queued, or the Reader has completed, since the buffer provided here needs to be kept alive /// until the matching Read finishes (because we don't have ownership tracking when working with unowned buffers) /// </summary> /// <param name="buffer"></param> /// <param name="cancellationToken"></param> /// <returns></returns> // Called by the WRITER public async Task WriteAsync(OwnedBuffer <byte> buffer, CancellationToken cancellationToken) { // If Writing has stopped, why is the caller writing?? if (Writing.Status != TaskStatus.WaitingForActivation) { throw new OperationCanceledException("Writing has ceased on this pipeline"); } // If Reading has stopped, we cancel. We don't write unless there's a reader ready in this pipeline. if (Reading.Status != TaskStatus.WaitingForActivation) { throw new OperationCanceledException("Reading has ceased on this pipeline"); } // Register for cancellation on this token for the duration of the write using (cancellationToken.Register(state => ((UnownedBufferReader)state).CancelWriter(), this)) { // Wait for reading to start await ReadingStarted; // Cancel this task if this write is cancelled cancellationToken.ThrowIfCancellationRequested(); // Allocate a new segment to hold the buffer being written. using (var segment = new BufferSegment(buffer)) { segment.End = buffer.Buffer.Length; if (_head == null || _head.ReadableBytes == 0) { // Update the head to point to the head of the buffer. _head = segment; } else if (_tail != null) { // Add this segment to the end of the chain _tail.SetNext(segment); } // Always update tail to the buffer's tail _tail = segment; // Trigger the continuation Complete(); // Wait for another read to come (or for the end of Reading, which will also trigger this gate to open) in before returning await _readWaiting; if (_head.ReadableBytes > 0) { // We need to preserve any buffers that haven't been consumed _head = BufferSegment.Clone(new ReadCursor(_head), new ReadCursor(_tail, _tail?.End ?? 0), out _tail); } else { // Drop segement references before Dispose gets called on the segment _head = _tail = null; } } // Cancel this task if this write is cancelled cancellationToken.ThrowIfCancellationRequested(); } }
/// <summary> /// Wraps a rented buffer and returns it to the shared pool on Dispose /// </summary> /// <param name="rentedBuffer">A buffer that was previously rented from the shared BufferPool</param> /// <param name="offset"></param> /// <param name="count"></param> public RentedBufferStream(OwnedBuffer <byte> rentedBuffer, int count) : base(GetSegment(rentedBuffer).Array, 0, count) { _rentedBuffer = rentedBuffer; }
public JsonObject Parse(ReadOnlySpan <byte> utf8Json, BufferPool pool = null) { _pool = pool; if (_pool == null) { _pool = BufferPool.Default; } _scratchManager = _pool.Rent(utf8Json.Length * 4); _scratchMemory = _scratchManager.Buffer; int dbLength = _scratchMemory.Length / 2; _db = _scratchMemory.Slice(0, dbLength); _stack = new TwoStacks(_scratchMemory.Slice(dbLength)); _values = utf8Json; _insideObject = 0; _insideArray = 0; _tokenType = 0; _valuesIndex = 0; _dbIndex = 0; _jsonStartIsObject = false; SkipWhitespace(); _jsonStartIsObject = _values[_valuesIndex] == '{'; int arrayItemsCount = 0; int numberOfRowsForMembers = 0; while (Read()) { var tokenType = _tokenType; switch (tokenType) { case JsonTokenType.ObjectStart: AppendDbRow(JsonObject.JsonValueType.Object, _valuesIndex); while (!_stack.TryPushObject(numberOfRowsForMembers)) { ResizeDb(); } numberOfRowsForMembers = 0; break; case JsonTokenType.ObjectEnd: _db.Span.Slice(FindLocation(_stack.ObjectStackCount - 1, true)).Write <int>(numberOfRowsForMembers); numberOfRowsForMembers += _stack.PopObject(); break; case JsonTokenType.ArrayStart: AppendDbRow(JsonObject.JsonValueType.Array, _valuesIndex); while (!_stack.TryPushArray(arrayItemsCount)) { ResizeDb(); } arrayItemsCount = 0; break; case JsonTokenType.ArrayEnd: _db.Span.Slice(FindLocation(_stack.ArrayStackCount - 1, false)).Write <int>(arrayItemsCount); arrayItemsCount = _stack.PopArray(); break; case JsonTokenType.Property: ParsePropertyName(); ParseValue(); numberOfRowsForMembers++; numberOfRowsForMembers++; break; case JsonTokenType.Value: ParseValue(); arrayItemsCount++; numberOfRowsForMembers++; break; default: throw new ArgumentOutOfRangeException(); } } var result = new JsonObject(_values, _db.Slice(0, _dbIndex).Span, _pool, _scratchManager); _scratchManager = null; return(result); }
internal JsonObject(ReadOnlySpan <byte> values, ReadOnlySpan <byte> db, BufferPool pool = null, OwnedBuffer <byte> dbMemory = null) { _db = db; _values = values; _pool = pool; _dbMemory = dbMemory; }