From 3c40df452d135fdb0736c23793d64d2c012eac00 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 3 May 2019 10:43:45 -0700 Subject: [PATCH] Update MessagePack commit to be inline with upstream changes (#9753) * Update MessagePack commit to be inline with upstream changes --- THIRD-PARTY-NOTICES.txt | 69 +++ .../src/BlazorPack/NativeDateTimeFormatter.cs | 9 - .../Server/src/BlazorPack/Requires.cs | 35 ++ .../Server/src/BlazorPack/SequenceOfT.cs | 451 ++++++++++++++++++ ...rosoft.AspNetCore.Components.Server.csproj | 3 + .../Microsoft.AspNetCore.App.Runtime.csproj | 1 + src/submodules/MessagePack-CSharp | 2 +- 7 files changed, 560 insertions(+), 10 deletions(-) delete mode 100644 src/Components/Server/src/BlazorPack/NativeDateTimeFormatter.cs create mode 100644 src/Components/Server/src/BlazorPack/Requires.cs create mode 100644 src/Components/Server/src/BlazorPack/SequenceOfT.cs diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt index 5e6431e7c6..96dcfb8ae7 100644 --- a/THIRD-PARTY-NOTICES.txt +++ b/THIRD-PARTY-NOTICES.txt @@ -95,3 +95,72 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for MessagePack-CSharp +------------------------------------- + +MessagePack for C# + +MIT License + +Copyright (c) 2017 Yoshifumi Kawai + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +lz4net + +Copyright (c) 2013-2017, Milosz Krajewski + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +License notice for Nerdbank.Streams +----------------------------------- + +The MIT License (MIT) + +Copyright (c) Andrew Arnott + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/Components/Server/src/BlazorPack/NativeDateTimeFormatter.cs b/src/Components/Server/src/BlazorPack/NativeDateTimeFormatter.cs deleted file mode 100644 index f45c61926c..0000000000 --- a/src/Components/Server/src/BlazorPack/NativeDateTimeFormatter.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace MessagePack.Formatters -{ - internal class NativeDateTimeFormatter - { - } -} diff --git a/src/Components/Server/src/BlazorPack/Requires.cs b/src/Components/Server/src/BlazorPack/Requires.cs new file mode 100644 index 0000000000..4a7532d78f --- /dev/null +++ b/src/Components/Server/src/BlazorPack/Requires.cs @@ -0,0 +1,35 @@ +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + +using System; +using System.Buffers; + +namespace Nerdbank.Streams +{ + internal static class Requires + { + internal static void NotNull(object arg, string paramName) + { + if (arg == null) + { + throw new ArgumentNullException(nameof(paramName)); + } + } + + internal static void Argument(bool condition, string paramName, string message) + { + if (condition) + { + throw new ArgumentException(message, paramName); + } + } + + internal static void Range(bool condition, string paramName) + { + if (condition) + { + throw new ArgumentOutOfRangeException(paramName); + } + } + } +} diff --git a/src/Components/Server/src/BlazorPack/SequenceOfT.cs b/src/Components/Server/src/BlazorPack/SequenceOfT.cs new file mode 100644 index 0000000000..453d6b42e2 --- /dev/null +++ b/src/Components/Server/src/BlazorPack/SequenceOfT.cs @@ -0,0 +1,451 @@ +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + +namespace Nerdbank.Streams +{ + using System; + using System.Buffers; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics; + using System.Reflection; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using Microsoft; + + /// + /// Manages a sequence of elements, readily castable as a . + /// + /// The type of element stored by the sequence. + /// + /// Instance members are not thread-safe. + /// + [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] + internal class Sequence : IBufferWriter, IDisposable + { + private static readonly int DefaultLengthFromArrayPool = 1 + (4095 / Marshal.SizeOf()); + + private readonly Stack segmentPool = new Stack(); + + private readonly MemoryPool memoryPool; + + private readonly ArrayPool arrayPool; + + private SequenceSegment first; + + private SequenceSegment last; + + /// + /// Initializes a new instance of the class + /// that uses a private for recycling arrays. + /// + public Sequence() + : this(ArrayPool.Create()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The pool to use for recycling backing arrays. + public Sequence(MemoryPool memoryPool) + { + Requires.NotNull(memoryPool, nameof(memoryPool)); + this.memoryPool = memoryPool; + } + + /// + /// Initializes a new instance of the class. + /// + /// The pool to use for recycling backing arrays. + public Sequence(ArrayPool arrayPool) + { + Requires.NotNull(arrayPool, nameof(arrayPool)); + this.arrayPool = arrayPool; + } + + /// + /// Gets or sets the minimum length for any array allocated as a segment in the sequence. + /// Any non-positive value allows the pool to determine the length of the array. + /// + /// The default value is 0. + /// + /// + /// Each time or is called, + /// previously allocated memory is used if it is large enough to satisfy the length demand. + /// If new memory must be allocated, the argument to one of these methods typically dictate + /// the length of array to allocate. When the caller uses very small values (just enough for its immediate need) + /// but the high level scenario can predict that a large amount of memory will be ultimately required, + /// it can be advisable to set this property to a value such that just a few larger arrays are allocated + /// instead of many small ones. + /// + /// + /// The in use may itself have a minimum array length as well, + /// in which case the higher of the two minimums dictate the minimum array size that will be allocated. + /// + /// + public int MinimumSpanLength { get; set; } = 0; + + /// + /// Gets this sequence expressed as a . + /// + /// A read only sequence representing the data in this object. + public ReadOnlySequence AsReadOnlySequence => this; + + /// + /// Gets the length of the sequence. + /// + public long Length => this.AsReadOnlySequence.Length; + + /// + /// Gets the value to display in a debugger datatip. + /// + private string DebuggerDisplay => $"Length: {AsReadOnlySequence.Length}"; + + /// + /// Expresses this sequence as a . + /// + /// The sequence to convert. + public static implicit operator ReadOnlySequence(Sequence sequence) + { + return sequence.first != null + ? new ReadOnlySequence(sequence.first, sequence.first.Start, sequence.last, sequence.last.End) + : ReadOnlySequence.Empty; + } + + /// + /// Removes all elements from the sequence from its beginning to the specified position, + /// considering that data to have been fully processed. + /// + /// + /// The position of the first element that has not yet been processed. + /// This is typically after reading all elements from that instance. + /// + public void AdvanceTo(SequencePosition position) + { + var firstSegment = (SequenceSegment)position.GetObject(); + int firstIndex = position.GetInteger(); + + // Before making any mutations, confirm that the block specified belongs to this sequence. + var current = this.first; + while (current != firstSegment && current != null) + { + current = current.Next; + } + + Requires.Argument(current != null, nameof(position), "Position does not represent a valid position in this sequence."); + + // Also confirm that the position is not a prior position in the block. + Requires.Argument(firstIndex >= current.Start, nameof(position), "Position must not be earlier than current position."); + + // Now repeat the loop, performing the mutations. + current = this.first; + while (current != firstSegment) + { + current = this.RecycleAndGetNext(current); + } + + firstSegment.AdvanceTo(firstIndex); + + if (firstSegment.Length == 0) + { + firstSegment = this.RecycleAndGetNext(firstSegment); + } + + this.first = firstSegment; + + if (this.first == null) + { + this.last = null; + } + } + + /// + /// Advances the sequence to include the specified number of elements initialized into memory + /// returned by a prior call to . + /// + /// The number of elements written into memory. + public void Advance(int count) + { + SequenceSegment last = this.last; + Debug.Assert(last != null, "Cannot advance before acquiring memory."); + last.Advance(count); + } + + /// + /// Gets writable memory that can be initialized and added to the sequence via a subsequent call to . + /// + /// The size of the memory required, or 0 to just get a convenient (non-empty) buffer. + /// The requested memory. + public Memory GetMemory(int sizeHint) => this.GetSegment(sizeHint).RemainingMemory; + + /// + /// Gets writable memory that can be initialized and added to the sequence via a subsequent call to . + /// + /// The size of the memory required, or 0 to just get a convenient (non-empty) buffer. + /// The requested memory. + public Span GetSpan(int sizeHint) => this.GetSegment(sizeHint).RemainingSpan; + + /// + /// Clears the entire sequence, recycles associated memory into pools, + /// and resets this instance for reuse. + /// This invalidates any previously produced by this instance. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Dispose() => this.Reset(); + + /// + /// Clears the entire sequence and recycles associated memory into pools. + /// This invalidates any previously produced by this instance. + /// + public void Reset() + { + var current = this.first; + while (current != null) + { + current = this.RecycleAndGetNext(current); + } + + this.first = this.last = null; + } + + private SequenceSegment GetSegment(int sizeHint) + { + Requires.Range(sizeHint >= 0, nameof(sizeHint)); + int? minBufferSize = null; + if (sizeHint == 0) + { + if (this.last == null || this.last.WritableBytes == 0) + { + // We're going to need more memory. Take whatever size the pool wants to give us. + minBufferSize = -1; + } + } + else + { + sizeHint = Math.Max(this.MinimumSpanLength, sizeHint); + if (this.last == null || this.last.WritableBytes < sizeHint) + { + minBufferSize = sizeHint; + } + } + + if (minBufferSize.HasValue) + { + var segment = this.segmentPool.Count > 0 ? this.segmentPool.Pop() : new SequenceSegment(); + if (this.arrayPool != null) + { + segment.Assign(this.arrayPool.Rent(minBufferSize.Value == -1 ? DefaultLengthFromArrayPool : minBufferSize.Value)); + } + else + { + segment.Assign(this.memoryPool.Rent(minBufferSize.Value)); + } + + this.Append(segment); + } + + return this.last; + } + + private void Append(SequenceSegment segment) + { + if (this.last == null) + { + this.first = this.last = segment; + } + else + { + if (this.last.Length > 0) + { + // Add a new block. + this.last.SetNext(segment); + } + else + { + // The last block is completely unused. Replace it instead of appending to it. + var current = this.first; + if (this.first != this.last) + { + while (current.Next != this.last) + { + current = current.Next; + } + } + else + { + this.first = segment; + } + + current.SetNext(segment); + this.RecycleAndGetNext(this.last); + } + + this.last = segment; + } + } + + private SequenceSegment RecycleAndGetNext(SequenceSegment segment) + { + var recycledSegment = segment; + segment = segment.Next; + recycledSegment.ResetMemory(this.arrayPool); + this.segmentPool.Push(recycledSegment); + return segment; + } + + private class SequenceSegment : ReadOnlySequenceSegment + { + /// + /// A value indicating whether the element is a value type. + /// + private static readonly bool IsValueTypeElement = typeof(T).GetTypeInfo().IsValueType; + + /// + /// Gets the backing array, when using an instead of a . + /// + private T[] array; + + /// + /// Gets the position within where the data starts. + /// + /// This may be nonzero as a result of calling . + internal int Start { get; private set; } + + /// + /// Gets the position within where the data ends. + /// + internal int End { get; private set; } + + /// + /// Gets the tail of memory that has not yet been committed. + /// + internal Memory RemainingMemory => this.AvailableMemory.Slice(this.End); + + /// + /// Gets the tail of memory that has not yet been committed. + /// + internal Span RemainingSpan => this.AvailableMemory.Span.Slice(this.End); + + /// + /// Gets the tracker for the underlying array for this segment, which can be used to recycle the array when we're disposed of. + /// Will be null if using an array pool, in which case the memory is held by . + /// + internal IMemoryOwner MemoryOwner { get; private set; } + + /// + /// Gets the full memory owned by the . + /// + internal Memory AvailableMemory => this.array ?? this.MemoryOwner?.Memory ?? default; + + /// + /// Gets the number of elements that are committed in this segment. + /// + internal int Length => this.End - this.Start; + + /// + /// Gets the amount of writable bytes in this segment. + /// It is the amount of bytes between and . + /// + internal int WritableBytes => this.AvailableMemory.Length - this.End; + + /// + /// Gets or sets the next segment in the singly linked list of segments. + /// + internal new SequenceSegment Next + { + get => (SequenceSegment)base.Next; + set => base.Next = value; + } + + /// + /// Assigns this (recyclable) segment a new area in memory. + /// + /// The memory and a means to recycle it. + internal void Assign(IMemoryOwner memoryOwner) + { + this.MemoryOwner = memoryOwner; + this.Memory = memoryOwner.Memory; + } + + /// + /// Assigns this (recyclable) segment a new area in memory. + /// + /// An array drawn from an . + internal void Assign(T[] array) + { + this.array = array; + this.Memory = array; + } + + /// + /// Clears all fields in preparation to recycle this instance. + /// + internal void ResetMemory(ArrayPool arrayPool) + { + this.ClearReferences(this.Start, this.End); + this.Memory = default; + this.Next = null; + this.RunningIndex = 0; + this.Start = 0; + this.End = 0; + if (this.array != null) + { + arrayPool.Return(this.array); + this.array = null; + } + else + { + this.MemoryOwner?.Dispose(); + this.MemoryOwner = null; + } + } + + /// + /// Adds a new segment after this one. + /// + /// The next segment in the linked list. + internal void SetNext(SequenceSegment segment) + { + Debug.Assert(segment != null, "Null not allowed."); + this.Next = segment; + segment.RunningIndex = this.RunningIndex + this.Start + this.Length; + + // When setting Memory, we start with index 0 instead of this.Start because + // the first segment has an explicit index set anyway, + // and we don't want to double-count it here. + this.Memory = this.AvailableMemory.Slice(0, this.Start + this.Length); + } + + /// + /// Commits more elements as written in this segment. + /// + /// The number of elements written. + internal void Advance(int count) + { + Requires.Range(count >= 0 && this.End + count <= this.Memory.Length, nameof(count)); + this.End += count; + } + + /// + /// Removes some elements from the start of this segment. + /// + /// The number of elements to ignore from the start of the underlying array. + internal void AdvanceTo(int offset) + { + Debug.Assert(offset >= this.Start, "Trying to rewind."); + this.ClearReferences(this.Start, offset - this.Start); + this.Start = offset; + } + + private void ClearReferences(int startIndex, int length) + { + // If we store references, clear them to allow the objects to be GC'd. + if (!IsValueTypeElement) + { + this.AvailableMemory.Span.Slice(startIndex, length).Fill(default); + } + } + } + } +} diff --git a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj index d4dc401cd7..ffafb4e262 100644 --- a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj +++ b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj @@ -7,6 +7,8 @@ true true true + CS0436;$(NoWarn) + $(DefineConstants);MESSAGEPACK_INTERNAL @@ -42,6 +44,7 @@ + diff --git a/src/Framework/src/Microsoft.AspNetCore.App.Runtime.csproj b/src/Framework/src/Microsoft.AspNetCore.App.Runtime.csproj index 7e15088844..7af695b6c2 100644 --- a/src/Framework/src/Microsoft.AspNetCore.App.Runtime.csproj +++ b/src/Framework/src/Microsoft.AspNetCore.App.Runtime.csproj @@ -376,6 +376,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant + diff --git a/src/submodules/MessagePack-CSharp b/src/submodules/MessagePack-CSharp index 1917b8018f..8861abdde9 160000 --- a/src/submodules/MessagePack-CSharp +++ b/src/submodules/MessagePack-CSharp @@ -1 +1 @@ -Subproject commit 1917b8018fca93805573663d5baf067e6ac2b137 +Subproject commit 8861abdde93a3b97180ac3b2eafa33459ad52392