http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs index 08789b6..ce9fcf6 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs @@ -157,8 +157,6 @@ { IgniteArgumentCheck.NotNull(configuration, "configuration"); - CopyLocalProperties(configuration); - using (var stream = IgniteManager.Memory.Allocate().GetStream()) { var marsh = new Marshaller(configuration.BinaryConfiguration); @@ -171,6 +169,8 @@ ReadCore(marsh.StartUnmarshal(stream)); } + + CopyLocalProperties(configuration); } /// <summary> @@ -255,12 +255,37 @@ writer.WriteBoolean(false); // Binary config - var isCompactFooterSet = BinaryConfiguration != null && BinaryConfiguration.CompactFooterInternal != null; + if (BinaryConfiguration != null) + { + writer.WriteBoolean(true); - writer.WriteBoolean(isCompactFooterSet); + if (BinaryConfiguration.CompactFooterInternal != null) + { + writer.WriteBoolean(true); + writer.WriteBoolean(BinaryConfiguration.CompactFooter); + } + else + { + writer.WriteBoolean(false); + } + + // Send only descriptors with non-null EqualityComparer to preserve old behavior where + // remote nodes can have no BinaryConfiguration. + var types = writer.Marshaller.GetUserTypeDescriptors().Where(x => x.EqualityComparer != null).ToList(); + + writer.WriteInt(types.Count); - if (isCompactFooterSet) - writer.WriteBoolean(BinaryConfiguration.CompactFooter); + foreach (var type in types) + { + writer.WriteString(BinaryUtils.SimpleTypeName(type.TypeName)); + writer.WriteBoolean(type.IsEnum); + BinaryEqualityComparerSerializer.Write(writer, type.EqualityComparer); + } + } + else + { + writer.WriteBoolean(false); + } // User attributes var attrs = UserAttributes; @@ -361,7 +386,28 @@ if (r.ReadBoolean()) { BinaryConfiguration = BinaryConfiguration ?? new BinaryConfiguration(); - BinaryConfiguration.CompactFooter = r.ReadBoolean(); + + if (r.ReadBoolean()) + BinaryConfiguration.CompactFooter = r.ReadBoolean(); + + var typeCount = r.ReadInt(); + + if (typeCount > 0) + { + var types = new List<BinaryTypeConfiguration>(typeCount); + + for (var i = 0; i < typeCount; i++) + { + types.Add(new BinaryTypeConfiguration + { + TypeName = r.ReadString(), + IsEnum = r.ReadBoolean(), + EqualityComparer = BinaryEqualityComparerSerializer.Read(r) + }); + } + + BinaryConfiguration.TypeConfigurations = types; + } } // User attributes @@ -402,17 +448,15 @@ /// <param name="binaryReader">The binary reader.</param> private void Read(BinaryReader binaryReader) { - var r = binaryReader; - - CopyLocalProperties(r.Marshaller.Ignite.Configuration); + ReadCore(binaryReader); - ReadCore(r); + CopyLocalProperties(binaryReader.Marshaller.Ignite.Configuration); // Misc - IgniteHome = r.ReadString(); + IgniteHome = binaryReader.ReadString(); - JvmInitialMemoryMb = (int) (r.ReadLong()/1024/2014); - JvmMaxMemoryMb = (int) (r.ReadLong()/1024/2014); + JvmInitialMemoryMb = (int) (binaryReader.ReadLong()/1024/2014); + JvmMaxMemoryMb = (int) (binaryReader.ReadLong()/1024/2014); // Local data (not from reader) JvmDllPath = Process.GetCurrentProcess().Modules.OfType<ProcessModule>() @@ -426,9 +470,16 @@ private void CopyLocalProperties(IgniteConfiguration cfg) { GridName = cfg.GridName; - BinaryConfiguration = cfg.BinaryConfiguration == null - ? null - : new BinaryConfiguration(cfg.BinaryConfiguration); + + if (BinaryConfiguration != null && cfg.BinaryConfiguration != null) + { + BinaryConfiguration.MergeTypes(cfg.BinaryConfiguration); + } + else if (cfg.BinaryConfiguration != null) + { + BinaryConfiguration = new BinaryConfiguration(cfg.BinaryConfiguration); + } + JvmClasspath = cfg.JvmClasspath; JvmOptions = cfg.JvmOptions; Assemblies = cfg.Assemblies;
http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd index b35527d..d54a200 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd @@ -152,6 +152,20 @@ </xs:attribute> </xs:complexType> </xs:element> + <xs:element name="equalityComparer" minOccurs="0"> + <xs:annotation> + <xs:documentation> + Equality comparer to compute hash codes and compare objects in IBinaryObject form. + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="required"> + <xs:annotation> + <xs:documentation>Assembly-qualified type name.</xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + </xs:element> </xs:all> <xs:attribute name="typeName" type="xs:string"> <xs:annotation> @@ -297,6 +311,11 @@ <xs:documentation>Java field type name.</xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute name="isKeyField" type="xs:boolean"> + <xs:annotation> + <xs:documentation>Indicates whether this field belongs to the cache key.</xs:documentation> + </xs:annotation> + </xs:attribute> </xs:complexType> </xs:element> </xs:sequence> http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs index 3d55acd..fa7cf6c 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs @@ -81,7 +81,7 @@ namespace Apache.Ignite.Core.Impl.Binary throw new IgniteException("Type is not binary (add it to BinaryConfiguration): " + type.FullName); - return Builder0(null, BinaryFromDescriptor(desc), desc); + return Builder0(null, null, desc); } /** <inheritDoc /> */ @@ -91,7 +91,7 @@ namespace Apache.Ignite.Core.Impl.Binary IBinaryTypeDescriptor desc = _marsh.GetDescriptor(typeName); - return Builder0(null, BinaryFromDescriptor(desc), desc); + return Builder0(null, null, desc); } /** <inheritDoc /> */ @@ -182,30 +182,6 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Create empty binary object from descriptor. - /// </summary> - /// <param name="desc">Descriptor.</param> - /// <returns>Empty binary object.</returns> - private BinaryObject BinaryFromDescriptor(IBinaryTypeDescriptor desc) - { - const int len = BinaryObjectHeader.Size; - - var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; - - if (_marsh.CompactFooter && desc.UserType) - flags |= BinaryObjectHeader.Flag.CompactFooter; - - var hdr = new BinaryObjectHeader(desc.TypeId, 0, len, 0, len, flags); - - using (var stream = new BinaryHeapStream(len)) - { - BinaryObjectHeader.Write(hdr, stream, 0); - - return new BinaryObject(_marsh, stream.InternalArray, 0, hdr); - } - } - - /// <summary> /// Internal builder creation routine. /// </summary> /// <param name="parent">Parent builder.</param> http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs new file mode 100644 index 0000000..aa4795e --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs @@ -0,0 +1,99 @@ +/* + * 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; + using System.Collections.Generic; + using System.Linq; + using Apache.Ignite.Core.Binary; + + /// <summary> + /// Reads and writes <see cref="IBinaryEqualityComparer"/>. + /// </summary> + internal static class BinaryEqualityComparerSerializer + { + /// <summary> + /// SwapSpace type. + /// </summary> + private enum Type : byte + { + None = 0, + Array = 1, + Field = 2 + } + + /// <summary> + /// Writes an instance. + /// </summary> + public static void Write(IBinaryRawWriter writer, IBinaryEqualityComparer comparer) + { + if (comparer == null) + { + writer.WriteByte((byte) Type.None); + return; + } + + var arrCmp = comparer as BinaryArrayEqualityComparer; + + if (arrCmp != null) + { + writer.WriteByte((byte) Type.Array); + return; + } + + var fieldCmp = (BinaryFieldEqualityComparer) comparer; + + writer.WriteByte((byte) Type.Field); + + fieldCmp.Validate(); + + writer.WriteInt(fieldCmp.FieldNames.Count); + + foreach (var field in fieldCmp.FieldNames) + writer.WriteString(field); + } + + /// <summary> + /// Reads an instance. + /// </summary> + /// <param name="reader">The reader.</param> + /// <returns></returns> + public static IEqualityComparer<IBinaryObject> Read(IBinaryRawReader reader) + { + var type = (Type) reader.ReadByte(); + + switch (type) + { + case Type.None: + return null; + + case Type.Array: + return new BinaryArrayEqualityComparer(); + + case Type.Field: + return new BinaryFieldEqualityComparer + { + FieldNames = Enumerable.Range(0, reader.ReadInt()).Select(x => reader.ReadString()).ToArray() + }; + + default: + throw new ArgumentOutOfRangeException(); + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs new file mode 100644 index 0000000..433657a --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs @@ -0,0 +1,138 @@ +/* + * 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; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Impl.Binary.IO; + using Apache.Ignite.Core.Impl.Common; + + /// <summary> + /// Uses a set of binary object fields to calculate hash code and check equality. + /// Not implemented for now, will be done as part of IGNITE-4397. + /// </summary> + internal class BinaryFieldEqualityComparer : IEqualityComparer<IBinaryObject>, IBinaryEqualityComparer + { + /// <summary> + /// Initializes a new instance of the <see cref="BinaryFieldEqualityComparer"/> class. + /// </summary> + public BinaryFieldEqualityComparer() + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="BinaryFieldEqualityComparer"/> class. + /// </summary> + /// <param name="fieldNames">The field names for comparison.</param> + public BinaryFieldEqualityComparer(params string[] fieldNames) + { + IgniteArgumentCheck.NotNullOrEmpty(fieldNames, "fieldNames"); + + FieldNames = fieldNames; + } + + /// <summary> + /// Gets or sets the field names to be used for equality comparison. + /// </summary> + public ICollection<string> FieldNames { get; set; } + + /// <summary> + /// Determines whether the specified objects are equal. + /// </summary> + /// <param name="x">The first object to compare.</param> + /// <param name="y">The second object to compare.</param> + /// <returns> + /// true if the specified objects are equal; otherwise, false. + /// </returns> + public bool Equals(IBinaryObject x, IBinaryObject y) + { + throw new NotSupportedException(GetType() + "is not intended for direct usage."); + } + + /// <summary> + /// Returns a hash code for this instance. + /// </summary> + /// <param name="obj">The object.</param> + /// <returns> + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// </returns> + public int GetHashCode(IBinaryObject obj) + { + throw new NotSupportedException(GetType() + "is not intended for direct usage."); + } + + /** <inheritdoc /> */ + int IBinaryEqualityComparer.GetHashCode(IBinaryStream stream, int startPos, int length, + BinaryObjectSchemaHolder schema, int schemaId, Marshaller marshaller, IBinaryTypeDescriptor desc) + { + Debug.Assert(stream != null); + Debug.Assert(startPos >= 0); + Debug.Assert(length >= 0); + Debug.Assert(schema != null); + Debug.Assert(marshaller != null); + Debug.Assert(desc != null); + + Validate(); + + stream.Flush(); + + // Preserve stream position. + var pos = stream.Position; + + var reader = marshaller.StartUnmarshal(stream, BinaryMode.ForceBinary); + var fields = schema.GetFullSchema(schemaId); + + int hash = 0; + + foreach (var fieldName in FieldNames) + { + int fieldId = BinaryUtils.FieldId(desc.TypeId, fieldName, desc.NameMapper, desc.IdMapper); + int fieldHash = 0; // Null (missing) field hash code is 0. + int fieldPos; + + if (fields.TryGetValue(fieldId, out fieldPos)) + { + stream.Seek(startPos + fieldPos - BinaryObjectHeader.Size, SeekOrigin.Begin); + var fieldVal = reader.Deserialize<object>(); + fieldHash = fieldVal != null ? fieldVal.GetHashCode() : 0; + } + + hash = 31 * hash + fieldHash; + } + + // Restore stream position. + stream.Seek(pos, SeekOrigin.Begin); + + return hash; + } + + /// <summary> + /// Validates this instance. + /// </summary> + public void Validate() + { + if (FieldNames == null || FieldNames.Count == 0) + throw new IgniteException("BinaryFieldEqualityComparer.FieldNames can not be null or empty."); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs index 6dc5d4d..d88e7a9 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs @@ -20,6 +20,7 @@ namespace Apache.Ignite.Core.Impl.Binary using System; using System.Collections.Generic; using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Common; using Apache.Ignite.Core.Impl.Binary.Structure; /// <summary> @@ -66,6 +67,9 @@ namespace Apache.Ignite.Core.Impl.Binary /** Enum flag. */ private readonly bool _isEnum; + /** Comparer. */ + private readonly IBinaryEqualityComparer _equalityComparer; + /// <summary> /// Constructor. /// </summary> @@ -79,6 +83,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="affKeyFieldName">Affinity field key name.</param> /// <param name="isEnum">Enum flag.</param> + /// <param name="comparer">Equality comparer.</param> public BinaryFullTypeDescriptor( Type type, int typeId, @@ -89,7 +94,8 @@ namespace Apache.Ignite.Core.Impl.Binary IBinarySerializerInternal serializer, bool keepDeserialized, string affKeyFieldName, - bool isEnum) + bool isEnum, + IEqualityComparer<IBinaryObject> comparer) { _type = type; _typeId = typeId; @@ -101,6 +107,13 @@ namespace Apache.Ignite.Core.Impl.Binary _keepDeserialized = keepDeserialized; _affKeyFieldName = affKeyFieldName; _isEnum = isEnum; + + _equalityComparer = comparer as IBinaryEqualityComparer; + + if (comparer != null && _equalityComparer == null) + throw new IgniteException(string.Format("Unsupported IEqualityComparer<IBinaryObject> " + + "implementation: {0}. Only predefined implementations " + + "are supported.", comparer.GetType())); } /// <summary> @@ -181,6 +194,12 @@ namespace Apache.Ignite.Core.Impl.Binary get { return _isEnum; } } + /** <inheritdoc/> */ + public IBinaryEqualityComparer EqualityComparer + { + get { return _equalityComparer; } + } + /** <inheritDoc /> */ public BinaryStructure WriterTypeStructure { http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs index 39a2f8b..0a14bd2 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs @@ -195,6 +195,14 @@ namespace Apache.Ignite.Core.Impl.Binary get { return _offset; } } + /// <summary> + /// Gets the header. + /// </summary> + public BinaryObjectHeader Header + { + get { return _header; } + } + public bool TryGetFieldPosition(string fieldName, out int pos) { var desc = _marsh.GetDescriptor(true, _header.TypeId); @@ -244,6 +252,14 @@ namespace Apache.Ignite.Core.Impl.Binary if (_data == that._data && _offset == that._offset) return true; + if (TypeId != that.TypeId) + return false; + + var desc = _marsh.GetDescriptor(true, TypeId); + + if (desc != null && desc.EqualityComparer != null) + return desc.EqualityComparer.Equals(this, that); + // 1. Check headers if (_header == that._header) { @@ -266,8 +282,21 @@ namespace Apache.Ignite.Core.Impl.Binary object fieldVal = GetField<object>(field.Value, null); object thatFieldVal = that.GetField<object>(that._fields[field.Key], null); - if (!Equals(fieldVal, thatFieldVal)) + var arr = fieldVal as Array; + var thatArr = thatFieldVal as Array; + + if (arr != null && thatArr != null && arr.Length == thatArr.Length) + { + for (var i = 0; i < arr.Length; i++) + { + if (!Equals(arr.GetValue(i), thatArr.GetValue(i))) + return false; + } + } + else if (!Equals(fieldVal, thatFieldVal)) + { return false; + } } // 4. Check if objects have the same raw data. http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs index 1626a2d..db18638 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs @@ -55,7 +55,7 @@ namespace Apache.Ignite.Core.Impl.Binary private IDictionary<int, BinaryBuilderField> _cache; /** Hash code. */ - private int _hashCode; + private int? _hashCode; /** Current context. */ private Context _ctx; @@ -87,15 +87,21 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryObject obj, IBinaryTypeDescriptor desc) { Debug.Assert(binary != null); - Debug.Assert(obj != null); Debug.Assert(desc != null); _binary = binary; _parent = parent ?? this; - _obj = obj; _desc = desc; - _hashCode = obj.GetHashCode(); + if (obj != null) + { + _obj = obj; + _hashCode = obj.GetHashCode(); + } + else + { + _obj = BinaryFromDescriptor(desc); + } } /** <inheritDoc /> */ @@ -508,7 +514,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryHeapStream inStream, BinaryHeapStream outStream, IBinaryTypeDescriptor desc, - int hashCode, + int? hashCode, IDictionary<string, BinaryBuilderField> vals) { // Set correct builder to writer frame. @@ -578,7 +584,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="vals">Values to be replaced.</param> /// <returns>Mutated object.</returns> private void Mutate0(Context ctx, BinaryHeapStream inStream, IBinaryStream outStream, - bool changeHash, int hash, IDictionary<int, BinaryBuilderField> vals) + bool changeHash, int? hash, IDictionary<int, BinaryBuilderField> vals) { int inStartPos = inStream.Position; int outStartPos = outStream.Position; @@ -730,7 +736,25 @@ namespace Apache.Ignite.Core.Impl.Binary var outLen = outStream.Position - outStartPos; - var outHash = changeHash ? hash : inHeader.HashCode; + var outHash = inHeader.HashCode; + + if (changeHash) + { + if (hash != null) + { + outHash = hash.Value; + } + else + { + // Get from identity resolver. + outHash = _desc.EqualityComparer != null + ? _desc.EqualityComparer.GetHashCode(outStream, + outStartPos + BinaryObjectHeader.Size, + schemaPos - outStartPos - BinaryObjectHeader.Size, + outSchema, outSchemaId, _binary.Marshaller, _desc) + : 0; + } + } var outHeader = new BinaryObjectHeader(inHeader.TypeId, outHash, outLen, outSchemaId, outSchemaOff, flags); @@ -1027,6 +1051,30 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> + /// Create empty binary object from descriptor. + /// </summary> + /// <param name="desc">Descriptor.</param> + /// <returns>Empty binary object.</returns> + private BinaryObject BinaryFromDescriptor(IBinaryTypeDescriptor desc) + { + const int len = BinaryObjectHeader.Size; + + var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; + + if (_binary.Marshaller.CompactFooter && desc.UserType) + flags |= BinaryObjectHeader.Flag.CompactFooter; + + var hdr = new BinaryObjectHeader(desc.TypeId, 0, len, 0, len, flags); + + using (var stream = new BinaryHeapStream(len)) + { + BinaryObjectHeader.Write(hdr, stream, 0); + + return new BinaryObject(_binary.Marshaller, stream.InternalArray, 0, hdr); + } + } + + /// <summary> /// Mutation context. /// </summary> private class Context http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs index 0e5ad2a..636b177 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs @@ -211,21 +211,40 @@ namespace Apache.Ignite.Core.Impl.Binary /// Gets the raw offset of this object in specified stream. /// </summary> /// <param name="stream">The stream.</param> - /// <param name="position">The position.</param> + /// <param name="position">The binary object position in the stream.</param> /// <returns>Raw offset.</returns> public int GetRawOffset(IBinaryStream stream, int position) { Debug.Assert(stream != null); + // Either schema or raw is not present - offset is in the header. if (!HasRaw || !HasSchema) return SchemaOffset; + // Both schema and raw data are present: raw offset is in the last 4 bytes. stream.Seek(position + Length - 4, SeekOrigin.Begin); return stream.ReadInt(); } /// <summary> + /// Gets the footer offset where raw and non-raw data ends. + /// </summary> + /// <value>Footer offset.</value> + public int FooterStartOffset + { + get + { + // No schema: all we have is data. There is no offset in last 4 bytes. + if (!HasSchema) + return Length; + + // There is schema. Regardless of raw data presence, footer starts with schema. + return SchemaOffset; + } + } + + /// <summary> /// Writes specified header to a stream. /// </summary> /// <param name="header">The header.</param> http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs index c95746a..8ad78a4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs @@ -18,6 +18,7 @@ namespace Apache.Ignite.Core.Impl.Binary { using System; + using System.Collections.Generic; using System.Threading; using Apache.Ignite.Core.Impl.Binary.IO; using Apache.Ignite.Core.Impl.Common; @@ -119,5 +120,26 @@ namespace Apache.Ignite.Core.Impl.Binary return result; } + + /// <summary> + /// Gets the schema. + /// </summary> + /// <param name="schemaOffset">The schema offset.</param> + /// <returns>Current schema as a dictionary.</returns> + public Dictionary<int, int> GetFullSchema(int schemaOffset) + { + var size = _idx - schemaOffset; + + var result = new Dictionary<int, int>(size); + + for (int i = schemaOffset; i < _idx; i++) + { + var fld = _fields[i]; + + result[fld.Id] = fld.Offset; + } + + return result; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs index b572e7c..adba577 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs @@ -130,6 +130,12 @@ namespace Apache.Ignite.Core.Impl.Binary get { return false; } } + /** <inheritdoc/> */ + public IBinaryEqualityComparer EqualityComparer + { + get { return null; } + } + /** <inheritDoc /> */ public BinaryStructure WriterTypeStructure { http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 ccb2d1b..bdd7137 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs @@ -614,7 +614,9 @@ namespace Apache.Ignite.Core.Impl.Binary */ private static object ReadEnumArray(BinaryReader ctx, Type type) { - return BinaryUtils.ReadTypedArray(ctx, true, type.GetElementType()); + var elemType = type.GetElementType() ?? typeof(object); + + return BinaryUtils.ReadTypedArray(ctx, true, elemType); } /** @@ -622,7 +624,7 @@ namespace Apache.Ignite.Core.Impl.Binary */ private static object ReadArray(BinaryReader ctx, Type type) { - var elemType = type.IsArray ? type.GetElementType() : typeof(object); + var elemType = type.GetElementType() ?? typeof(object); return BinaryUtils.ReadTypedArray(ctx, true, elemType); } http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 77a22dd..47b0663 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs @@ -1195,9 +1195,10 @@ namespace Apache.Ignite.Core.Impl.Binary { // Write object fields. desc.Serializer.WriteBinary(obj, this); + var dataEnd = _stream.Position; // Write schema - var schemaOffset = _stream.Position - pos; + var schemaOffset = dataEnd - pos; int schemaId; @@ -1230,8 +1231,12 @@ namespace Apache.Ignite.Core.Impl.Binary var len = _stream.Position - pos; - var header = new BinaryObjectHeader(desc.TypeId, obj.GetHashCode(), len, - schemaId, schemaOffset, flags); + var hashCode = desc.EqualityComparer != null + ? desc.EqualityComparer.GetHashCode(Stream, pos + BinaryObjectHeader.Size, + dataEnd - pos - BinaryObjectHeader.Size, _schema, schemaIdx, _marsh, desc) + : obj.GetHashCode(); + + var header = new BinaryObjectHeader(desc.TypeId, hashCode, len, schemaId, schemaOffset, flags); BinaryObjectHeader.Write(header, _stream, pos); http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs index b80348e..6adb847 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs @@ -24,7 +24,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <summary> /// Wraps DateTime item in a binarizable. /// </summary> - internal class DateTimeHolder : IBinaryWriteAware + internal struct DateTimeHolder : IBinaryWriteAware { /** */ private readonly DateTime _item; @@ -64,5 +64,18 @@ namespace Apache.Ignite.Core.Impl.Binary writer.GetRawWriter().WriteLong(_item.ToBinary()); } + + /** <inheritDoc /> */ + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is DateTimeHolder && _item.Equals(((DateTimeHolder) obj)._item); + } + + /** <inheritDoc /> */ + public override int GetHashCode() + { + return _item.GetHashCode(); + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs new file mode 100644 index 0000000..9628688 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs @@ -0,0 +1,53 @@ +/* + * 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 Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Impl.Binary.IO; + + /// <summary> + /// Internal comparer interface for <see cref="BinaryTypeConfiguration.EqualityComparer"/> implementations, + /// provides more efficient API. + /// </summary> + internal interface IBinaryEqualityComparer + { + /// <summary> + /// Returns a hash code for the binary object in specified stream at specified position. + /// </summary> + /// <param name="stream">Stream.</param> + /// <param name="startPos">Data start position (right after the header).</param> + /// <param name="length">Data length (without header and schema).</param> + /// <param name="schema">Schema holder.</param> + /// <param name="schemaId">Schema identifier.</param> + /// <param name="marshaller">Marshaller.</param> + /// <param name="desc">Type descriptor.</param> + /// <returns> + /// A hash code for the object in the stream. + /// </returns> + int GetHashCode(IBinaryStream stream, int startPos, int length, BinaryObjectSchemaHolder schema, int schemaId, + Marshaller marshaller, IBinaryTypeDescriptor desc); + + /// <summary> + /// Returns a value indicating that two binary object are equal. + /// </summary> + /// <param name="x">First object.</param> + /// <param name="y">Second object.</param> + /// <returns>True when objects are equal; otherwise false.</returns> + bool Equals(IBinaryObject x, IBinaryObject y); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs index e25d720..6c7e360 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs @@ -78,6 +78,11 @@ namespace Apache.Ignite.Core.Impl.Binary bool IsEnum { get; } /// <summary> + /// Gets the equality comparer. + /// </summary> + IBinaryEqualityComparer EqualityComparer { get; } + + /// <summary> /// Write type structure. /// </summary> BinaryStructure WriterTypeStructure { get; } http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs index 2ce2138..ad35ff9 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs @@ -420,6 +420,15 @@ namespace Apache.Ignite.Core.Impl.Binary.IO } /** <inheritdoc /> */ + public override T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg) + { + fixed (byte* data0 = _data) + { + return proc.Invoke(data0, arg); + } + } + + /** <inheritdoc /> */ protected override void Dispose(bool disposing) { // No-op. http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs index 184209f..0b855f8 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs @@ -1119,6 +1119,19 @@ namespace Apache.Ignite.Core.Impl.Binary.IO return Pos; } + /// <summary> + /// Returns a hash code for the specified byte range. + /// </summary> + public abstract T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg); + + /// <summary> + /// Flushes the data to underlying storage. + /// </summary> + public void Flush() + { + // No-op. + } + /** <inheritdoc /> */ public void Dispose() { http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs index cd509c6..3a46515 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs @@ -318,5 +318,30 @@ namespace Apache.Ignite.Core.Impl.Binary.IO /// <param name="origin">Seek origin.</param> /// <returns>Position.</returns> int Seek(int offset, SeekOrigin origin); + + /// <summary> + /// Applies specified processor to the raw stream data. + /// </summary> + T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg); + + /// <summary> + /// Flushes the data to underlying storage. + /// </summary> + void Flush(); + } + + /// <summary> + /// Binary stream processor. + /// </summary> + [CLSCompliant(false)] + public unsafe interface IBinaryStreamProcessor<in TArg, out T> + { + /// <summary> + /// Invokes the processor. + /// </summary> + /// <param name="data">Data.</param> + /// <param name="arg">Argument.</param> + /// <returns>Result.</returns> + T Invoke(byte* data, TArg arg); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs index 475762a..6dee998 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs @@ -408,7 +408,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (meta != BinaryType.Empty) { desc = new BinaryFullTypeDescriptor(null, meta.TypeId, meta.TypeName, true, null, null, null, false, - meta.AffinityKeyFieldName, meta.IsEnum); + meta.AffinityKeyFieldName, meta.IsEnum, null); _idToDesc.GetOrAdd(typeKey, _ => desc); @@ -419,6 +419,14 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> + /// Gets the user type descriptors. + /// </summary> + public ICollection<IBinaryTypeDescriptor> GetUserTypeDescriptors() + { + return _typeNameToDesc.Values; + } + + /// <summary> /// Add user type. /// </summary> /// <param name="cfg">Configuration.</param> @@ -453,7 +461,7 @@ namespace Apache.Ignite.Core.Impl.Binary var serializer = GetSerializer(cfg, typeCfg, type, typeId, nameMapper, idMapper); AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, - affKeyFld, type.IsEnum); + affKeyFld, type.IsEnum, typeCfg.EqualityComparer); } else { @@ -463,7 +471,7 @@ namespace Apache.Ignite.Core.Impl.Binary int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, - typeCfg.AffinityKeyFieldName, typeCfg.IsEnum); + typeCfg.AffinityKeyFieldName, typeCfg.IsEnum, typeCfg.EqualityComparer); } } @@ -521,9 +529,11 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="serializer">Serializer.</param> /// <param name="affKeyFieldName">Affinity key field name.</param> /// <param name="isEnum">Enum flag.</param> + /// <param name="comparer">Comparer.</param> private void AddType(Type type, int typeId, string typeName, bool userType, bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, - IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum) + IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum, + IEqualityComparer<IBinaryObject> comparer) { long typeKey = BinaryUtils.TypeKey(userType, typeId); @@ -545,7 +555,7 @@ namespace Apache.Ignite.Core.Impl.Binary throw new BinaryObjectException("Conflicting type name: " + typeName); var descriptor = new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, - serializer, keepDeserialized, affKeyFieldName, isEnum); + serializer, keepDeserialized, affKeyFieldName, isEnum, comparer); if (type != null) _typeToDesc[type] = descriptor; @@ -571,7 +581,7 @@ namespace Apache.Ignite.Core.Impl.Binary typeId = BinaryUtils.TypeId(type.Name, null, null); AddType(type, typeId, BinaryUtils.GetTypeName(type), false, false, null, null, serializer, affKeyFldName, - false); + false, null); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs index 99c8f49..26b1d5f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs @@ -76,5 +76,21 @@ namespace Apache.Ignite.Core.Impl.Binary _item = new BinaryFormatter().Deserialize(streamAdapter, null); } } + + /** <inheritdoc /> */ + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + + return Equals(_item, ((SerializableObjectHolder) obj)._item); + } + + /** <inheritdoc /> */ + public override int GetHashCode() + { + return _item != null ? _item.GetHashCode() : 0; + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs index e1df50b..bb9cbfc 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs @@ -142,7 +142,7 @@ namespace Apache.Ignite.Core.Impl.Common /// </summary> private static void WriteComplexProperty(object obj, XmlWriter writer, Type valueType) { - var props = GetNonDefaultProperties(obj).ToList(); + var props = GetNonDefaultProperties(obj).OrderBy(x => x.Name).ToList(); // Specify type for interfaces and abstract classes if (valueType.IsAbstract) @@ -353,7 +353,8 @@ namespace Apache.Ignite.Core.Impl.Common /// </summary> private static List<Type> GetConcreteDerivedTypes(Type type) { - return type.Assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && type.IsAssignableFrom(t)).ToList(); + return typeof(IIgnite).Assembly.GetTypes() + .Where(t => t.IsClass && !t.IsAbstract && type.IsAssignableFrom(t)).ToList(); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs index c758d28..3719846 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs @@ -732,6 +732,22 @@ namespace Apache.Ignite.Core.Impl.Memory } /// <summary> + /// Returns a hash code for the specified byte range. + /// </summary> + public T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg) + { + return proc.Invoke(_data, arg); + } + + /// <summary> + /// Flushes the data to underlying storage. + /// </summary> + public void Flush() + { + SynchronizeOutput(); + } + + /// <summary> /// Ensure capacity for write and shift position. /// </summary> /// <param name="cnt">Bytes count.</param>