ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From voze...@apache.org
Subject [1/2] ignite git commit: IGNITE-1759: .NET: Improved GUID handling for different platforms and endians. This closes #437.
Date Mon, 08 Feb 2016 07:31:16 GMT
Repository: ignite
Updated Branches:
  refs/heads/master bad042097 -> d844e9599


IGNITE-1759: .NET: Improved GUID handling for different platforms and endians. This closes
#437.


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

Branch: refs/heads/master
Commit: f07adff7bb601971bb6c83b0459113678f387592
Parents: e88cc67
Author: Pavel Tupitsyn <ptupitsyn@gridgain.com>
Authored: Mon Feb 8 10:30:57 2016 +0300
Committer: vozerov-gridgain <vozerov@gridgain.com>
Committed: Mon Feb 8 10:30:57 2016 +0300

----------------------------------------------------------------------
 .../Binary/BinarySelfTest.cs                    |  32 ++++
 .../Impl/Binary/BinaryUtils.cs                  | 166 ++++++++++++++++---
 2 files changed, 172 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/f07adff7/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
index 44db6f7..f49a28a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
@@ -26,12 +26,15 @@ namespace Apache.Ignite.Core.Tests.Binary
     using System.Collections;
     using System.Collections.Generic;
     using System.Diagnostics.CodeAnalysis;
+    using System.IO;
     using System.Linq;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using NUnit.Framework;
+    using BinaryReader = Apache.Ignite.Core.Impl.Binary.BinaryReader;
+    using BinaryWriter = Apache.Ignite.Core.Impl.Binary.BinaryWriter;
 
     /// <summary>
     /// 
@@ -476,6 +479,35 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.AreEqual(vals, newVals);
         }
 
+        /// <summary>
+        /// Checks that both methods produce identical results.
+        /// </summary>
+        [Test]
+        public void TestGuidSlowFast()
+        {
+            var stream = new BinaryHeapStream(128);
+
+            var guid = Guid.NewGuid();
+
+            BinaryUtils.WriteGuidFast(guid, stream);
+
+            stream.Seek(0, SeekOrigin.Begin);
+            Assert.AreEqual(guid, BinaryUtils.ReadGuidFast(stream));
+
+            stream.Seek(0, SeekOrigin.Begin);
+            Assert.AreEqual(guid, BinaryUtils.ReadGuidSlow(stream));
+
+
+            stream.Seek(0, SeekOrigin.Begin);
+            BinaryUtils.WriteGuidFast(guid, stream);
+
+            stream.Seek(0, SeekOrigin.Begin);
+            Assert.AreEqual(guid, BinaryUtils.ReadGuidFast(stream));
+
+            stream.Seek(0, SeekOrigin.Begin);
+            Assert.AreEqual(guid, BinaryUtils.ReadGuidSlow(stream));
+        }
+
         /**
         * <summary>Check write of enum.</summary>
         */

http://git-wip-us.apache.org/repos/asf/ignite/blob/f07adff7/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
----------------------------------------------------------------------
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 06dec2c..9066bd1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
@@ -243,6 +243,17 @@ namespace Apache.Ignite.Core.Impl.Binary
         private static readonly CopyOnWriteConcurrentDictionary<Type, Func<BinaryReader,
bool, object>>
             ArrayReaders = new CopyOnWriteConcurrentDictionary<Type, Func<BinaryReader,
bool, object>>();
 
+        /** Flag indicating whether Guid struct is sequential in current runtime. */
+        private static readonly bool IsGuidSequential = GetIsGuidSequential();
+
+        /** Guid writer. */
+        public static readonly Action<Guid, IBinaryStream> WriteGuid = IsGuidSequential
+            ? (Action<Guid, IBinaryStream>)WriteGuidFast : WriteGuidSlow;
+
+        /** Guid reader. */
+        public static readonly Func<IBinaryStream, Guid?> ReadGuid = IsGuidSequential
+            ? (Func<IBinaryStream, Guid?>)ReadGuidFast : ReadGuidSlow;
+
         /// <summary>
         /// Default marshaller.
         /// </summary>
