Repository: ignite
Updated Branches:
  refs/heads/ignite-1282 4e053e45d -> 1dbb37f02


IGNITE-1613: Optimized Guid read/write.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/1dbb37f0
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/1dbb37f0
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/1dbb37f0

Branch: refs/heads/ignite-1282
Commit: 1dbb37f02ac6f927e0887263d9f67eb20284a8e1
Parents: 4e053e4
Author: Pavel Tupitsyn <[email protected]>
Authored: Wed Oct 7 15:22:58 2015 +0300
Committer: vozerov-gridgain <[email protected]>
Committed: Wed Oct 7 15:22:58 2015 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Benchmarks.csproj             |   1 +
 .../Apache.Ignite.Benchmarks/Model/TestModel.cs | 111 ++++++++++++++
 .../Portable/PortableWriteBenchmark.cs          |  56 ++++++-
 .../Portable/PortableApiSelfTest.cs             |   2 +-
 .../Impl/Portable/PortableUtils.cs              | 152 ++++++++++---------
 5 files changed, 245 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbb37f0/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
 
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
index 19f2724..a85b189 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
@@ -56,6 +56,7 @@
     <Compile Include="Model\Department.cs" />
     <Compile Include="Model\Employee.cs" />
     <Compile Include="Model\Sex.cs" />
