Repository: ignite Updated Branches: refs/heads/master 69f526a48 -> cadc61fa8
IGNITE-1957: .NET: Binary marshaller now use handles for arrays, collections and dictionaries. This closes #302. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/cadc61fa Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/cadc61fa Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/cadc61fa Branch: refs/heads/master Commit: cadc61fa89df00d0c632328d0678e2b19d525e42 Parents: 69f526a Author: Pavel Tupitsyn <[email protected]> Authored: Mon Mar 21 15:23:47 2016 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Mon Mar 21 15:23:47 2016 +0300 ---------------------------------------------------------------------- .../Binary/BinarySelfTest.cs | 113 ++++++++++++++++ .../Apache.Ignite.Core.csproj | 1 + .../Impl/Binary/BinaryHandleDictionary.cs | 32 +++-- .../Impl/Binary/BinaryReader.cs | 61 ++++----- .../Impl/Binary/BinaryReaderHandleDictionary.cs | 2 +- .../Impl/Binary/BinarySystemHandlers.cs | 132 ++++++++++--------- .../Impl/Binary/BinaryUtils.cs | 12 ++ .../Impl/Binary/BinaryWriter.cs | 24 ++-- .../Impl/Binary/ReferenceEqualityComparer.cs | 45 +++++++ .../Impl/Common/DelegateConverter.cs | 4 +- 10 files changed, 301 insertions(+), 125 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/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 0fcb792..41e327b 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs @@ -29,10 +29,12 @@ namespace Apache.Ignite.Core.Tests.Binary using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; + using System.Reflection; using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Common; using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Binary.IO; + using Apache.Ignite.Core.Impl.Common; using NUnit.Framework; using BinaryReader = Apache.Ignite.Core.Impl.Binary.BinaryReader; using BinaryWriter = Apache.Ignite.Core.Impl.Binary.BinaryWriter; @@ -1256,6 +1258,87 @@ namespace Apache.Ignite.Core.Tests.Binary Assert.IsTrue(newOuter.RawInner == newOuter.RawInner.Outer.RawInner); } + [Test] + public void TestHandlesCollections() + { + var marsh = new Marshaller(new BinaryConfiguration + { + TypeConfigurations = new[] + { + new BinaryTypeConfiguration(typeof (HandleCollection)) + } + }); + + // Collection in collection dependency loop + var collection = new ArrayList {1, 2}; + collection.Add(collection); + + var collectionRaw = new ArrayList(collection); + collectionRaw.Add(collectionRaw); + + var collectionObj = new ArrayList(collectionRaw); + collectionObj.Add(collectionObj); + + var dict = new Hashtable { { 1, 1 }, { 2, 2 } }; + dict.Add(3, dict); + + var arr = collectionObj.ToArray(); + arr[1] = arr; + + object entry = new DictionaryEntry(1, 2); + var dictionaryEntryValSetter = DelegateConverter.CompileFieldSetter(typeof (DictionaryEntry) + .GetField("_value", BindingFlags.Instance | BindingFlags.NonPublic)); + dictionaryEntryValSetter(entry, entry); // modify boxed copy to create reference loop + + var data = new HandleCollection + { + Collection = collection, + CollectionRaw = collectionRaw, + Object = collectionObj, + Dictionary = dict, + Array = arr, + DictionaryEntry = (DictionaryEntry) entry + }; + + var res = marsh.Unmarshal<HandleCollection>(marsh.Marshal(data)); + + var resCollection = (ArrayList) res.Collection; + Assert.AreEqual(collection[0], resCollection[0]); + Assert.AreEqual(collection[1], resCollection[1]); + Assert.AreSame(resCollection, resCollection[2]); + + var resCollectionRaw = (ArrayList) res.CollectionRaw; + Assert.AreEqual(collectionRaw[0], resCollectionRaw[0]); + Assert.AreEqual(collectionRaw[1], resCollectionRaw[1]); + Assert.AreSame(resCollection, resCollectionRaw[2]); + Assert.AreSame(resCollectionRaw, resCollectionRaw[3]); + + var resCollectionObj = (ArrayList) res.Object; + Assert.AreEqual(collectionObj[0], resCollectionObj[0]); + Assert.AreEqual(collectionObj[1], resCollectionObj[1]); + Assert.AreSame(resCollection, resCollectionObj[2]); + Assert.AreSame(resCollectionRaw, resCollectionObj[3]); + Assert.AreSame(resCollectionObj, resCollectionObj[4]); + + var resDict = (Hashtable) res.Dictionary; + Assert.AreEqual(1, resDict[1]); + Assert.AreEqual(2, resDict[2]); + Assert.AreSame(resDict, resDict[3]); + + var resArr = res.Array; + Assert.AreEqual(arr[0], resArr[0]); + Assert.AreSame(resArr, resArr[1]); + Assert.AreSame(resCollection, resArr[2]); + Assert.AreSame(resCollectionRaw, resArr[3]); + Assert.AreSame(resCollectionObj, resArr[4]); + + var resEntry = res.DictionaryEntry; + var innerEntry = (DictionaryEntry) resEntry.Value; + Assert.AreEqual(1, resEntry.Key); + Assert.AreEqual(1, innerEntry.Key); + Assert.IsTrue(ReferenceEquals(innerEntry.Value, ((DictionaryEntry) innerEntry.Value).Value)); + } + /// /// <summary>Test KeepSerialized property</summary> /// @@ -2186,6 +2269,36 @@ namespace Apache.Ignite.Core.Tests.Binary } } + public class HandleCollection : IBinarizable + { + public ICollection Collection { get; set; } + public IDictionary Dictionary { get; set; } + public DictionaryEntry DictionaryEntry { get; set; } + public ICollection CollectionRaw { get; set; } + public object Object { get; set; } + public object[] Array { get; set; } + + public void WriteBinary(IBinaryWriter writer) + { + writer.WriteCollection("col", Collection); + writer.WriteDictionary("dict", Dictionary); + writer.WriteObject("dictEntry", DictionaryEntry); + writer.WriteObject("obj", Object); + writer.WriteArray("arr", Array); + writer.GetRawWriter().WriteCollection(CollectionRaw); + } + + public void ReadBinary(IBinaryReader reader) + { + Collection = reader.ReadCollection("col"); + Dictionary = reader.ReadDictionary("dict"); + DictionaryEntry = reader.ReadObject<DictionaryEntry>("dictEntry"); + Object = reader.ReadObject<object>("obj"); + Array = reader.ReadArray<object>("arr"); + CollectionRaw = reader.GetRawReader().ReadCollection(); + } + } + public class PropertyType { public int Field1; http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj index dedf084..bfedce9 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -194,6 +194,7 @@ <Compile Include="IIgnite.cs" /> <Compile Include="Impl\Binary\BinaryEnum.cs" /> <Compile Include="Impl\Binary\BinaryObjectSchemaSerializer.cs" /> + <Compile Include="Impl\Binary\ReferenceEqualityComparer.cs" /> <Compile Include="Impl\Binary\JavaTypes.cs" /> <Compile Include="Impl\Cache\CacheAffinityImpl.cs" /> <Compile Include="Impl\Cache\CacheEntry.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHandleDictionary.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHandleDictionary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHandleDictionary.cs index 3f39bcc..08e17ca 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHandleDictionary.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHandleDictionary.cs @@ -50,22 +50,28 @@ namespace Apache.Ignite.Core.Impl.Binary /** Third value. */ private TV _val3; + /** Comparer. */ + private readonly IEqualityComparer<TK> _comparer; + /// <summary> /// Constructor with initial key-value pair. /// </summary> /// <param name="key">Key.</param> /// <param name="val">Value.</param> + /// <param name="comparer">The comparer.</param> [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors"), SuppressMessage("ReSharper", "DoNotCallOverridableMethodsInConstructor")] - public BinaryHandleDictionary(TK key, TV val) + public BinaryHandleDictionary(TK key, TV val, IEqualityComparer<TK> comparer) { - Debug.Assert(!Equals(key, EmptyKey)); - _key1 = key; _val1 = val; _key2 = EmptyKey; _key3 = EmptyKey; + + _comparer = comparer ?? EqualityComparer<TK>.Default; + + Debug.Assert(!_comparer.Equals(key, EmptyKey)); } /// <summary> @@ -75,9 +81,9 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="val">Value.</param> public void Add(TK key, TV val) { - Debug.Assert(!Equals(key, EmptyKey)); + Debug.Assert(!_comparer.Equals(key, EmptyKey)); - if (Equals(_key2, EmptyKey)) + if (_comparer.Equals(_key2, EmptyKey)) { _key2 = key; _val2 = val; @@ -85,7 +91,7 @@ namespace Apache.Ignite.Core.Impl.Binary return; } - if (Equals(_key3, EmptyKey)) + if (_comparer.Equals(_key3, EmptyKey)) { _key3 = key; _val3 = val; @@ -94,7 +100,7 @@ namespace Apache.Ignite.Core.Impl.Binary } if (_dict == null) - _dict = new Dictionary<TK, TV>(InitialSize); + _dict = new Dictionary<TK, TV>(InitialSize, _comparer); _dict[key] = val; } @@ -107,23 +113,23 @@ namespace Apache.Ignite.Core.Impl.Binary /// <returns>True if key was found.</returns> public bool TryGetValue(TK key, out TV val) { - Debug.Assert(!Equals(key, EmptyKey)); + Debug.Assert(!_comparer.Equals(key, EmptyKey)); - if (Equals(key, _key1)) + if (_comparer.Equals(key, _key1)) { val = _val1; return true; } - if (Equals(key, _key2)) + if (_comparer.Equals(key, _key2)) { val = _val2; return true; } - if (Equals(key, _key3)) + if (_comparer.Equals(key, _key3)) { val = _val3; @@ -167,10 +173,10 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="val">Value.</param> private void AddIfAbsent(TK key, TV val) { - if (Equals(key, EmptyKey)) + if (_comparer.Equals(key, EmptyKey)) return; - if (Equals(key, _key1) || Equals(key, _key2) || Equals(key, _key3)) + if (_comparer.Equals(key, _key1) || _comparer.Equals(key, _key2) || _comparer.Equals(key, _key3)) return; if (_dict == null || !_dict.ContainsKey(key)) http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs ---------------------------------------------------------------------- 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 21c1642..1403410 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs @@ -874,7 +874,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> /// <param name="pos">Position.</param> /// <param name="obj">Object.</param> - private void AddHandle(int pos, object obj) + internal void AddHandle(int pos, object obj) { if (_hnds == null) _hnds = new BinaryReaderHandleDictionary(pos, obj); @@ -905,35 +905,6 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Determines whether header at current position is HDR_NULL. - /// </summary> - private bool IsNotNullHeader(byte expHdr) - { - var hdr = ReadByte(); - - if (hdr == BinaryUtils.HdrNull) - return false; - - if (expHdr != hdr) - throw new BinaryObjectException(string.Format("Invalid header on deserialization. " + - "Expected: {0} but was: {1}", expHdr, hdr)); - - return true; - } - - /// <summary> - /// Seeks the field by name, reads header and returns true if field is present and header is not null. - /// </summary> - private bool SeekField(string fieldName, byte expHdr) - { - if (!SeekField(fieldName)) - return false; - - // Expected read order, no need to seek. - return IsNotNullHeader(expHdr); - } - - /// <summary> /// Seeks the field by name. /// </summary> private bool SeekField(string fieldName) @@ -971,7 +942,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> private T ReadField<T>(string fieldName, Func<IBinaryStream, T> readFunc, byte expHdr) { - return SeekField(fieldName, expHdr) ? readFunc(Stream) : default(T); + return SeekField(fieldName) ? Read(readFunc, expHdr) : default(T); } /// <summary> @@ -979,7 +950,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> private T ReadField<T>(string fieldName, Func<BinaryReader, T> readFunc, byte expHdr) { - return SeekField(fieldName, expHdr) ? readFunc(this) : default(T); + return SeekField(fieldName) ? Read(readFunc, expHdr) : default(T); } /// <summary> @@ -987,7 +958,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> private T ReadField<T>(string fieldName, Func<T> readFunc, byte expHdr) { - return SeekField(fieldName, expHdr) ? readFunc() : default(T); + return SeekField(fieldName) ? Read(readFunc, expHdr) : default(T); } /// <summary> @@ -995,7 +966,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> private T Read<T>(Func<BinaryReader, T> readFunc, byte expHdr) { - return IsNotNullHeader(expHdr) ? readFunc(this) : default(T); + return Read(() => readFunc(this), expHdr); } /// <summary> @@ -1003,7 +974,27 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> private T Read<T>(Func<IBinaryStream, T> readFunc, byte expHdr) { - return IsNotNullHeader(expHdr) ? readFunc(Stream) : default(T); + return Read(() => readFunc(Stream), expHdr); + } + + /// <summary> + /// Reads header and invokes specified func if the header is not null. + /// </summary> + private T Read<T>(Func<T> readFunc, byte expHdr) + { + var hdr = ReadByte(); + + if (hdr == BinaryUtils.HdrNull) + return default(T); + + if (hdr == BinaryUtils.HdrHnd) + return ReadHandleObject<T>(Stream.Position - 1); + + if (expHdr != hdr) + throw new BinaryObjectException(string.Format("Invalid header on deserialization. " + + "Expected: {0} but was: {1}", expHdr, hdr)); + + return readFunc(); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs index c145e7f..8a9a466 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderHandleDictionary.cs @@ -28,7 +28,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="key">Key.</param> /// <param name="val">Value.</param> public BinaryReaderHandleDictionary(int key, object val) - : base(key, val) + : base(key, val, null) { // No-op. } http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs ---------------------------------------------------------------------- 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 36e324d..89925dd 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs @@ -26,24 +26,14 @@ namespace Apache.Ignite.Core.Impl.Binary using Apache.Ignite.Core.Impl.Binary.IO; using Apache.Ignite.Core.Impl.Common; - /// <summary> - /// Write delegate. - /// </summary> - /// <param name="writer">Write context.</param> - /// <param name="obj">Object to write.</param> - internal delegate void BinarySystemWriteDelegate(BinaryWriter writer, object obj); - /** * <summary>Collection of predefined handlers for various system types.</summary> */ internal static class BinarySystemHandlers { /** Write handlers. */ - private static volatile Dictionary<Type, BinarySystemWriteDelegate> _writeHandlers = - new Dictionary<Type, BinarySystemWriteDelegate>(); - - /** Mutex for write handlers update. */ - private static readonly object WriteHandlersMux = new object(); + private static readonly CopyOnWriteConcurrentDictionary<Type, BinarySystemWriteHandler> WriteHandlers = + new CopyOnWriteConcurrentDictionary<Type, BinarySystemWriteHandler>(); /** Read handlers. */ private static readonly IBinarySystemReader[] ReadHandlers = new IBinarySystemReader[255]; @@ -171,32 +161,30 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> /// <param name="type"></param> /// <returns></returns> - public static BinarySystemWriteDelegate GetWriteHandler(Type type) + public static BinarySystemWriteHandler GetWriteHandler(Type type) { - BinarySystemWriteDelegate res; - - var writeHandlers0 = _writeHandlers; - - // Have we ever met this type? - if (writeHandlers0 != null && writeHandlers0.TryGetValue(type, out res)) - return res; - - // Determine write handler for type and add it. - res = FindWriteHandler(type); + return WriteHandlers.GetOrAdd(type, t => + { + bool supportsHandles; - if (res != null) - AddWriteHandler(type, res); + var handler = FindWriteHandler(t, out supportsHandles); - return res; + return handler == null ? null : new BinarySystemWriteHandler(handler, supportsHandles); + }); } /// <summary> /// Find write handler for type. /// </summary> /// <param name="type">Type.</param> - /// <returns>Write handler or NULL.</returns> - private static BinarySystemWriteDelegate FindWriteHandler(Type type) + /// <param name="supportsHandles">Flag indicating whether returned delegate supports handles.</param> + /// <returns> + /// Write handler or NULL. + /// </returns> + private static Action<BinaryWriter, object> FindWriteHandler(Type type, out bool supportsHandles) { + supportsHandles = false; + // 1. Well-known types. if (type == typeof(string)) return WriteString; @@ -210,9 +198,15 @@ namespace Apache.Ignite.Core.Impl.Binary return WriteBinary; if (type == typeof (BinaryEnum)) return WriteBinaryEnum; + if (type.IsEnum) + return WriteEnum; + + // All types below can be written as handles. + supportsHandles = true; + if (type == typeof (ArrayList)) return WriteArrayList; - if (type == typeof(Hashtable)) + if (type == typeof (Hashtable)) return WriteHashtable; if (type.IsArray) @@ -258,14 +252,11 @@ namespace Apache.Ignite.Core.Impl.Binary return WriteEnumArray; // Object array. - if (elemType == typeof (object) || elemType == typeof(IBinaryObject) || elemType == typeof(BinaryObject)) + if (elemType == typeof (object) || elemType == typeof (IBinaryObject) || + elemType == typeof (BinaryObject)) return WriteArray; } - if (type.IsEnum) - // We know how to write enums. - return WriteEnum; - if (type.IsSerializable) return WriteSerializable; @@ -294,36 +285,6 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Add write handler for type. - /// </summary> - /// <param name="type"></param> - /// <param name="handler"></param> - private static void AddWriteHandler(Type type, BinarySystemWriteDelegate handler) - { - lock (WriteHandlersMux) - { - if (_writeHandlers == null) - { - Dictionary<Type, BinarySystemWriteDelegate> writeHandlers0 = - new Dictionary<Type, BinarySystemWriteDelegate>(); - - writeHandlers0[type] = handler; - - _writeHandlers = writeHandlers0; - } - else if (!_writeHandlers.ContainsKey(type)) - { - Dictionary<Type, BinarySystemWriteDelegate> writeHandlers0 = - new Dictionary<Type, BinarySystemWriteDelegate>(_writeHandlers); - - writeHandlers0[type] = handler; - - _writeHandlers = writeHandlers0; - } - } - } - - /// <summary> /// Reads an object of predefined type. /// </summary> public static bool TryReadSystemType<T>(byte typeId, BinaryReader ctx, out T res) @@ -818,4 +779,47 @@ namespace Apache.Ignite.Core.Impl.Binary } } } + + /// <summary> + /// Write delegate + handles flag. + /// </summary> + internal class BinarySystemWriteHandler + { + /** */ + private readonly Action<BinaryWriter, object> _writeAction; + + /** */ + private readonly bool _supportsHandles; + + /// <summary> + /// Initializes a new instance of the <see cref="BinarySystemWriteHandler"/> class. + /// </summary> + /// <param name="writeAction">The write action.</param> + /// <param name="supportsHandles">Handles flag.</param> + public BinarySystemWriteHandler(Action<BinaryWriter, object> writeAction, bool supportsHandles = false) + { + Debug.Assert(writeAction != null); + + _writeAction = writeAction; + _supportsHandles = supportsHandles; + } + + /// <summary> + /// Writes object to a specified writer. + /// </summary> + /// <param name="writer">The writer.</param> + /// <param name="obj">The object.</param> + public void Write(BinaryWriter writer, object obj) + { + _writeAction(writer, obj); + } + + /// <summary> + /// Gets a value indicating whether this handler supports handles. + /// </summary> + public bool SupportsHandles + { + get { return _supportsHandles; } + } + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/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 b73a6c4..4142d60 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs @@ -1123,6 +1123,8 @@ namespace Apache.Ignite.Core.Impl.Binary { var stream = ctx.Stream; + var pos = stream.Position; + if (typed) stream.ReadInt(); @@ -1130,6 +1132,8 @@ namespace Apache.Ignite.Core.Impl.Binary var vals = new T[len]; + ctx.AddHandle(pos - 1, vals); + for (int i = 0; i < len; i++) vals[i] = ctx.Deserialize<T>(); @@ -1209,6 +1213,8 @@ namespace Apache.Ignite.Core.Impl.Binary { IBinaryStream stream = ctx.Stream; + int pos = stream.Position; + int len = stream.ReadInt(); byte colType = ctx.Stream.ReadByte(); @@ -1225,6 +1231,8 @@ namespace Apache.Ignite.Core.Impl.Binary else res = factory.Invoke(len); + ctx.AddHandle(pos - 1, res); + if (adder == null) adder = (col, elem) => ((ArrayList) col).Add(elem); @@ -1286,6 +1294,8 @@ namespace Apache.Ignite.Core.Impl.Binary { IBinaryStream stream = ctx.Stream; + int pos = stream.Position; + int len = stream.ReadInt(); // Skip dictionary type as we can do nothing with it here. @@ -1293,6 +1303,8 @@ namespace Apache.Ignite.Core.Impl.Binary var res = factory == null ? new Hashtable(len) : factory.Invoke(len); + ctx.AddHandle(pos - 1, res); + for (int i = 0; i < len; i++) { object key = ctx.Deserialize<object>(); http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs index 47bc2b6..1ac98c4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs @@ -907,13 +907,7 @@ namespace Apache.Ignite.Core.Impl.Binary { WriteFieldId(fieldName, BinaryUtils.TypeArray); - if (val == null) - WriteNullField(); - else - { - _stream.WriteByte(BinaryUtils.TypeArray); - BinaryUtils.WriteArray(val, this); - } + WriteArray(val); } /// <summary> @@ -936,6 +930,9 @@ namespace Apache.Ignite.Core.Impl.Binary WriteNullRawField(); else { + if (WriteHandle(_stream.Position, val)) + return; + _stream.WriteByte(BinaryUtils.TypeArray); BinaryUtils.WriteArray(val, this); } @@ -963,6 +960,9 @@ namespace Apache.Ignite.Core.Impl.Binary WriteNullField(); else { + if (WriteHandle(_stream.Position, val)) + return; + WriteByte(BinaryUtils.TypeCollection); BinaryUtils.WriteCollection(val, this); } @@ -990,6 +990,9 @@ namespace Apache.Ignite.Core.Impl.Binary WriteNullField(); else { + if (WriteHandle(_stream.Position, val)) + return; + WriteByte(BinaryUtils.TypeDictionary); BinaryUtils.WriteDictionary(val, this); } @@ -1194,7 +1197,10 @@ namespace Apache.Ignite.Core.Impl.Binary if (handler == null) // We did our best, object cannot be marshalled. throw new BinaryObjectException("Unsupported object type [type=" + type + ", object=" + obj + ']'); - handler(this, obj); + if (handler.SupportsHandles && WriteHandle(_stream.Position, obj)) + return; + + handler.Write(this, obj); } } @@ -1326,7 +1332,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (_hnds == null) { // Cache absolute handle position. - _hnds = new BinaryHandleDictionary<object, long>(obj, pos); + _hnds = new BinaryHandleDictionary<object, long>(obj, pos, ReferenceEqualityComparer<object>.Instance); return false; } http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReferenceEqualityComparer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReferenceEqualityComparer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReferenceEqualityComparer.cs new file mode 100644 index 0000000..8038d6b --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReferenceEqualityComparer.cs @@ -0,0 +1,45 @@ +/* + * 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.Core.Impl.Binary +{ + using System.Collections.Generic; + using System.Runtime.CompilerServices; + + /// <summary> + /// Comparer that uses ReferenceEquals. + /// </summary> + internal class ReferenceEqualityComparer<T> : IEqualityComparer<T> + { + /// <summary> + /// Default instance. + /// </summary> + public static readonly ReferenceEqualityComparer<T> Instance = new ReferenceEqualityComparer<T>(); + + /** <inheritdoc /> */ + public bool Equals(T x, T y) + { + return ReferenceEquals(x, y); + } + + /** <inheritdoc /> */ + public int GetHashCode(T obj) + { + return RuntimeHelpers.GetHashCode(obj); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/cadc61fa/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs index fa19a9e..00bda16 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs @@ -214,12 +214,10 @@ namespace Apache.Ignite.Core.Impl.Common Debug.Assert(field.DeclaringType != null); // non-static var targetParam = Expression.Parameter(typeof(object)); - var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType); - var valParam = Expression.Parameter(typeof(object)); var valParamConverted = Expression.Convert(valParam, field.FieldType); - var assignExpr = Expression.Call(GetWriteFieldMethod(field), targetParamConverted, valParamConverted); + var assignExpr = Expression.Call(GetWriteFieldMethod(field), targetParam, valParamConverted); return Expression.Lambda<Action<object, object>>(assignExpr, targetParam, valParam).Compile(); }