@@ -900,12 +911,33 @@ namespace Apache.Ignite.Core.Impl.Binary
             return vals;
         }
 
-        /**
-         * <summary>Write GUID.</summary>
-         * <param name="val">GUID.</param>
-         * <param name="stream">Stream.</param>
-         */
-        public static unsafe void WriteGuid(Guid val, IBinaryStream stream)
+        /// <summary>
+        /// Gets a value indicating whether <see cref="Guid"/> fields are stored sequentially
in memory.
+        /// </summary>
+        /// <returns></returns>
+        private static unsafe bool GetIsGuidSequential()
+        {
+            // Check that bitwise conversion returns correct result
+            var guid = Guid.NewGuid();
+
+            var bytes = guid.ToByteArray();
+
+            var bytes0 = (byte*) &guid;
+
+            for (var i = 0; i < bytes.Length; i++)
+                if (bytes[i] != bytes0[i])
+                    return false;
+
+            return true;
+        }
+
+        /// <summary>
+        /// 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>
+        /// <param name="stream">The stream.</param>
+        public static unsafe void WriteGuidFast(Guid val, IBinaryStream stream)
         {
             var jguid = new JavaGuid(val);
 
@@ -913,13 +945,47 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             stream.Write((byte*) ptr, 16);
         }
-        
-        /**
-         * <summary>Read GUID.</summary>
-         * <param name="stream">Stream.</param>
-         * <returns>GUID</returns>
-         */
-        public static unsafe Guid? ReadGuid(IBinaryStream stream)
+
+        /// <summary>
+        /// Writes a guid byte by byte.
+        /// </summary>
+        /// <param name="val">The value.</param>
+        /// <param name="stream">The stream.</param>
+        public static unsafe void WriteGuidSlow(Guid val, IBinaryStream stream)
+        {
+            var bytes = val.ToByteArray();
+            byte* jBytes = stackalloc byte[16];
+
+            jBytes[0] = bytes[6]; // c1
+            jBytes[1] = bytes[7]; // c2
+
+            jBytes[2] = bytes[4]; // b1
+            jBytes[3] = bytes[5]; // b2
+
+            jBytes[4] = bytes[0]; // a1
+            jBytes[5] = bytes[1]; // a2
+            jBytes[6] = bytes[2]; // a3
+            jBytes[7] = bytes[3]; // a4
+
+            jBytes[8] = bytes[15]; // k
+            jBytes[9] = bytes[14]; // j
+            jBytes[10] = bytes[13]; // i
+            jBytes[11] = bytes[12]; // h
+            jBytes[12] = bytes[11]; // g
+            jBytes[13] = bytes[10]; // f
+            jBytes[14] = bytes[9]; // e
+            jBytes[15] = bytes[8]; // d
+            
+            stream.Write(jBytes, 16);
+        }
+
+        /// <summary>
+        /// 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>
+        /// <returns>Guid.</returns>
+        public static unsafe Guid? ReadGuidFast(IBinaryStream stream)
         {
             JavaGuid jguid;
 
@@ -931,7 +997,43 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             return *(Guid*) (&dotnetGuid);
         }
-        
+
+        /// <summary>
+        /// Reads a guid byte by byte.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        /// <returns>Guid.</returns>
+        public static unsafe Guid? ReadGuidSlow(IBinaryStream stream)
+        {
+            byte* jBytes = stackalloc byte[16];
+
+            stream.Read(jBytes, 16);
+
+            var bytes = new byte[16];
+
+            bytes[0] = jBytes[4]; // a1
+            bytes[1] = jBytes[5]; // a2
+            bytes[2] = jBytes[6]; // a3
+            bytes[3] = jBytes[7]; // a4
+
+            bytes[4] = jBytes[2]; // b1
+            bytes[5] = jBytes[3]; // b2
+
+            bytes[6] = jBytes[0]; // c1
+            bytes[7] = jBytes[1]; // c2
+
+            bytes[8] = jBytes[15]; // d
+            bytes[9] = jBytes[14]; // e
+            bytes[10] = jBytes[13]; // f
+            bytes[11] = jBytes[12]; // g
+            bytes[12] = jBytes[11]; // h
+            bytes[13] = jBytes[10]; // i
+            bytes[14] = jBytes[9]; // j
+            bytes[15] = jBytes[8]; // k
+
+            return new Guid(bytes);
+        }
+
         /// <summary>
         /// Write GUID array.
         /// </summary>
