This is an automated email from the ASF dual-hosted git repository. ptupitsyn pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push: new 971f318 IGNITE-13883 .NET: Simplify and optimize TryReadSystemType 971f318 is described below commit 971f31852a9fbdf14f0fd987d87d344b97298000 Author: Pavel Tupitsyn <ptupit...@apache.org> AuthorDate: Wed Dec 30 10:22:08 2020 +0300 IGNITE-13883 .NET: Simplify and optimize TryReadSystemType Replace dictionary+interfaces with a simple switch statement in `BinarySystemHandlers.TryReadSystemType`: * Less code * Simpler * Faster Benchmark added: `BinarySystemTypeReadBenchmark`; results on Core i7-9700K, Ubuntu 20.04, .NET Core 3.1: ``` | | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | |------- |---------:|----------:|----------:|-------:|------:|------:|----------:| | Before | 1.080 us | 0.0030 us | 0.0025 us | 0.0725 | - | - | 456 B | | After | 849.4 ns | 4.44 ns | 4.16 ns | 0.0725 | - | - | 456 B | ``` (~20% improvement) --- .../Apache.Ignite.BenchmarkDotNet.csproj | 4 + .../Apache.Ignite.BenchmarkDotNet.snk | Bin 0 -> 596 bytes .../Binary/BinarySystemTypeReadBenchmark.cs | 124 +++++++ .../Apache.Ignite.BenchmarkDotNet/Program.cs | 4 +- .../Apache.Ignite.Core.Tests/Services/Model.cs | 13 +- .../Apache.Ignite.Core/Impl/Binary/BinaryReader.cs | 28 +- .../Impl/Binary/BinarySystemHandlers.cs | 407 +++++++-------------- .../Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs | 56 ++- .../Apache.Ignite.Core/Properties/AssemblyInfo.cs | 1 + 9 files changed, 337 insertions(+), 300 deletions(-) diff --git a/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Apache.Ignite.BenchmarkDotNet.csproj b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Apache.Ignite.BenchmarkDotNet.csproj index 338ddd8..b2ff028 100644 --- a/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Apache.Ignite.BenchmarkDotNet.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Apache.Ignite.BenchmarkDotNet.csproj @@ -5,6 +5,10 @@ <TargetFramework>netcoreapp2.0</TargetFramework> <ServerGarbageCollection>true</ServerGarbageCollection> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> + <AssemblyOriginatorKeyFile>Apache.Ignite.BenchmarkDotNet.snk</AssemblyOriginatorKeyFile> + <SignAssembly>true</SignAssembly> + <DelaySign>false</DelaySign> + <ServerGarbageCollection>true</ServerGarbageCollection> </PropertyGroup> <ItemGroup> diff --git a/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Apache.Ignite.BenchmarkDotNet.snk b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Apache.Ignite.BenchmarkDotNet.snk new file mode 100644 index 0000000..886b6bb Binary files /dev/null and b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Apache.Ignite.BenchmarkDotNet.snk differ diff --git a/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Binary/BinarySystemTypeReadBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Binary/BinarySystemTypeReadBenchmark.cs new file mode 100644 index 0000000..c40b403 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Binary/BinarySystemTypeReadBenchmark.cs @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ReSharper disable RedundantCast +namespace Apache.Ignite.BenchmarkDotNet.Binary +{ + using System; + using System.IO; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Impl.Binary; + using Apache.Ignite.Core.Impl.Memory; + using global::BenchmarkDotNet.Attributes; + using BinaryReader = Apache.Ignite.Core.Impl.Binary.BinaryReader; + + /// <summary> + /// System type reading benchmark. Checks <see cref="BinarySystemHandlers.TryReadSystemType{T}"/> performance. + /// <para /> + /// Results on Core i7-9700K, Ubuntu 20.04, .NET Core 3.1: + /// | Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | + /// |------- |---------:|--------:|--------:|-------:|------:|------:|----------:| + /// | Read | 849.4 ns | 4.44 ns | 4.16 ns | 0.0725 | - | - | 456 B | + /// </summary> + [MemoryDiagnoser] + public class BinarySystemTypeReadBenchmark + { + /** */ + private static readonly DateTime DateTime = new DateTime(2010, 10, 10).ToUniversalTime(); + + /** */ + private static readonly Guid Guid = Guid.NewGuid(); + + /** */ + private static readonly Marshaller Marsh = new Marshaller(new BinaryConfiguration {ForceTimestamp = true}); + + /** */ + private static readonly PlatformMemoryManager MemMgr = new PlatformMemoryManager(1024); + + /** */ + private BinaryReader _reader; + + /// <summary> + /// Sets up the benchmark. + /// </summary> + [GlobalSetup] + public void Setup() + { + var mem = MemMgr.Allocate(); + var stream = mem.GetStream(); + var writer = Marsh.StartMarshal(stream); + + writer.Write(true); + writer.Write('i'); + writer.Write((byte) 1); + writer.Write((short) 2); + writer.Write((int) 3); + writer.Write((long) 4); + writer.Write((float) 5.5); + writer.Write((double) 6.6); + writer.Write((decimal) 7.7); + writer.Write(DateTime); + writer.Write(Guid); + + writer.Write(new[] {true}); + writer.Write(new[] {'i'}); + writer.Write(new[] {(byte) 1}); + writer.Write(new[] {(short) 2}); + writer.Write(new[] {(int) 3}); + writer.Write(new[] {(long) 4}); + writer.Write(new[] {(float) 5.5}); + writer.Write(new[] {(double) 6.6}); + writer.Write(new[] {(decimal?) 7.7}); + writer.Write(new DateTime?[] {DateTime}); + writer.Write(new Guid?[] {Guid}); + + stream.SynchronizeOutput(); + + _reader = Marsh.StartUnmarshal(stream); + } + + [Benchmark] + public void Read() + { + _reader.Stream.Seek(0, SeekOrigin.Begin); + + _reader.ReadObject<bool>(); + _reader.ReadObject<char>(); + _reader.ReadObject<byte>(); + _reader.ReadObject<short>(); + _reader.ReadObject<int>(); + _reader.ReadObject<long>(); + _reader.ReadObject<float>(); + _reader.ReadObject<double>(); + _reader.ReadObject<decimal>(); + _reader.ReadObject<DateTime>(); + _reader.ReadObject<Guid>(); + + _reader.ReadObject<bool[]>(); + _reader.ReadObject<char[]>(); + _reader.ReadObject<byte[]>(); + _reader.ReadObject<short[]>(); + _reader.ReadObject<int[]>(); + _reader.ReadObject<long[]>(); + _reader.ReadObject<float[]>(); + _reader.ReadObject<double[]>(); + _reader.ReadObject<decimal?[]>(); + _reader.ReadObject<DateTime?[]>(); + _reader.ReadObject<Guid?[]>(); + } + } +} diff --git a/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Program.cs b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Program.cs index d9f53d4..3a1513b 100644 --- a/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Program.cs +++ b/modules/platforms/dotnet/Apache.Ignite.BenchmarkDotNet/Program.cs @@ -17,7 +17,7 @@ namespace Apache.Ignite.BenchmarkDotNet { - using Apache.Ignite.BenchmarkDotNet.ThinClient; + using Apache.Ignite.BenchmarkDotNet.Binary; using global::BenchmarkDotNet.Running; /// <summary> @@ -30,7 +30,7 @@ namespace Apache.Ignite.BenchmarkDotNet /// </summary> public static void Main() { - BenchmarkRunner.Run<ThinClientServicesBenchmark>(); + BenchmarkRunner.Run<BinarySystemTypeReadBenchmark>(); } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs index e030098..e239c45 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs @@ -94,7 +94,7 @@ namespace org.apache.ignite.platform.model public class Account { public String Id { get; set; } - + public int Amount { get; set; } protected bool Equals(Account other) @@ -120,6 +120,7 @@ namespace org.apache.ignite.platform.model /// <summary> /// A enum is a clone of Java class User with the same namespace. /// </summary> + // ReSharper disable once InconsistentNaming public enum ACL { Allow, Deny @@ -139,16 +140,16 @@ namespace org.apache.ignite.platform.model public class User { public int Id { get; set; } - + public ACL Acl { get; set; } - + public Role Role { get; set; } - } - + } + /// <summary> /// A class is a clone of Java class ParamValue with the same namespace. /// </summary> - public class ParamValue + public class ParamValue { /** */ public int Id { get; set; } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs index c1a6fed..2d266d6 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs @@ -29,7 +29,7 @@ namespace Apache.Ignite.Core.Impl.Binary using Apache.Ignite.Core.Impl.Common; /// <summary> - /// Binary reader implementation. + /// Binary reader implementation. /// </summary> internal class BinaryReader : IBinaryReader, IBinaryRawReader { @@ -60,7 +60,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="builder">Builder.</param> public BinaryReader (Marshaller marsh, - IBinaryStream stream, + IBinaryStream stream, BinaryMode mode, BinaryObjectBuilder builder) { @@ -323,19 +323,19 @@ namespace Apache.Ignite.Core.Impl.Binary { return Read(stream => BinaryUtils.ReadTimestamp(stream, _marsh.TimestampConverter), BinaryTypeId.Timestamp); } - + /** <inheritdoc /> */ public DateTime?[] ReadTimestampArray(string fieldName) { return ReadField(fieldName, stream => BinaryUtils.ReadTimestampArray(stream, _marsh.TimestampConverter), BinaryTypeId.ArrayTimestamp); } - + /** <inheritdoc /> */ public DateTime?[] ReadTimestampArray() { return Read(stream => BinaryUtils.ReadTimestampArray(stream, _marsh.TimestampConverter), BinaryTypeId.ArrayTimestamp); } - + /** <inheritdoc /> */ public string ReadString(string fieldName) { @@ -351,13 +351,13 @@ namespace Apache.Ignite.Core.Impl.Binary /** <inheritdoc /> */ public string[] ReadStringArray(string fieldName) { - return ReadField(fieldName, r => BinaryUtils.ReadArray<string>(r, false), BinaryTypeId.ArrayString); + return ReadField(fieldName, stream => BinaryUtils.ReadStringArray(stream), BinaryTypeId.ArrayString); } /** <inheritdoc /> */ public string[] ReadStringArray() { - return Read(r => BinaryUtils.ReadArray<string>(r, false), BinaryTypeId.ArrayString); + return Read(stream => BinaryUtils.ReadStringArray(stream), BinaryTypeId.ArrayString); } /** <inheritdoc /> */ @@ -375,13 +375,13 @@ namespace Apache.Ignite.Core.Impl.Binary /** <inheritdoc /> */ public Guid?[] ReadGuidArray(string fieldName) { - return ReadField(fieldName, r => BinaryUtils.ReadArray<Guid?>(r, false), BinaryTypeId.ArrayGuid); + return ReadField(fieldName, stream => BinaryUtils.ReadGuidArray(stream), BinaryTypeId.ArrayGuid); } /** <inheritdoc /> */ public Guid?[] ReadGuidArray() { - return Read(r => BinaryUtils.ReadArray<Guid?>(r, false), BinaryTypeId.ArrayGuid); + return Read(stream => BinaryUtils.ReadGuidArray(stream), BinaryTypeId.ArrayGuid); } /** <inheritdoc /> */ @@ -410,7 +410,7 @@ namespace Apache.Ignite.Core.Impl.Binary // Unregistered enum written as serializable Stream.Seek(-1, SeekOrigin.Current); - return ReadObject<T>(); + return ReadObject<T>(); default: throw new BinaryObjectException(string.Format( @@ -474,7 +474,7 @@ namespace Apache.Ignite.Core.Impl.Binary } /** <inheritdoc /> */ - public ICollection ReadCollection(string fieldName, Func<int, ICollection> factory, + public ICollection ReadCollection(string fieldName, Func<int, ICollection> factory, Action<ICollection, object> adder) { return ReadField(fieldName, r => BinaryUtils.ReadCollection(r, factory, adder), BinaryTypeId.Collection); @@ -511,7 +511,7 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Enable detach mode for the next object read. + /// Enable detach mode for the next object read. /// </summary> public BinaryReader DetachNext() { @@ -800,7 +800,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (_frame.Schema == null) { - _frame.Schema = + _frame.Schema = BinaryObjectSchemaSerializer.GetFieldIds(_frame.Hdr, Marshaller.Ignite, Stream, _frame.Pos); desc.Schema.Add(_frame.Hdr.SchemaId, _frame.Schema); @@ -889,7 +889,7 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Mark current output as raw. + /// Mark current output as raw. /// </summary> private void MarkRaw() { diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs index 8fdf371..58a4d24 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs @@ -20,8 +20,6 @@ namespace Apache.Ignite.Core.Impl.Binary using System; using System.Collections; using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using Apache.Ignite.Core.Impl.Binary.IO; using Apache.Ignite.Core.Impl.Common; /** @@ -33,83 +31,13 @@ namespace Apache.Ignite.Core.Impl.Binary private static readonly CopyOnWriteConcurrentDictionary<Type, IBinarySystemWriteHandler> WriteHandlers = new CopyOnWriteConcurrentDictionary<Type, IBinarySystemWriteHandler>(); - /** Read handlers. */ - private static readonly IBinarySystemReader[] ReadHandlers = new IBinarySystemReader[255]; - - /// <summary> - /// Initializes the <see cref="BinarySystemHandlers"/> class. - /// </summary> - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", - Justification = "Readability.")] - static BinarySystemHandlers() - { - // 1. Primitives. - ReadHandlers[BinaryTypeId.Bool] = new BinarySystemReader<bool>(s => s.ReadBool()); - ReadHandlers[BinaryTypeId.Byte] = new BinarySystemReader<byte>(s => s.ReadByte()); - ReadHandlers[BinaryTypeId.Short] = new BinarySystemReader<short>(s => s.ReadShort()); - ReadHandlers[BinaryTypeId.Char] = new BinarySystemReader<char>(s => s.ReadChar()); - ReadHandlers[BinaryTypeId.Int] = new BinarySystemReader<int>(s => s.ReadInt()); - ReadHandlers[BinaryTypeId.Long] = new BinarySystemReader<long>(s => s.ReadLong()); - ReadHandlers[BinaryTypeId.Float] = new BinarySystemReader<float>(s => s.ReadFloat()); - ReadHandlers[BinaryTypeId.Double] = new BinarySystemReader<double>(s => s.ReadDouble()); - ReadHandlers[BinaryTypeId.Decimal] = new BinarySystemReader<decimal?>(BinaryUtils.ReadDecimal); - - // 3. String. - ReadHandlers[BinaryTypeId.String] = new BinarySystemReader<string>(BinaryUtils.ReadString); - - // 4. Guid. - ReadHandlers[BinaryTypeId.Guid] = new BinarySystemReader<Guid?>(s => BinaryUtils.ReadGuid(s)); - - // 5. Primitive arrays. - ReadHandlers[BinaryTypeId.ArrayBool] = new BinarySystemReader<bool[]>(BinaryUtils.ReadBooleanArray); - - ReadHandlers[BinaryTypeId.ArrayByte] = - new BinarySystemDualReader<byte[], sbyte[]>(BinaryUtils.ReadByteArray, BinaryUtils.ReadSbyteArray); - - ReadHandlers[BinaryTypeId.ArrayShort] = - new BinarySystemDualReader<short[], ushort[]>(BinaryUtils.ReadShortArray, - BinaryUtils.ReadUshortArray); - - ReadHandlers[BinaryTypeId.ArrayChar] = - new BinarySystemReader<char[]>(BinaryUtils.ReadCharArray); - - ReadHandlers[BinaryTypeId.ArrayInt] = - new BinarySystemDualReader<int[], uint[]>(BinaryUtils.ReadIntArray, BinaryUtils.ReadUintArray); - - ReadHandlers[BinaryTypeId.ArrayLong] = - new BinarySystemDualReader<long[], ulong[]>(BinaryUtils.ReadLongArray, - BinaryUtils.ReadUlongArray); - - ReadHandlers[BinaryTypeId.ArrayFloat] = - new BinarySystemReader<float[]>(BinaryUtils.ReadFloatArray); - - ReadHandlers[BinaryTypeId.ArrayDouble] = - new BinarySystemReader<double[]>(BinaryUtils.ReadDoubleArray); - - ReadHandlers[BinaryTypeId.ArrayDecimal] = - new BinarySystemReader<decimal?[]>(BinaryUtils.ReadDecimalArray); - - // 7. String array. - ReadHandlers[BinaryTypeId.ArrayString] = new BinarySystemTypedArrayReader<string>(); - - // 8. Guid array. - ReadHandlers[BinaryTypeId.ArrayGuid] = new BinarySystemTypedArrayReader<Guid?>(); - - // 9. Array. - ReadHandlers[BinaryTypeId.Array] = new BinarySystemReader(ReadArray); - - // 11. Arbitrary collection. - ReadHandlers[BinaryTypeId.Collection] = new BinarySystemReader(ReadCollection); - - // 13. Arbitrary dictionary. - ReadHandlers[BinaryTypeId.Dictionary] = new BinarySystemReader(ReadDictionary); - - // 14. Enum. Should be read as Array, see WriteEnumArray implementation. - ReadHandlers[BinaryTypeId.ArrayEnum] = new BinarySystemReader(ReadArray); + /** */ + private static readonly BinarySystemWriteHandler<DateTime> TimestampWriteHandler = + new BinarySystemWriteHandler<DateTime>(WriteTimestamp, false); - // 15. Optimized marshaller objects. - ReadHandlers[BinaryTypeId.OptimizedMarshaller] = new BinarySystemReader(ReadOptimizedMarshallerObject); - } + /** */ + private static readonly BinarySystemWriteHandler<DateTime?[]> TimestampArrayWriteHandler = + new BinarySystemWriteHandler<DateTime?[]>(WriteTimestampArray, true); /// <summary> /// Try getting write handler for type. @@ -122,9 +50,10 @@ namespace Apache.Ignite.Core.Impl.Binary if (forceTimestamp) { if (type == typeof(DateTime)) - return new BinarySystemWriteHandler<DateTime>(WriteTimestamp, false); + return TimestampWriteHandler; + if (type == typeof(DateTime?[])) - return new BinarySystemWriteHandler<DateTime?[]>(WriteTimestampArray, true); + return TimestampArrayWriteHandler; } return WriteHandlers.GetOrAdd(type, t => @@ -192,7 +121,7 @@ namespace Apache.Ignite.Core.Impl.Binary // We know how to write any array type. Type elemType = type.GetElementType(); - + // Primitives. if (elemType == typeof (bool)) return new BinarySystemWriteHandler<bool[]>(WriteBoolArray, true); @@ -247,32 +176,139 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> public static bool TryReadSystemType<T>(byte typeId, BinaryReader ctx, out T res) { - var handler = ReadHandlers[typeId]; + var stream = ctx.Stream; - if (handler == null) + switch (typeId) { - if (typeId == BinaryTypeId.Timestamp) - { - // Date. - res = TypeCaster<T>.Cast(BinaryUtils.ReadTimestamp(ctx.Stream, ctx.Marshaller.TimestampConverter)); + case BinaryTypeId.Byte: + res = TypeCaster<T>.Cast(stream.ReadByte()); return true; - } - if (typeId == BinaryTypeId.ArrayTimestamp) - { - // Date array. - res = TypeCaster<T>.Cast(BinaryUtils.ReadTimestampArray(ctx.Stream, ctx.Marshaller.TimestampConverter)); + case BinaryTypeId.Short: + res = TypeCaster<T>.Cast(stream.ReadShort()); + return true; + + case BinaryTypeId.Int: + res = TypeCaster<T>.Cast(stream.ReadInt()); + return true; + + case BinaryTypeId.Long: + res = TypeCaster<T>.Cast(stream.ReadLong()); + return true; + + case BinaryTypeId.Float: + res = TypeCaster<T>.Cast(stream.ReadFloat()); + return true; + + case BinaryTypeId.Double: + res = TypeCaster<T>.Cast(stream.ReadDouble()); + return true; + + case BinaryTypeId.Char: + res = TypeCaster<T>.Cast(stream.ReadChar()); + return true; + + case BinaryTypeId.Bool: + res = TypeCaster<T>.Cast(stream.ReadBool()); + return true; + + case BinaryTypeId.String: + res = TypeCaster<T>.Cast(BinaryUtils.ReadString(stream)); + return true; + + case BinaryTypeId.Guid: + res = TypeCaster<T>.Cast(BinaryUtils.ReadGuid(stream)); + return true; + + case BinaryTypeId.ArrayByte: + res = typeof(T) == typeof(sbyte[]) + ? TypeCaster<T>.Cast(BinaryUtils.ReadSbyteArray(stream)) + : TypeCaster<T>.Cast(BinaryUtils.ReadByteArray(stream)); + return true; + + case BinaryTypeId.ArrayShort: + res = typeof(T) == typeof(ushort[]) + ? TypeCaster<T>.Cast(BinaryUtils.ReadUshortArray(stream)) + : TypeCaster<T>.Cast(BinaryUtils.ReadShortArray(stream)); + return true; + + case BinaryTypeId.ArrayInt: + res = typeof(T) == typeof(uint[]) + ? TypeCaster<T>.Cast(BinaryUtils.ReadUintArray(stream)) + : TypeCaster<T>.Cast(BinaryUtils.ReadIntArray(stream)); + return true; + + case BinaryTypeId.ArrayLong: + res = typeof(T) == typeof(ulong[]) + ? TypeCaster<T>.Cast(BinaryUtils.ReadUlongArray(stream)) + : TypeCaster<T>.Cast(BinaryUtils.ReadLongArray(stream)); + return true; + + case BinaryTypeId.ArrayFloat: + res = TypeCaster<T>.Cast(BinaryUtils.ReadFloatArray(stream)); + return true; + + case BinaryTypeId.ArrayDouble: + res = TypeCaster<T>.Cast(BinaryUtils.ReadDoubleArray(stream)); + return true; + + case BinaryTypeId.ArrayChar: + res = TypeCaster<T>.Cast(BinaryUtils.ReadCharArray(stream)); + return true; + + case BinaryTypeId.ArrayBool: + res = TypeCaster<T>.Cast(BinaryUtils.ReadBooleanArray(stream)); + return true; + + case BinaryTypeId.ArrayString: + res = TypeCaster<T>.Cast(BinaryUtils.ReadStringArray(stream)); + return true; + + case BinaryTypeId.ArrayGuid: + res = TypeCaster<T>.Cast(BinaryUtils.ReadGuidArray(stream)); + return true; + + case BinaryTypeId.Array: + res = (T) ReadArray(ctx, typeof(T)); + return true; + + case BinaryTypeId.Collection: + res = (T) BinaryUtils.ReadCollection(ctx, null, null); + return true; + + case BinaryTypeId.Dictionary: + res = (T) BinaryUtils.ReadDictionary(ctx, null); + return true; + + case BinaryTypeId.ArrayEnum: + res = (T) ReadArray(ctx, typeof(T)); + return true; + + case BinaryTypeId.Decimal: + res = TypeCaster<T>.Cast(BinaryUtils.ReadDecimal(stream)); + return true; + + case BinaryTypeId.ArrayDecimal: + res = TypeCaster<T>.Cast(BinaryUtils.ReadDecimalArray(stream)); + return true; + + case BinaryTypeId.Timestamp: + res = TypeCaster<T>.Cast(BinaryUtils.ReadTimestamp(stream, ctx.Marshaller.TimestampConverter)); + return true; + + case BinaryTypeId.ArrayTimestamp: + res = TypeCaster<T>.Cast(BinaryUtils.ReadTimestampArray(stream, ctx.Marshaller.TimestampConverter)); return true; - } - res = default(T); - return false; + case BinaryTypeId.OptimizedMarshaller: + res = (T) (object) new OptimizedMarshallerObject(ctx.Stream); + return true; } - res = handler.Read<T>(ctx); - return true; + res = default(T); + return false; } - + /// <summary> /// Write decimal. /// </summary> @@ -284,7 +320,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryUtils.WriteDecimal(obj, ctx.Stream); } - + /// <summary> /// Write string. /// </summary> @@ -332,7 +368,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryUtils.WriteBooleanArray(obj, ctx.Stream); } - + /// <summary> /// Write byte array. /// </summary> @@ -356,7 +392,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryUtils.WriteShortArray(obj, ctx.Stream); } - + /// <summary> /// Write char array. /// </summary> @@ -428,7 +464,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryUtils.WriteDecimalArray(obj, ctx.Stream); } - + /// <summary> /// Write string array. /// </summary> @@ -440,7 +476,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryUtils.WriteStringArray(obj, ctx.Stream); } - + /// <summary> /// Write nullable GUID array. /// </summary> @@ -514,7 +550,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryUtils.WriteBinary(ctx.Stream, obj); } - + /// <summary> /// Write enum. /// </summary> @@ -557,22 +593,6 @@ namespace Apache.Ignite.Core.Impl.Binary return BinaryUtils.ReadTypedArray(ctx, true, elemType); } - /** - * <summary>Read collection.</summary> - */ - private static object ReadCollection(BinaryReader ctx, Type type) - { - return BinaryUtils.ReadCollection(ctx, null, null); - } - - /** - * <summary>Read dictionary.</summary> - */ - private static object ReadDictionary(BinaryReader ctx, Type type) - { - return BinaryUtils.ReadDictionary(ctx, null); - } - /// <summary> /// Write Ignite. /// </summary> @@ -580,151 +600,6 @@ namespace Apache.Ignite.Core.Impl.Binary { ctx.Stream.WriteByte(BinaryUtils.HdrNull); } - - /// <summary> - /// Reads the optimized marshaller object. - /// </summary> - private static object ReadOptimizedMarshallerObject(BinaryReader ctx, Type type) - { - return new OptimizedMarshallerObject(ctx.Stream); - } - - /** - * <summary>Read delegate.</summary> - * <param name="ctx">Read context.</param> - * <param name="type">Type.</param> - */ - private delegate object BinarySystemReadDelegate(BinaryReader ctx, Type type); - - /// <summary> - /// System type reader. - /// </summary> - private interface IBinarySystemReader - { - /// <summary> - /// Reads a value of specified type from reader. - /// </summary> - T Read<T>(BinaryReader ctx); - } - - /// <summary> - /// System type generic reader. - /// </summary> - private interface IBinarySystemReader<out T> - { - /// <summary> - /// Reads a value of specified type from reader. - /// </summary> - T Read(BinaryReader ctx); - } - - /// <summary> - /// Default reader with boxing. - /// </summary> - private class BinarySystemReader : IBinarySystemReader - { - /** */ - private readonly BinarySystemReadDelegate _readDelegate; - - /// <summary> - /// Initializes a new instance of the <see cref="BinarySystemReader"/> class. - /// </summary> - /// <param name="readDelegate">The read delegate.</param> - public BinarySystemReader(BinarySystemReadDelegate readDelegate) - { - Debug.Assert(readDelegate != null); - - _readDelegate = readDelegate; - } - - /** <inheritdoc /> */ - public T Read<T>(BinaryReader ctx) - { - return (T)_readDelegate(ctx, typeof(T)); - } - } - - /// <summary> - /// Reader without boxing. - /// </summary> - private class BinarySystemReader<T> : IBinarySystemReader - { - /** */ - private readonly Func<IBinaryStream, T> _readDelegate; - - /// <summary> - /// Initializes a new instance of the <see cref="BinarySystemReader{T}"/> class. - /// </summary> - /// <param name="readDelegate">The read delegate.</param> - public BinarySystemReader(Func<IBinaryStream, T> readDelegate) - { - Debug.Assert(readDelegate != null); - - _readDelegate = readDelegate; - } - - /** <inheritdoc /> */ - public TResult Read<TResult>(BinaryReader ctx) - { - return TypeCaster<TResult>.Cast(_readDelegate(ctx.Stream)); - } - } - - /// <summary> - /// Reader without boxing. - /// </summary> - private class BinarySystemTypedArrayReader<T> : IBinarySystemReader - { - public TResult Read<TResult>(BinaryReader ctx) - { - return TypeCaster<TResult>.Cast(BinaryUtils.ReadArray<T>(ctx, false)); - } - } - - /// <summary> - /// Reader with selection based on requested type. - /// </summary> - private class BinarySystemDualReader<T1, T2> : IBinarySystemReader, IBinarySystemReader<T2> - { - /** */ - private readonly Func<IBinaryStream, T1> _readDelegate1; - - /** */ - private readonly Func<IBinaryStream, T2> _readDelegate2; - - /// <summary> - /// Initializes a new instance of the <see cref="BinarySystemDualReader{T1,T2}"/> class. - /// </summary> - /// <param name="readDelegate1">The read delegate1.</param> - /// <param name="readDelegate2">The read delegate2.</param> - public BinarySystemDualReader(Func<IBinaryStream, T1> readDelegate1, Func<IBinaryStream, T2> readDelegate2) - { - Debug.Assert(readDelegate1 != null); - Debug.Assert(readDelegate2 != null); - - _readDelegate1 = readDelegate1; - _readDelegate2 = readDelegate2; - } - - /** <inheritdoc /> */ - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods")] - T2 IBinarySystemReader<T2>.Read(BinaryReader ctx) - { - return _readDelegate2(ctx.Stream); - } - - /** <inheritdoc /> */ - public T Read<T>(BinaryReader ctx) - { - // Can't use "as" because of variance. - // For example, IBinarySystemReader<byte[]> can be cast to IBinarySystemReader<sbyte[]>, which - // will cause incorrect behavior. - if (typeof (T) == typeof (T2)) - return ((IBinarySystemReader<T>) this).Read(ctx); - - return TypeCaster<T>.Cast(_readDelegate1(ctx.Stream)); - } - } } /// <summary> @@ -748,7 +623,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <summary> /// Write delegate + handles flag. /// </summary> - internal class BinarySystemWriteHandler<T1> : IBinarySystemWriteHandler + internal sealed class BinarySystemWriteHandler<T1> : IBinarySystemWriteHandler { /** */ private readonly Action<BinaryWriter, T1> _writeAction; diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs index 82e2284..a60411f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs @@ -110,9 +110,9 @@ namespace Apache.Ignite.Core.Impl.Binary /** String mode. */ public static readonly bool UseStringSerializationVer2 = (Environment.GetEnvironmentVariable(IgniteBinaryMarshallerUseStringSerializationVer2) ?? "false") == "true"; - + /** Cached maps of enum members per type. */ - private static readonly CopyOnWriteConcurrentDictionary<Type, Dictionary<string, int>> EnumValues = + private static readonly CopyOnWriteConcurrentDictionary<Type, Dictionary<string, int>> EnumValues = new CopyOnWriteConcurrentDictionary<Type, Dictionary<string, int>>(); /// <summary> @@ -926,7 +926,7 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Writes a guid with bitwise conversion, assuming that <see cref="Guid"/> + /// Writes a guid with bitwise conversion, assuming that <see cref="Guid"/> /// is laid out in memory sequentially and without gaps between fields. /// </summary> /// <param name="val">The value.</param> @@ -974,7 +974,7 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Reads a guid with bitwise conversion, assuming that <see cref="Guid"/> + /// Reads a guid with bitwise conversion, assuming that <see cref="Guid"/> /// is laid out in memory sequentially and without gaps between fields. /// </summary> /// <param name="stream">The stream.</param> @@ -1103,8 +1103,8 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> public static int GetArrayElementTypeId(Type elemType, Marshaller marsh) { - return elemType == typeof(object) - ? ObjTypeId + return elemType == typeof(object) + ? ObjTypeId : marsh.GetDescriptor(elemType).TypeId; } @@ -1171,6 +1171,38 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> + /// Read string array. + /// </summary> + /// <param name="stream">Stream</param> + /// <returns>String array.</returns> + public static string[] ReadStringArray(IBinaryStream stream) + { + var len = stream.ReadInt(); + var res = new string[len]; + + for (var i = 0; i < len; i++) + res[i] = stream.ReadByte() == HdrNull ? null : ReadString(stream); + + return res; + } + + /// <summary> + /// Read string array. + /// </summary> + /// <param name="stream">Stream</param> + /// <returns>String array.</returns> + public static Guid?[] ReadGuidArray(IBinaryStream stream) + { + var len = stream.ReadInt(); + var res = new Guid?[len]; + + for (var i = 0; i < len; i++) + res[i] = stream.ReadByte() == HdrNull ? (Guid?) null : ReadGuid(stream); + + return res; + } + + /// <summary> /// Read timestamp array. /// </summary> /// <param name="stream">Stream.</param> @@ -1596,7 +1628,7 @@ namespace Apache.Ignite.Core.Impl.Binary err = null; if (reader.ReadBoolean()) // success indication - return reader.ReadObject<object>(); + return reader.ReadObject<object>(); err = reader.ReadBoolean() // native error indication ? reader.ReadObject<object>() @@ -1746,7 +1778,7 @@ namespace Apache.Ignite.Core.Impl.Binary var enumType = Enum.GetUnderlyingType(type); - return enumType == typeof(int) || enumType == typeof(byte) || enumType == typeof(sbyte) + return enumType == typeof(int) || enumType == typeof(byte) || enumType == typeof(sbyte) || enumType == typeof(short) || enumType == typeof(ushort) || enumType == typeof(uint); } @@ -1763,7 +1795,7 @@ namespace Apache.Ignite.Core.Impl.Binary return TimeSpan.FromMilliseconds(ms); } - + /// <summary> /// Gets the enum values. /// </summary> @@ -1771,7 +1803,7 @@ namespace Apache.Ignite.Core.Impl.Binary { Debug.Assert(enumType != null); Debug.Assert(enumType.IsEnum); - + Dictionary<string,int> res; if (EnumValues.TryGetValue(enumType, out res)) { @@ -1792,10 +1824,10 @@ namespace Apache.Ignite.Core.Impl.Binary } EnumValues.Set(enumType, res); - + return res; } - + /// <summary> /// Gets the enum value as int. /// </summary> diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs index 608a527..63b7ee3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs @@ -48,5 +48,6 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo("Apache.Ignite, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e3e6312f7ca1ab31b8ac8408668fc85b4a76a689f7eef8553d491a594cd9ea29432b7aea12ed8f34925b2db1e01fa64f333c4e8866252a2b2d512afa5d2e06eef94fb2cdd05904f2ad70d3752fbf531bef128ecad9e699f54b2cfcd0b394b7b40e33b8c7ed45a2cd300e1b4d01c8ec7fd753683594a18f396727c304920a5e97")] #if NETCOREAPP [assembly: InternalsVisibleTo("Apache.Ignite.Core.Tests.DotNetCore, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c9b65cf83e050e9d360a840fc6632774936ea62a9a14db0aa1b991ac6b7c94030a647be9755d6b3b5883367c58cb834866b4f3acbdb5881dff677f2c046ed7cae85c9a62a7737f377813ebe4ae19f89d357e811aa577c909b82d5f02a9b05dab39da3ff92927ce0b0c4d0204961ee5d5c329274b68f19ebba129ee8e3fd0d0c1")] +[assembly: InternalsVisibleTo("Apache.Ignite.BenchmarkDotNet, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a3e0c1df4cbedbd4ed0e88808401c69b69ec12575ed1c056ac9f448e018fb29af19d236b7b03563aad66c48ab2045e72971ed098d4f65d4cdd38d65abcb39b4f84c626b22ccab2754375f0e8c97dc304fa146f0eddad5cc40a71803a8f15b0b0bb0bff0d4bf0ff6a64bb1044e0d71e6e2405b83fd4c1f7b3e2cfc2e9d50823d4")] #endif #endif