diff --git a/src/Elasticsearch.Net/Extensions/UtilExtensions.cs b/src/Elasticsearch.Net/Extensions/UtilExtensions.cs index 88206c42fcb..2891a756bd2 100644 --- a/src/Elasticsearch.Net/Extensions/UtilExtensions.cs +++ b/src/Elasticsearch.Net/Extensions/UtilExtensions.cs @@ -27,6 +27,16 @@ internal static string Utf8String(this MemoryStream ms) return Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); } + /// Attempts to return to underlying bytes buffer (no-copy) if possible + internal static byte[] ToArrayOrBuffer(this MemoryStream ms) + { + if (ms is null) return null; + + if (!ms.TryGetBuffer(out var buffer) || buffer.Array is null) + return ms.ToArray(); + + return buffer.Array; + } internal static byte[] Utf8Bytes(this string s) => s.IsNullOrEmpty() ? null : Encoding.UTF8.GetBytes(s); diff --git a/src/Elasticsearch.Net/Serialization/ElasticsearchSerializerExtensions.cs b/src/Elasticsearch.Net/Serialization/ElasticsearchSerializerExtensions.cs index 1948f5b43a2..4455fcdcd5c 100644 --- a/src/Elasticsearch.Net/Serialization/ElasticsearchSerializerExtensions.cs +++ b/src/Elasticsearch.Net/Serialization/ElasticsearchSerializerExtensions.cs @@ -1,5 +1,4 @@ using Elasticsearch.Net.Extensions; -using Elasticsearch.Net.Utf8Json; namespace Elasticsearch.Net { @@ -16,7 +15,7 @@ public static byte[] SerializeToBytes( using (var ms = memoryStreamFactory.Create()) { serializer.Serialize(data, ms, formatting); - return ms.ToArray(); + return ms.ToArrayOrBuffer(); } } diff --git a/src/Elasticsearch.Net/Transport/Pipeline/ResponseBuilder.cs b/src/Elasticsearch.Net/Transport/Pipeline/ResponseBuilder.cs index c3fe2fcc0df..70521e6d61c 100644 --- a/src/Elasticsearch.Net/Transport/Pipeline/ResponseBuilder.cs +++ b/src/Elasticsearch.Net/Transport/Pipeline/ResponseBuilder.cs @@ -174,7 +174,7 @@ private static bool NeedsToEagerReadStream() private static byte[] SwapStreams(ref Stream responseStream, ref MemoryStream ms) { - var bytes = ms.ToArray(); + var bytes = ms.ToArrayOrBuffer(); responseStream.Dispose(); responseStream = ms; responseStream.Position = 0; diff --git a/src/Elasticsearch.Net/Transport/PostData.cs b/src/Elasticsearch.Net/Transport/PostData.cs index 934d7ad1bbd..2da69af0d8e 100644 --- a/src/Elasticsearch.Net/Transport/PostData.cs +++ b/src/Elasticsearch.Net/Transport/PostData.cs @@ -124,7 +124,7 @@ public override void Write(Stream writableStream, IConnectionConfigurationValues ms.CopyTo(writableStream, BufferSize); } if (Type != 0) - WrittenBytes = ms?.ToArray(); + WrittenBytes = ms?.ToArrayOrBuffer(); } public override async Task WriteAsync(Stream writableStream, IConnectionConfigurationValues settings, CancellationToken cancellationToken) @@ -169,7 +169,7 @@ await settings.RequestResponseSerializer.SerializeAsync(o, stream, Serialization await ms.CopyToAsync(writableStream, BufferSize, cancellationToken).ConfigureAwait(false); } if (Type != 0) - WrittenBytes = ms?.ToArray(); + WrittenBytes = ms?.ToArrayOrBuffer(); } } } diff --git a/src/Elasticsearch.Net/Transport/SerializableData.cs b/src/Elasticsearch.Net/Transport/SerializableData.cs index ac769d01186..5006a386e55 100644 --- a/src/Elasticsearch.Net/Transport/SerializableData.cs +++ b/src/Elasticsearch.Net/Transport/SerializableData.cs @@ -1,6 +1,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Elasticsearch.Net.Extensions; namespace Elasticsearch.Net { @@ -31,7 +32,7 @@ public override void Write(Stream writableStream, IConnectionConfigurationValues ms.CopyTo(writableStream, BufferSize); } if (Type != 0) - WrittenBytes = ms?.ToArray(); + WrittenBytes = ms?.ToArrayOrBuffer(); } public static implicit operator SerializableData(T serializableData) => new SerializableData(serializableData); @@ -53,7 +54,7 @@ public override async Task WriteAsync(Stream writableStream, IConnectionConfigur await ms.CopyToAsync(writableStream, BufferSize, cancellationToken).ConfigureAwait(false); } if (Type != 0) - WrittenBytes = ms?.ToArray(); + WrittenBytes = ms?.ToArrayOrBuffer(); } } } diff --git a/src/Elasticsearch.Net/Utf8Json/Internal/BinaryUtil.cs b/src/Elasticsearch.Net/Utf8Json/Internal/BinaryUtil.cs index 1aab9555058..49a9ccb33de 100644 --- a/src/Elasticsearch.Net/Utf8Json/Internal/BinaryUtil.cs +++ b/src/Elasticsearch.Net/Utf8Json/Internal/BinaryUtil.cs @@ -112,9 +112,8 @@ public static byte[] FastCloneWithResize(byte[] src, int newSize) { if (newSize < 0) throw new ArgumentOutOfRangeException("newSize"); - if (src.Length < newSize) throw new ArgumentException("length < newSize"); - if (src == null) return new byte[newSize]; + if (src.Length < newSize) throw new ArgumentException("length < newSize"); byte[] dst = new byte[newSize]; diff --git a/src/Nest/Cat/CatHelpResponseBuilder.cs b/src/Nest/Cat/CatHelpResponseBuilder.cs index a985dc94142..909552db5eb 100644 --- a/src/Nest/Cat/CatHelpResponseBuilder.cs +++ b/src/Nest/Cat/CatHelpResponseBuilder.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Elasticsearch.Net; +using Elasticsearch.Net.Extensions; namespace Nest { @@ -20,7 +21,7 @@ public override object DeserializeResponse(IElasticsearchSerializer builtInSeria using (var ms = response.ConnectionConfiguration.MemoryStreamFactory.Create()) { stream.CopyTo(ms); - var body = ms.ToArray().Utf8String(); + var body = ms.Utf8String(); Parse(catResponse, body); } @@ -46,7 +47,7 @@ public override async Task DeserializeResponseAsync(IElasticsearchSerial using (var ms = response.ConnectionConfiguration.MemoryStreamFactory.Create()) { await stream.CopyToAsync(ms, 81920, ctx); - var body = ms.ToArray().Utf8String(); + var body = ms.Utf8String(); Parse(catResponse, body); } diff --git a/src/Nest/CommonAbstractions/Extensions/Extensions.cs b/src/Nest/CommonAbstractions/Extensions/Extensions.cs index 255de369a58..e9060e8e067 100644 --- a/src/Nest/CommonAbstractions/Extensions/Extensions.cs +++ b/src/Nest/CommonAbstractions/Extensions/Extensions.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Serialization; @@ -96,7 +97,6 @@ internal static string ToEnumValue(this T enumValue) where T : struct return null; } - internal static string Utf8String(this ref ArraySegment segment) => StringEncoding.UTF8.GetString(segment.Array, segment.Offset, segment.Count); @@ -161,7 +161,7 @@ internal static bool IsEmpty(this IEnumerable list) return !enumerable.Any() || enumerable.All(t => t == null); } - internal static void ThrowIfNull(this T value, string name, string message = null) + internal static void ThrowIfNull(this T value, string name, string message = null) { if (value == null && message.IsNullOrEmpty()) throw new ArgumentNullException(name); else if (value == null) throw new ArgumentNullException(name, "Argument can not be null when " + message); diff --git a/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/ProxyRequestFormatterBase.cs b/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/ProxyRequestFormatterBase.cs index bf3e906fb4e..17b2b9eb5fe 100644 --- a/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/ProxyRequestFormatterBase.cs +++ b/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/ProxyRequestFormatterBase.cs @@ -1,5 +1,6 @@ using System.Reflection; using Elasticsearch.Net; +using Elasticsearch.Net.Extensions; using Elasticsearch.Net.Utf8Json; namespace Nest @@ -41,7 +42,7 @@ public void Serialize(ref JsonWriter writer, TRequestInterface value, IJsonForma using (var ms = settings.MemoryStreamFactory.Create()) { untypedDocumentRequest.WriteJson(serializer, ms, SerializationFormatting.None); - var v = ms.ToArray(); + var v = ms.ToArrayOrBuffer(); writer.WriteRaw(v); } } diff --git a/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/SourceFormatter.cs b/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/SourceFormatter.cs index 00124c73741..0c226e74008 100644 --- a/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/SourceFormatter.cs +++ b/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/SourceFormatter.cs @@ -1,4 +1,5 @@ using Elasticsearch.Net; +using Elasticsearch.Net.Extensions; using Elasticsearch.Net.Utf8Json; namespace Nest @@ -43,7 +44,7 @@ public virtual void Serialize(ref JsonWriter writer, T value, IJsonFormatterReso { sourceSerializer.Serialize(value, ms, f); // TODO: read each byte instead of creating and allocating an array - bytes = ms.ToArray(); + bytes = ms.ToArrayOrBuffer(); } writer.WriteRaw(bytes);