@@ -1689,7 +1791,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         private struct GuidAccessor
         {
             public readonly ulong ABC;
-            public readonly ulong DEGHIJK;
+            public readonly ulong DEFGHIJK;
 
             /// <summary>
             /// Initializes a new instance of the <see cref="GuidAccessor"/> struct.
@@ -1699,21 +1801,28 @@ namespace Apache.Ignite.Core.Impl.Binary
             {
                 var l = val.CBA;
 
-                ABC = ((l >> 32) & 0x00000000FFFFFFFF) | ((l << 48) &
0xFFFF000000000000) |
-                      ((l << 16) & 0x0000FFFF00000000);
+                if (BitConverter.IsLittleEndian)
+                    ABC = ((l >> 32) & 0x00000000FFFFFFFF) | ((l << 48) &
0xFFFF000000000000) |
+                          ((l << 16) & 0x0000FFFF00000000);
+                else
+                    ABC = ((l << 32) & 0xFFFFFFFF00000000) | ((l >> 48) &
0x000000000000FFFF) |
+                          ((l >> 16) & 0x00000000FFFF0000);
 
-                DEGHIJK = ReverseByteOrder(val.KJIHGED);
+                // This is valid in any endianness (symmetrical)
+                DEFGHIJK = ReverseByteOrder(val.KJIHGFED);
             }
         }
 
         /// <summary>
         /// Struct with Java-style Guid memory layout.
         /// </summary>
-        [StructLayout(LayoutKind.Sequential, Pack = 0)]
+        [StructLayout(LayoutKind.Explicit)]
         private struct JavaGuid
         {
-            public readonly ulong CBA;
-            public readonly ulong KJIHGED;
+            [FieldOffset(0)] public readonly ulong CBA;
+            [FieldOffset(8)] public readonly ulong KJIHGFED;
+            [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
+            [FieldOffset(0)] public unsafe fixed byte Bytes [16];
 
             /// <summary>
             /// Initializes a new instance of the <see cref="JavaGuid"/> struct.
@@ -1721,17 +1830,22 @@ namespace Apache.Ignite.Core.Impl.Binary
             /// <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.
+                // .Net returns bytes in the following order: _a(4), _b(2), _c(2), _d, _e,
_f, _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.
+                // To be compliant with Java we rearrange them as follows: _c, _b_, a_, _k,
_j, _i, _h, _g, _f, _e, _d.
                 var accessor = *((GuidAccessor*)&val);
 
                 var l = accessor.ABC;
 
-                CBA = ((l << 32) & 0xFFFFFFFF00000000) | ((l >> 48) &
0x000000000000FFFF) |
-                      ((l >> 16) & 0x00000000FFFF0000);
+                if (BitConverter.IsLittleEndian)
+                    CBA = ((l << 32) & 0xFFFFFFFF00000000) | ((l >> 48) &
0x000000000000FFFF) |
+                          ((l >> 16) & 0x00000000FFFF0000);
+                else
+                    CBA = ((l >> 32) & 0x00000000FFFFFFFF) | ((l << 48) &
0xFFFF000000000000) |
+                          ((l << 16) & 0x0000FFFF00000000);
 
-                KJIHGED = ReverseByteOrder(accessor.DEGHIJK);
+                // This is valid in any endianness (symmetrical)
+                KJIHGFED = ReverseByteOrder(accessor.DEFGHIJK);
             }
         }
     }


Mime
View raw message