+    <Compile Include="Model\TestModel.cs" />
     <Compile Include="Portable\PortableWriteBenchmark.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Result\BenchmarkConsoleResultWriter.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbb37f0/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/TestModel.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/TestModel.cs 
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/TestModel.cs
new file mode 100644
index 0000000..1c87018
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/TestModel.cs
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Benchmarks.Model
+{
+    using System;
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Model class with all kinds of fields to test serialization.
+    /// </summary>
+    internal class TestModel : IPortableMarshalAware
+    {
+        public byte Byte { get; set; }
+        public byte[] ByteArray { get; set; }
+        public char Char { get; set; }
+        public char[] CharArray { get; set; }
+        public short Short { get; set; }
+        public short[] ShortArray { get; set; }
+        public int Int { get; set; }
+        public int[] IntArray { get; set; }
+        public long Long { get; set; }
+        public long[] LongArray { get; set; }
+        public bool Boolean { get; set; }
+        public bool[] BooleanArray { get; set; }
+        public float Float { get; set; }
+        public float[] FloatArray { get; set; }
+        public double Double { get; set; }
+        public double[] DoubleArray { get; set; }
+        public decimal Decimal { get; set; }
+        public decimal[] DecimalArray { get; set; }
+        public DateTime? Date { get; set; }
+        public DateTime?[] DateArray { get; set; }
+        public string String { get; set; }
+        public string[] StringArray { get; set; }
+        public Guid? Guid { get; set; }
+        public Guid?[] GuidArray { get; set; }
+
+        /** <inheritDoc /> */
+        public void WritePortable(IPortableWriter writer)
+        {
+            writer.WriteByte("Byte", Byte);
+            writer.WriteByteArray("ByteArray", ByteArray);
+            writer.WriteChar("Char", Char);
+            writer.WriteCharArray("CharArray", CharArray);
+            writer.WriteShort("Short", Short);
+            writer.WriteShortArray("ShortArray", ShortArray);
+            writer.WriteInt("Int", Int);
+            writer.WriteIntArray("IntArray", IntArray);
+            writer.WriteLong("Long", Long);
+            writer.WriteLongArray("LongArray", LongArray);
+            writer.WriteBoolean("Boolean", Boolean);
+            writer.WriteBooleanArray("BooleanArray", BooleanArray);
+            writer.WriteFloat("Float", Float);
+            writer.WriteFloatArray("FloatArray", FloatArray);
+            writer.WriteDouble("Double", Double);
+            writer.WriteDoubleArray("DoubleArray", DoubleArray);
+            writer.WriteDecimal("Decimal", Decimal);
+            writer.WriteDecimalArray("DecimalArray", DecimalArray);
+            writer.WriteDate("Date", Date);
+            writer.WriteDateArray("DateArray", DateArray);
+            writer.WriteString("String", String);
+            writer.WriteStringArray("StringArray", StringArray);
+            writer.WriteGuid("Guid", Guid);
+            writer.WriteGuidArray("GuidArray", GuidArray);
+        }
+
+        /** <inheritDoc /> */
+        public void ReadPortable(IPortableReader reader)
+        {
+            Byte = reader.ReadByte("Byte");
+            ByteArray = reader.ReadByteArray("ByteArray");
+            Char = reader.ReadChar("Char");
+            CharArray = reader.ReadCharArray("CharArray");
+            Short = reader.ReadShort("Short");
+            ShortArray = reader.ReadShortArray("ShortArray");
+            Int = reader.ReadInt("Int");
+            IntArray = reader.ReadIntArray("IntArray");
+            Long = reader.ReadLong("Long");
+            LongArray = reader.ReadLongArray("LongArray");
+            Boolean = reader.ReadBoolean("Boolean");
+            BooleanArray = reader.ReadBooleanArray("BooleanArray");
+            Float = reader.ReadFloat("Float");
+            FloatArray = reader.ReadFloatArray("FloatArray");
+            Double = reader.ReadDouble("Double");
+            DoubleArray = reader.ReadDoubleArray("DoubleArray");
+            Decimal = reader.ReadDecimal("Decimal");
+            DecimalArray = reader.ReadDecimalArray("DecimalArray");
+            Date = reader.ReadDate("Date");
+            DateArray = reader.ReadDateArray("DateArray");
+            String = reader.ReadString("String");
+            StringArray = reader.ReadStringArray("StringArray");
+            Guid = reader.ReadGuid("Guid");
+            GuidArray = reader.ReadGuidArray("GuidArray");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbb37f0/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
index 5638195..7ac27ea 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
@@ -17,7 +17,9 @@
 
 namespace Apache.Ignite.Benchmarks.Portable
 {
+    using System;
     using System.Collections.Generic;
+    using System.Linq;
     using Apache.Ignite.Benchmarks.Model;
     using Apache.Ignite.Core.Impl.Memory;
     using Apache.Ignite.Core.Impl.Portable;
@@ -34,9 +36,38 @@ namespace Apache.Ignite.Benchmarks.Portable
         /** Memory manager. */
         private readonly PlatformMemoryManager _memMgr = new 
PlatformMemoryManager(1024);
 
-        /** Pre-allocated addess. */
+        /** Pre-allocated address. */
         private readonly Address _address = BenchmarkUtils.GetRandomAddress();
 
+        /** Pre-allocated model. */
+        private readonly TestModel _model = new TestModel
+        {
+            Byte = 5,
+            Boolean = true,
+            BooleanArray = new[] {true, false, false, false, true, true},
+            ByteArray = new byte[] {128, 1, 2, 3, 5, 6, 8, 9, 14},
+            Char = 'h',
+            CharArray = new[] {'b', 'n', 'm', 'q', 'w', 'e', 'r', 't', 'y'},
+            Date = DateTime.Now,
+            DateArray = Enumerable.Range(1, 15).Select(x => (DateTime?) 
DateTime.Now.AddDays(x)).ToArray(),
+            Decimal = decimal.MinValue,
+            DecimalArray = new[] {1.1M, decimal.MinValue, decimal.MaxValue, 
decimal.MinusOne, decimal.One},
+            Double = double.MaxValue/2,
+            DoubleArray = new[] {double.MaxValue, double.MinValue, 
double.Epsilon, double.NegativeInfinity},
+            Float = 98,
+            FloatArray = new[] {float.MinValue, float.MaxValue, 10F, 36F},
+            Guid = Guid.NewGuid(),
+            GuidArray = Enumerable.Range(1, 9).Select(x => (Guid?) 
Guid.NewGuid()).ToArray(),
+            Int = -90,
+            IntArray = new[] {128, 1, 2, 3, 5, 6, 8, 9, 14},
+            Long = long.MinValue,
+            LongArray = Enumerable.Range(1, 12).Select(x => (long) 
x).ToArray(),
+            Short = 67,
+            ShortArray = Enumerable.Range(100, 12).Select(x => (short) 
x).ToArray(),
+            String = "String value test 123",
+            StringArray = Enumerable.Range(1, 13).Select(x => 
Guid.NewGuid().ToString()).ToArray()
+        };
+
         /// <summary>
         /// Initializes a new instance of the <see 
cref="PortableWriteBenchmark"/> class.
         /// </summary>
@@ -46,7 +77,8 @@ namespace Apache.Ignite.Benchmarks.Portable
             {
                 TypeConfigurations = new List<PortableTypeConfiguration>
                 {
-                    new PortableTypeConfiguration(typeof (Address)) 
{MetadataEnabled = true}
+                    new PortableTypeConfiguration(typeof (Address)) 
{MetadataEnabled = true},
+                    new PortableTypeConfiguration(typeof (TestModel)) 
{MetadataEnabled = false}
                 }
             });
         }
@@ -58,6 +90,7 @@ namespace Apache.Ignite.Benchmarks.Portable
         protected override void 
GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
         {
             descs.Add(BenchmarkOperationDescriptor.Create("WriteAddress", 
WriteAddress, 1));
+            descs.Add(BenchmarkOperationDescriptor.Create("WriteTestModel", 
WriteTestModel, 1));
         }
 
         /// <summary>
@@ -79,5 +112,24 @@ namespace Apache.Ignite.Benchmarks.Portable
                 mem.Release();
             }
         }
