You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2016/03/21 13:23:53 UTC
ignite git commit: IGNITE-1957: .NET: Binary marshaller now use
handles for arrays, collections and dictionaries. This closes #302.
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 <pt...@gridgain.com>
Authored: Mon Mar 21 15:23:47 2016 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
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();
}