+        /// <summary>
+        /// Write address.
+        /// </summary>
+        /// <param name="state">State.</param>
+        private void WriteTestModel(BenchmarkState state)
+        {
+            var mem = _memMgr.Allocate();
+
+            try
+            {
+                var stream = mem.GetStream();
+
+                _marsh.StartMarshal(stream).Write(_model);
+            }
+            finally
+            {
+                mem.Release();
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbb37f0/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs
index b9a9936..8c5bb0b 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs
@@ -1381,7 +1381,7 @@ namespace Apache.Ignite.Core.Tests.Portable
 
             Assert.AreEqual(IdMapper.TestTypeId, 
_grid.GetPortables().GetTypeId(IdMapper.TestTypeName));
             
-            Assert.AreEqual(PortableUtils.StringHashCode("someTypeName"), 
_grid.GetPortables().GetTypeId("someTypeName"));
+            Assert.AreEqual(PortableUtils.GetStringHashCode("someTypeName"), 
_grid.GetPortables().GetTypeId("someTypeName"));
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbb37f0/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
index fb0b195..d02fcf1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
@@ -25,6 +25,7 @@ namespace Apache.Ignite.Core.Impl.Portable
     using System.Diagnostics.CodeAnalysis;
     using System.IO;
     using System.Reflection;
+    using System.Runtime.InteropServices;
     using System.Runtime.Serialization.Formatters.Binary;
     using System.Text;
     using Apache.Ignite.Core.Impl.Common;
@@ -992,29 +993,13 @@ namespace Apache.Ignite.Core.Impl.Portable
          */
         public static unsafe void WriteGuid(Guid val, IPortableStream stream)
         {
-            byte[] bytes = val.ToByteArray();
+            var jguid = new JavaGuid(val);
 
-            // .Net returns bytes in the following order: _a(4), _b(2), _c(2), 
_d, _e, _g, _h, _i, _j, _k.
-            // And _a, _b and _c are always in little endian format 
irrespective of system configuration.
-            // To be compliant with Java we rearrange them as follows: _c, 
_b_, a_, _k, _j, _i, _h, _g, _e, _d.
-            fixed (byte* bytes0 = bytes)
-            {
-                stream.Write(bytes0 + 6, 2); // _c
-                stream.Write(bytes0 + 4, 2); // _a
-                stream.Write(bytes0, 4);     // _a
-            }
-
-            stream.WriteByte(bytes[15]); // _k
-            stream.WriteByte(bytes[14]); // _j
-            stream.WriteByte(bytes[13]); // _i
-            stream.WriteByte(bytes[12]); // _h
+            var ptr = &jguid;
 
-            stream.WriteByte(bytes[11]); // _g
-            stream.WriteByte(bytes[10]); // _f
-            stream.WriteByte(bytes[9]);  // _e
-            stream.WriteByte(bytes[8]);  // _d
+            stream.Write((byte*) ptr, 16);
         }
-
+        
         /**
          * <summary>Read GUID.</summary>
          * <param name="stream">Stream.</param>
@@ -1022,61 +1007,15 @@ namespace Apache.Ignite.Core.Impl.Portable
          */
         public static unsafe Guid? ReadGuid(IPortableStream stream)
         {
-            byte[] bytes = new byte[16];
-
-            // Perform conversion opposite to what write does.
-            fixed (byte* bytes0 = bytes)
-            {
-                stream.Read(bytes0 + 6, 2);      // _c
-                stream.Read(bytes0 + 4, 2);      // _b
-                stream.Read(bytes0, 4);          // _a
-            }
-
-            bytes[15] = stream.ReadByte();  // _k
-            bytes[14] = stream.ReadByte();  // _j
-            bytes[13] = stream.ReadByte();  // _i
-            bytes[12] = stream.ReadByte();  // _h
-
-            bytes[11] = stream.ReadByte();  // _g
-            bytes[10] = stream.ReadByte();  // _f
-            bytes[9] = stream.ReadByte();   // _e
-            bytes[8] = stream.ReadByte();   // _d
-
-            return new Guid(bytes);
-        }
+            JavaGuid jguid;
 
-        /**
-         * <summary>Read GUID.</summary>
-         * <param name="data">Data array.</param>
-         * <param name="pos">Position.</param>
-         * <returns>GUID</returns>
-         */
-        public static Guid ReadGuid(byte[] data, int pos) {
-            byte[] bytes = new byte[16];
+            var ptr = (byte*) &jguid;
 
-            // Perform conversion opposite to what write does.
-            bytes[6] = data[pos];  // _c
-            bytes[7] = data[pos + 1];
+            stream.Read(ptr, 16);
 
-            bytes[4] = data[pos + 2];  // _b
-            bytes[5] = data[pos + 3];
+            var dotnetGuid = new GuidAccessor(jguid);
 
-            bytes[0] = data[pos + 4];  // _a
-            bytes[1] = data[pos + 5];
-            bytes[2] = data[pos + 6];
-            bytes[3] = data[pos + 7];
-
-            bytes[15] = data[pos + 8];  // _k
-            bytes[14] = data[pos + 9];  // _j
-            bytes[13] = data[pos + 10];  // _i
-            bytes[12] = data[pos + 11];  // _h
-
-            bytes[11] = data[pos + 12];  // _g
-            bytes[10] = data[pos + 13];  // _f
-            bytes[9] = data[pos + 14];   // _e
-            bytes[8] = data[pos + 15];   // _d
-
-            return new Guid(bytes);
+            return *(Guid*) (&dotnetGuid);
         }
 
         /// <summary>
@@ -1590,7 +1529,7 @@ namespace Apache.Ignite.Core.Impl.Portable
          * <param name="val">Value.</param>
          * <returns>Hash code.</returns>
          */
-        public static int StringHashCode(string val)
+        public static int GetStringHashCode(string val)
         {
             if (val == null)
                 return 0;
@@ -1761,7 +1700,7 @@ namespace Apache.Ignite.Core.Impl.Portable
             }
 
             if (id == 0)
-                id = StringHashCode(typeName);
+                id = GetStringHashCode(typeName);
 
             return id;
         }
@@ -1797,7 +1736,7 @@ namespace Apache.Ignite.Core.Impl.Portable
             }
 
             if (id == 0)
-                id = StringHashCode(fieldName);
+                id = GetStringHashCode(fieldName);
 
             if (id == 0)
                 throw new PortableException("Field ID is zero (please provide 
ID mapper or change field name) " + 
@@ -2183,5 +2122,70 @@ namespace Apache.Ignite.Core.Impl.Portable
 
             throw new PortableException("Failed to find class: " + typeName);
         }
+
+        /// <summary>
+        /// Reverses the byte order of an unsigned long.
+        /// </summary>
+        private static ulong ReverseByteOrder(ulong l)
+        {
+            // Fastest way would be to use bswap processor instruction.
+            return ((l >> 56) & 0x00000000000000FF) | ((l >> 40) & 
0x000000000000FF00) |
+                   ((l >> 24) & 0x0000000000FF0000) | ((l >> 8) & 
0x00000000FF000000) |
+                   ((l << 8) & 0x000000FF00000000) | ((l << 24) & 
0x0000FF0000000000) |
+                   ((l << 40) & 0x00FF000000000000) | ((l << 56) & 
0xFF00000000000000);
+        }
+
+        /// <summary>
+        /// Struct with .Net-style Guid memory layout.
+        /// </summary>
+        [StructLayout(LayoutKind.Sequential)]
+        private struct GuidAccessor
+        {
+            public readonly ulong ABC;
+            public readonly ulong DEGHIJK;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="GuidAccessor"/> 
struct.
+            /// </summary>
+            /// <param name="val">The value.</param>
+            public GuidAccessor(JavaGuid val)
+            {
+                var l = val.CBA;
+
+                ABC = ((l >> 32) & 0x00000000FFFFFFFF) | ((l << 48) & 
0xFFFF000000000000) |
+                      ((l << 16) & 0x0000FFFF00000000);
+
+                DEGHIJK = ReverseByteOrder(val.KJIHGED);
+            }
+        }
+
+        /// <summary>
+        /// Struct with Java-style Guid memory layout.
+        /// </summary>
+        [StructLayout(LayoutKind.Sequential)]
+        private struct JavaGuid
+        {
+            public readonly ulong CBA;
+            public readonly ulong KJIHGED;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="JavaGuid"/> 
struct.
+            /// </summary>
+            /// <param name="val">The value.</param>
+            public unsafe JavaGuid(Guid val)
+            {
+                // .Net returns bytes in the following order: _a(4), _b(2), 
_c(2), _d, _e, _g, _h, _i, _j, _k.
+                // And _a, _b and _c are always in little endian format 
irrespective of system configuration.
+                // To be compliant with Java we rearrange them as follows: _c, 
_b_, a_, _k, _j, _i, _h, _g, _e, _d.
+                var accessor = *((GuidAccessor*)&val);
+
+                var l = accessor.ABC;
+
+                CBA = ((l << 32) & 0xFFFFFFFF00000000) | ((l >> 48) & 
0x000000000000FFFF) |
+                      ((l >> 16) & 0x00000000FFFF0000);
+
+                KJIHGED = ReverseByteOrder(accessor.DEGHIJK);
+            }
+        }
     }
 }

Reply via email to