IGNITE-1644: Correct DateTime serialization.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/05e739f1 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/05e739f1 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/05e739f1 Branch: refs/heads/ignite-1753-1282 Commit: 05e739f1689cd801f669f3a668b5039ca0a7d653 Parents: 9d67c20 Author: Pavel Tupitsyn <[email protected]> Authored: Tue Oct 27 13:50:29 2015 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Tue Oct 27 13:50:29 2015 +0300 ---------------------------------------------------------------------- .../Portable/PortableApiSelfTest.cs | 60 ++- .../Portable/PortableSelfTest.cs | 42 +- .../Apache.Ignite.Core.csproj | 1 + .../Impl/Portable/DateTimeHolder.cs | 68 +++ .../Impl/Portable/PortableBuilderField.cs | 56 ++- .../Impl/Portable/PortableBuilderImpl.cs | 420 ++++++++++++++----- .../Impl/Portable/PortableMarshaller.cs | 1 + .../Impl/Portable/PortableReaderImpl.cs | 148 ++++--- .../Impl/Portable/PortableReflectiveRoutines.cs | 15 - .../Impl/Portable/PortableSystemHandlers.cs | 94 ++++- .../Impl/Portable/PortableUserObject.cs | 73 ++-- .../Impl/Portable/PortableUtils.cs | 19 +- .../Impl/Portable/PortableWriterImpl.cs | 31 +- .../Portable/IPortableBuilder.cs | 235 +++++++++++ 14 files changed, 929 insertions(+), 334 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs index bb1cf06..c85c823 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableApiSelfTest.cs @@ -448,7 +448,7 @@ namespace Apache.Ignite.Core.Tests.Portable IPortableBuilder builderItem = _grid.GetPortables().GetBuilder(typeof(BuilderCollectionItem)).SetField("val", 1); - builderCol.SetField<ICollection>("col", new ArrayList { builderItem }); + builderCol.SetCollectionField("col", new ArrayList { builderItem }); IPortableObject portCol = builderCol.Build(); @@ -801,18 +801,18 @@ namespace Apache.Ignite.Core.Tests.Portable [Test] public void TestStringDateGuidEnum() { - DateTime? nDate = DateTime.Now.ToUniversalTime(); + DateTime? nDate = DateTime.Now; Guid? nGuid = Guid.NewGuid(); IPortableObject portObj = _grid.GetPortables().GetBuilder(typeof(StringDateGuidEnum)) .SetField("fStr", "str") .SetField("fNDate", nDate) - .SetField("fNGuid", nGuid) + .SetGuidField("fNGuid", nGuid) .SetField("fEnum", TestEnum.One) .SetField("fStrArr", new[] { "str" }) - .SetField("fDateArr", new[] { nDate }) - .SetField("fGuidArr", new[] { nGuid }) + .SetArrayField("fDateArr", new[] { nDate }) + .SetGuidArrayField("fGuidArr", new[] { nGuid }) .SetField("fEnumArr", new[] { TestEnum.One }) .SetHashCode(100) .Build(); @@ -826,11 +826,11 @@ namespace Apache.Ignite.Core.Tests.Portable Assert.AreEqual(8, meta.Fields.Count); Assert.AreEqual(PortableTypeNames.TypeNameString, meta.GetFieldTypeName("fStr")); - Assert.AreEqual(PortableTypeNames.TypeNameTimestamp, meta.GetFieldTypeName("fNDate")); + Assert.AreEqual(PortableTypeNames.TypeNameObject, meta.GetFieldTypeName("fNDate")); Assert.AreEqual(PortableTypeNames.TypeNameGuid, meta.GetFieldTypeName("fNGuid")); Assert.AreEqual(PortableTypeNames.TypeNameEnum, meta.GetFieldTypeName("fEnum")); Assert.AreEqual(PortableTypeNames.TypeNameArrayString, meta.GetFieldTypeName("fStrArr")); - Assert.AreEqual(PortableTypeNames.TypeNameArrayTimestamp, meta.GetFieldTypeName("fDateArr")); + Assert.AreEqual(PortableTypeNames.TypeNameArrayObject, meta.GetFieldTypeName("fDateArr")); Assert.AreEqual(PortableTypeNames.TypeNameArrayGuid, meta.GetFieldTypeName("fGuidArr")); Assert.AreEqual(PortableTypeNames.TypeNameArrayEnum, meta.GetFieldTypeName("fEnumArr")); @@ -854,18 +854,52 @@ namespace Apache.Ignite.Core.Tests.Portable Assert.AreEqual(new[] { nGuid }, obj.FGuidArr); Assert.AreEqual(new[] { TestEnum.One }, obj.FEnumArr); + // Check builder field caching. + var builder = _grid.GetPortables().GetBuilder(portObj); + + Assert.AreEqual("str", builder.GetField<string>("fStr")); + Assert.AreEqual(nDate, builder.GetField<DateTime?>("fNDate")); + Assert.AreEqual(nGuid, builder.GetField<Guid?>("fNGuid")); + Assert.AreEqual(TestEnum.One, builder.GetField<TestEnum>("fEnum")); + Assert.AreEqual(new[] { "str" }, builder.GetField<string[]>("fStrArr")); + Assert.AreEqual(new[] { nDate }, builder.GetField<DateTime?[]>("fDateArr")); + Assert.AreEqual(new[] { nGuid }, builder.GetField<Guid?[]>("fGuidArr")); + Assert.AreEqual(new[] { TestEnum.One }, builder.GetField<TestEnum[]>("fEnumArr")); + + // Check reassemble. + portObj = builder.Build(); + + Assert.AreEqual("str", portObj.GetField<string>("fStr")); + Assert.AreEqual(nDate, portObj.GetField<DateTime?>("fNDate")); + Assert.AreEqual(nGuid, portObj.GetField<Guid?>("fNGuid")); + Assert.AreEqual(TestEnum.One, portObj.GetField<TestEnum>("fEnum")); + Assert.AreEqual(new[] { "str" }, portObj.GetField<string[]>("fStrArr")); + Assert.AreEqual(new[] { nDate }, portObj.GetField<DateTime?[]>("fDateArr")); + Assert.AreEqual(new[] { nGuid }, portObj.GetField<Guid?[]>("fGuidArr")); + Assert.AreEqual(new[] { TestEnum.One }, portObj.GetField<TestEnum[]>("fEnumArr")); + + obj = portObj.Deserialize<StringDateGuidEnum>(); + + Assert.AreEqual("str", obj.FStr); + Assert.AreEqual(nDate, obj.FnDate); + Assert.AreEqual(nGuid, obj.FnGuid); + Assert.AreEqual(TestEnum.One, obj.FEnum); + Assert.AreEqual(new[] { "str" }, obj.FStrArr); + Assert.AreEqual(new[] { nDate }, obj.FDateArr); + Assert.AreEqual(new[] { nGuid }, obj.FGuidArr); + Assert.AreEqual(new[] { TestEnum.One }, obj.FEnumArr); + // Overwrite. nDate = DateTime.Now.ToUniversalTime(); - nGuid = Guid.NewGuid(); - portObj = _grid.GetPortables().GetBuilder(typeof(StringDateGuidEnum)) + portObj = builder .SetField("fStr", "str2") - .SetField("fNDate", nDate) + .SetTimestampField("fNDate", nDate) .SetField("fNGuid", nGuid) .SetField("fEnum", TestEnum.Two) .SetField("fStrArr", new[] { "str2" }) - .SetField("fDateArr", new[] { nDate }) + .SetArrayField("fDateArr", new[] { nDate }) .SetField("fGuidArr", new[] { nGuid }) .SetField("fEnumArr", new[] { TestEnum.Two }) .SetHashCode(200) @@ -1070,8 +1104,8 @@ namespace Apache.Ignite.Core.Tests.Portable dict[3] = new CompositeInner(3); IPortableObject portObj = _grid.GetPortables().GetBuilder(typeof(CompositeContainer)).SetHashCode(100) - .SetField<ICollection>("col", col) - .SetField("dict", dict).Build(); + .SetCollectionField("col", col) + .SetDictionaryField("dict", dict).Build(); // 1. Check meta. IPortableMetadata meta = portObj.GetMetadata(); http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs index 62d52f6..08e0b31 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs @@ -26,7 +26,6 @@ namespace Apache.Ignite.Core.Tests.Portable using System.Collections; using System.Collections.Generic; using System.Linq; - using System.Text; using Apache.Ignite.Core.Common; using Apache.Ignite.Core.Impl.Portable; using Apache.Ignite.Core.Impl.Portable.IO; @@ -529,6 +528,24 @@ namespace Apache.Ignite.Core.Tests.Portable Assert.AreEqual(obj.UtcArrRaw, otherObj.UtcArrRaw); } + /// <summary> + /// Tests the DateTime marshalling. + /// </summary> + [Test] + public void TestDateTime() + { + var time = DateTime.Now; + Assert.AreEqual(_marsh.Unmarshal<DateTime>(_marsh.Marshal(time)), time); + + var timeUtc = DateTime.UtcNow; + Assert.AreEqual(_marsh.Unmarshal<DateTime>(_marsh.Marshal(timeUtc)), timeUtc); + + // Check exception with non-UTC date + var stream = new PortableHeapStream(128); + var writer = _marsh.StartMarshal(stream); + Assert.Throws<InvalidOperationException>(() => writer.WriteTimestamp(DateTime.Now)); + } + /** * <summary>Check generic collections.</summary> */ @@ -1396,29 +1413,6 @@ namespace Apache.Ignite.Core.Tests.Portable } } - private static string CollectionAsString(ICollection col) - { - if (col == null) - return null; - StringBuilder sb = new StringBuilder("["); - - bool first = true; - - foreach (object elem in col) - { - if (first) - first = false; - else - sb.Append(", "); - - sb.Append(elem); - } - - sb.Append("]"); - - return sb.ToString(); - } - public class TestList : ArrayList { http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/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 f314c99..04cbca1 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -243,6 +243,7 @@ <Compile Include="Impl\Messaging\Messaging.cs" /> <Compile Include="Impl\Messaging\MessagingAsync.cs" /> <Compile Include="Impl\NativeMethods.cs" /> + <Compile Include="Impl\Portable\DateTimeHolder.cs" /> <Compile Include="Impl\Portable\IO\IPortableStream.cs" /> <Compile Include="Impl\Portable\IO\PortableAbstractStream.cs" /> <Compile Include="Impl\Portable\IO\PortableHeapStream.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/DateTimeHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/DateTimeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/DateTimeHolder.cs new file mode 100644 index 0000000..9c232a0 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/DateTimeHolder.cs @@ -0,0 +1,68 @@ +/* + * 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.Portable +{ + using System; + using System.Diagnostics; + using Apache.Ignite.Core.Portable; + + /// <summary> + /// Wraps Serializable item in a portable. + /// </summary> + internal class DateTimeHolder : IPortableWriteAware + { + /** */ + private readonly DateTime _item; + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="item">The item to wrap.</param> + public DateTimeHolder(DateTime item) + { + _item = item; + } + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="reader">The reader.</param> + public DateTimeHolder(IPortableReader reader) + { + Debug.Assert(reader != null); + + _item = DateTime.FromBinary(reader.GetRawReader().ReadLong()); + } + + /// <summary> + /// Gets the item to wrap. + /// </summary> + public DateTime Item + { + get { return _item; } + } + + /** <inheritDoc /> */ + public void WritePortable(IPortableWriter writer) + { + Debug.Assert(writer != null); + + writer.GetRawWriter().WriteLong(_item.ToBinary()); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs index 026d0d4..c54348d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs @@ -24,28 +24,34 @@ namespace Apache.Ignite.Core.Impl.Portable /// </summary> internal class PortableBuilderField { - /** Remove marker object. */ - public static readonly object RmvMarkerObj = new object(); - /** Remove marker. */ - public static readonly PortableBuilderField RmvMarker = - new PortableBuilderField(null, RmvMarkerObj); + public static readonly PortableBuilderField RmvMarker = new PortableBuilderField(null, null, 0); /** Type. */ - private readonly Type _typ; + private readonly Type _type; /** Value. */ - private readonly object _val; + private readonly object _value; + + /** Write action. */ + private readonly Action<PortableWriterImpl, object> _writeAction; + + /** Type id. */ + private readonly byte _typeId; /// <summary> /// Constructor. /// </summary> - /// <param name="typ">Type.</param> - /// <param name="val">Value.</param> - public PortableBuilderField(Type typ, object val) + /// <param name="type">Type.</param> + /// <param name="value">Value.</param> + /// <param name="typeId">The type identifier.</param> + /// <param name="writeAction">Optional write action.</param> + public PortableBuilderField(Type type, object value, byte typeId, Action<PortableWriterImpl, object> writeAction = null) { - _typ = typ; - _val = val; + _type = type; + _value = value; + _typeId = typeId; + _writeAction = writeAction; } /// <summary> @@ -53,10 +59,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// </summary> public Type Type { - get - { - return _typ; - } + get { return _type; } } /// <summary> @@ -64,10 +67,23 @@ namespace Apache.Ignite.Core.Impl.Portable /// </summary> public object Value { - get - { - return _val; - } + get { return _value; } + } + + /// <summary> + /// Gets the write action. + /// </summary> + public Action<PortableWriterImpl, object> WriteAction + { + get { return _writeAction; } + } + + /// <summary> + /// Gets the type identifier. + /// </summary> + public byte TypeId + { + get { return _typeId; } } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs index ac7a957..9767037 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs @@ -20,7 +20,7 @@ namespace Apache.Ignite.Core.Impl.Portable using System; using System.Collections; using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; + using System.Diagnostics; using System.IO; using Apache.Ignite.Core.Common; using Apache.Ignite.Core.Impl.Portable.IO; @@ -32,11 +32,9 @@ namespace Apache.Ignite.Core.Impl.Portable /// </summary> internal class PortableBuilderImpl : IPortableBuilder { - /** Type IDs for metadata. */ - private static readonly IDictionary<Type, int> TypeIds; - /** Cached dictionary with no values. */ - private static readonly IDictionary<int, object> EmptyVals = new Dictionary<int, object>(); + private static readonly IDictionary<int, PortableBuilderField> EmptyVals = + new Dictionary<int, PortableBuilderField>(); /** Portables. */ private readonly PortablesImpl _portables; @@ -54,55 +52,29 @@ namespace Apache.Ignite.Core.Impl.Portable private IDictionary<string, PortableBuilderField> _vals; /** Contextual fields. */ - private IDictionary<int, object> _cache; + private IDictionary<int, PortableBuilderField> _cache; /** Hash code. */ private int _hashCode; /** Current context. */ private Context _ctx; - - /// <summary> - /// Static initializer. - /// </summary> - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static PortableBuilderImpl() - { - TypeIds = new Dictionary<Type, int>(); - - // 1. Primitives. - TypeIds[typeof(byte)] = PortableUtils.TypeByte; - TypeIds[typeof(bool)] = PortableUtils.TypeBool; - TypeIds[typeof(short)] = PortableUtils.TypeShort; - TypeIds[typeof(char)] = PortableUtils.TypeChar; - TypeIds[typeof(int)] = PortableUtils.TypeInt; - TypeIds[typeof(long)] = PortableUtils.TypeLong; - TypeIds[typeof(float)] = PortableUtils.TypeFloat; - TypeIds[typeof(double)] = PortableUtils.TypeDouble; - TypeIds[typeof(decimal)] = PortableUtils.TypeDecimal; - - TypeIds[typeof(byte[])] = PortableUtils.TypeArrayByte; - TypeIds[typeof(bool[])] = PortableUtils.TypeArrayBool; - TypeIds[typeof(short[])] = PortableUtils.TypeArrayShort; - TypeIds[typeof(char[])] = PortableUtils.TypeArrayChar; - TypeIds[typeof(int[])] = PortableUtils.TypeArrayInt; - TypeIds[typeof(long[])] = PortableUtils.TypeArrayLong; - TypeIds[typeof(float[])] = PortableUtils.TypeArrayFloat; - TypeIds[typeof(double[])] = PortableUtils.TypeArrayDouble; - TypeIds[typeof(decimal?[])] = PortableUtils.TypeArrayDecimal; - - // 2. String. - TypeIds[typeof(string)] = PortableUtils.TypeString; - TypeIds[typeof(string[])] = PortableUtils.TypeArrayString; - - // 3. Guid. - TypeIds[typeof(Guid?)] = PortableUtils.TypeGuid; - TypeIds[typeof(Guid?[])] = PortableUtils.TypeArrayGuid; - - // 4. Date. - TypeIds[typeof(DateTime?)] = PortableUtils.TypeTimestamp; - TypeIds[typeof(DateTime?[])] = PortableUtils.TypeArrayTimestamp; - } + + /** Write array action. */ + private static readonly Action<PortableWriterImpl, object> WriteArrayAction = + (w, o) => w.WriteArrayInternal((Array) o); + + /** Write collection action. */ + private static readonly Action<PortableWriterImpl, object> WriteCollectionAction = + (w, o) => w.WriteCollection((ICollection) o); + + /** Write timestamp action. */ + private static readonly Action<PortableWriterImpl, object> WriteTimestampAction = + (w, o) => w.WriteTimestamp((DateTime?) o); + + /** Write timestamp array action. */ + private static readonly Action<PortableWriterImpl, object> WriteTimestampArrayAction = + (w, o) => w.WriteTimestampArray((DateTime?[])o); /// <summary> /// Constructor. @@ -114,6 +86,10 @@ namespace Apache.Ignite.Core.Impl.Portable public PortableBuilderImpl(PortablesImpl portables, PortableBuilderImpl parent, PortableUserObject obj, IPortableTypeDescriptor desc) { + Debug.Assert(portables != null); + Debug.Assert(obj != null); + Debug.Assert(desc != null); + _portables = portables; _parent = parent ?? this; _obj = obj; @@ -136,22 +112,236 @@ namespace Apache.Ignite.Core.Impl.Portable PortableBuilderField field; if (_vals != null && _vals.TryGetValue(name, out field)) - return field != PortableBuilderField.RmvMarker ? (T)field.Value : default(T); - T val = _obj.Field<T>(name, this); + return field != PortableBuilderField.RmvMarker ? (T) field.Value : default(T); - if (_vals == null) - _vals = new Dictionary<string, PortableBuilderField>(2); + int pos; + + if (!_obj.TryGetFieldPosition(name, out pos)) + return default(T); + + T val; + + if (TryGetCachedField(pos, out val)) + return val; - _vals[name] = new PortableBuilderField(typeof(T), val); + val = _obj.GetField<T>(pos, this); + + var fld = CacheField(pos, val); + + SetField0(name, fld); return val; } /** <inheritDoc /> */ - public IPortableBuilder SetField<T>(string name, T val) + public IPortableBuilder SetField<T>(string fieldName, T val) + { + return SetField0(fieldName, + new PortableBuilderField(typeof (T), val, PortableSystemHandlers.GetTypeId(typeof (T)))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetArrayField<T>(string fieldName, T[] val) + { + return SetField0(fieldName, + new PortableBuilderField(typeof (T[]), val, PortableUtils.TypeArray, WriteArrayAction)); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetBooleanField(string fieldName, bool val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (bool), val, PortableUtils.TypeBool, + (w, o) => w.WriteBoolean((bool) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetBooleanArrayField(string fieldName, bool[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (bool[]), val, PortableUtils.TypeArrayBool, + (w, o) => w.WriteBooleanArray((bool[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetByteField(string fieldName, byte val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (byte), val, PortableUtils.TypeByte, + (w, o) => w.WriteByte((byte) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetByteArrayField(string fieldName, byte[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (byte[]), val, PortableUtils.TypeArrayByte, + (w, o) => w.WriteByteArray((byte[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetCharField(string fieldName, char val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (char), val, PortableUtils.TypeChar, + (w, o) => w.WriteChar((char) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetCharArrayField(string fieldName, char[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (char[]), val, PortableUtils.TypeArrayChar, + (w, o) => w.WriteCharArray((char[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetCollectionField(string fieldName, ICollection val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (ICollection), val, PortableUtils.TypeCollection, + WriteCollectionAction)); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetDecimalField(string fieldName, decimal? val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (decimal?), val, PortableUtils.TypeDecimal, + (w, o) => w.WriteDecimal((decimal?) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetDecimalArrayField(string fieldName, decimal?[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (decimal?[]), val, PortableUtils.TypeArrayDecimal, + (w, o) => w.WriteDecimalArray((decimal?[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetDictionaryField(string fieldName, IDictionary val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (IDictionary), val, PortableUtils.TypeDictionary, + (w, o) => w.WriteDictionary((IDictionary) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetDoubleField(string fieldName, double val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (double), val, PortableUtils.TypeDouble, + (w, o) => w.WriteDouble((double) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetDoubleArrayField(string fieldName, double[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (double[]), val, PortableUtils.TypeArrayDouble, + (w, o) => w.WriteDoubleArray((double[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetEnumField<T>(string fieldName, T val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (T), val, PortableUtils.TypeEnum, + (w, o) => w.WriteEnum((T) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetEnumArrayField<T>(string fieldName, T[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (T[]), val, PortableUtils.TypeArrayEnum, + (w, o) => w.WriteEnumArray((T[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetFloatField(string fieldName, float val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (float), val, PortableUtils.TypeFloat, + (w, o) => w.WriteFloat((float) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetFloatArrayField(string fieldName, float[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (float[]), val, PortableUtils.TypeArrayFloat, + (w, o) => w.WriteFloatArray((float[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetGuidField(string fieldName, Guid? val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (Guid?), val, PortableUtils.TypeGuid, + (w, o) => w.WriteGuid((Guid?) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetGuidArrayField(string fieldName, Guid?[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (Guid?[]), val, PortableUtils.TypeArrayGuid, + (w, o) => w.WriteGuidArray((Guid?[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetIntField(string fieldName, int val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (int), val, PortableUtils.TypeInt, + (w, o) => w.WriteInt((int) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetIntArrayField(string fieldName, int[] val) { - return SetField0(name, new PortableBuilderField(typeof(T), val)); + return SetField0(fieldName, new PortableBuilderField(typeof (int[]), val, PortableUtils.TypeArrayInt, + (w, o) => w.WriteIntArray((int[]) o))); } + + /** <inheritDoc /> */ + public IPortableBuilder SetLongField(string fieldName, long val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (long), val, PortableUtils.TypeLong, + (w, o) => w.WriteLong((long) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetLongArrayField(string fieldName, long[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (long[]), val, PortableUtils.TypeArrayLong, + (w, o) => w.WriteLongArray((long[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetShortField(string fieldName, short val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (short), val, PortableUtils.TypeShort, + (w, o) => w.WriteShort((short) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetShortArrayField(string fieldName, short[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (short[]), val, PortableUtils.TypeArrayShort, + (w, o) => w.WriteShortArray((short[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetStringField(string fieldName, string val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (string), val, PortableUtils.TypeString, + (w, o) => w.WriteString((string) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetStringArrayField(string fieldName, string[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (string[]), val, PortableUtils.TypeArrayString, + (w, o) => w.WriteStringArray((string[]) o))); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetTimestampField(string fieldName, DateTime? val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (DateTime?), val, PortableUtils.TypeTimestamp, + WriteTimestampAction)); + } + + /** <inheritDoc /> */ + public IPortableBuilder SetTimestampArrayField(string fieldName, DateTime?[] val) + { + return SetField0(fieldName, new PortableBuilderField(typeof (DateTime?[]), val, PortableUtils.TypeArrayTimestamp, + WriteTimestampArrayAction)); + } /** <inheritDoc /> */ public IPortableBuilder RemoveField(string name) @@ -215,15 +405,15 @@ namespace Apache.Ignite.Core.Impl.Portable /// <param name="pos">Position.</param> /// <param name="val">Value.</param> /// <returns><c>true</c> if value is found in cache.</returns> - public bool CachedField<T>(int pos, out T val) + public bool TryGetCachedField<T>(int pos, out T val) { if (_parent._cache != null) { - object res; + PortableBuilderField res; if (_parent._cache.TryGetValue(pos, out res)) { - val = res != null ? (T)res : default(T); + val = res != null ? (T) res.Value : default(T); return true; } @@ -239,12 +429,46 @@ namespace Apache.Ignite.Core.Impl.Portable /// </summary> /// <param name="pos">Position.</param> /// <param name="val">Value.</param> - public void CacheField(int pos, object val) + public PortableBuilderField CacheField<T>(int pos, T val) { if (_parent._cache == null) - _parent._cache = new Dictionary<int, object>(2); + _parent._cache = new Dictionary<int, PortableBuilderField>(2); + + var hdr = _obj.Data[pos]; + + var field = new PortableBuilderField(typeof(T), val, hdr, GetWriteAction(hdr)); + + _parent._cache[pos] = field; + + return field; + } + + /// <summary> + /// Gets the write action by header. + /// </summary> + /// <param name="header">The header.</param> + /// <returns>Write action.</returns> + private static Action<PortableWriterImpl, object> GetWriteAction(byte header) + { + // We need special actions for all cases where SetField(X) produces different result from SetSpecialField(X) + // Arrays, Collections, Dates + + switch (header) + { + case PortableUtils.TypeArray: + return WriteArrayAction; + + case PortableUtils.TypeCollection: + return WriteCollectionAction; + + case PortableUtils.TypeTimestamp: + return WriteTimestampAction; - _parent._cache[pos] = val; + case PortableUtils.TypeArrayTimestamp: + return WriteTimestampArrayAction; + } + + return null; } /// <summary> @@ -271,7 +495,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// <param name="desc">Portable type descriptor.</param> /// <param name="hashCode">Hash code.</param> /// <param name="vals">Values.</param> - internal void Mutate( + private void Mutate( PortableHeapStream inStream, PortableHeapStream outStream, IPortableTypeDescriptor desc, @@ -288,13 +512,13 @@ namespace Apache.Ignite.Core.Impl.Portable // Prepare fields. IPortableMetadataHandler metaHnd = _portables.Marshaller.GetMetadataHandler(desc); - IDictionary<int, object> vals0; + IDictionary<int, PortableBuilderField> vals0; if (vals == null || vals.Count == 0) vals0 = EmptyVals; else { - vals0 = new Dictionary<int, object>(vals.Count); + vals0 = new Dictionary<int, PortableBuilderField>(vals.Count); foreach (KeyValuePair<string, PortableBuilderField> valEntry in vals) { @@ -304,12 +528,12 @@ namespace Apache.Ignite.Core.Impl.Portable throw new IgniteException("Collision in field ID detected (change field name or " + "define custom ID mapper) [fieldName=" + valEntry.Key + ", fieldId=" + fieldId + ']'); - vals0[fieldId] = valEntry.Value.Value; + vals0[fieldId] = valEntry.Value; // Write metadata if: 1) it is enabled for type; 2) type is not null (i.e. it is neither // remove marker, nor a field read through "GetField" method. if (metaHnd != null && valEntry.Value.Type != null) - metaHnd.OnFieldWrite(fieldId, valEntry.Key, GetTypeId(valEntry.Value.Type)); + metaHnd.OnFieldWrite(fieldId, valEntry.Key, valEntry.Value.TypeId); } } @@ -345,7 +569,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// <param name="vals">Values to be replaced.</param> /// <returns>Mutated object.</returns> private void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream, - bool changeHash, int hash, IDictionary<int, object> vals) + bool changeHash, int hash, IDictionary<int, PortableBuilderField> vals) { int inStartPos = inStream.Position; int outStartPos = outStream.Position; @@ -394,10 +618,10 @@ namespace Apache.Ignite.Core.Impl.Portable if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos)) { // Object could be cached in parent builder. - object cachedVal; + PortableBuilderField cachedVal; if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) { - ctx.Writer.Write(cachedVal); + WriteField(ctx, cachedVal); } else { @@ -418,11 +642,11 @@ namespace Apache.Ignite.Core.Impl.Portable int inFieldLen = inStream.ReadInt(); int inFieldDataPos = inStream.Position; - object fieldVal; + PortableBuilderField fieldVal; bool fieldFound = vals.TryGetValue(inFieldId, out fieldVal); - if (!fieldFound || fieldVal != PortableBuilderField.RmvMarkerObj) + if (!fieldFound || fieldVal != PortableBuilderField.RmvMarker) { outStream.WriteInt(inFieldId); @@ -433,8 +657,8 @@ namespace Apache.Ignite.Core.Impl.Portable if (fieldFound) { // Replace field with new value. - if (fieldVal != PortableBuilderField.RmvMarkerObj) - ctx.Writer.Write(fieldVal); + if (fieldVal != PortableBuilderField.RmvMarker) + WriteField(ctx, fieldVal); vals.Remove(inFieldId); } @@ -442,9 +666,9 @@ namespace Apache.Ignite.Core.Impl.Portable { // If field was requested earlier, then we must write tracked value if (_parent._cache != null && _parent._cache.TryGetValue(inFieldDataPos, out fieldVal)) - ctx.Writer.Write(fieldVal); + WriteField(ctx, fieldVal); else - // Filed is not tracked, re-write as is. + // Field is not tracked, re-write as is. Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); } @@ -460,9 +684,9 @@ namespace Apache.Ignite.Core.Impl.Portable } // Write remaining new fields. - foreach (KeyValuePair<int, object> valEntry in vals) + foreach (var valEntry in vals) { - if (valEntry.Value != PortableBuilderField.RmvMarkerObj) + if (valEntry.Value != PortableBuilderField.RmvMarker) { outStream.WriteInt(valEntry.Key); @@ -470,7 +694,7 @@ namespace Apache.Ignite.Core.Impl.Portable outStream.Seek(4, SeekOrigin.Current); - ctx.Writer.Write(valEntry.Value); + WriteField(ctx, valEntry.Value); int fieldEndPos = outStream.Position; @@ -518,6 +742,19 @@ namespace Apache.Ignite.Core.Impl.Portable } /// <summary> + /// Writes the specified field. + /// </summary> + private static void WriteField(Context ctx, PortableBuilderField field) + { + var action = field.WriteAction; + + if (action != null) + action(ctx.Writer, field.Value); + else + ctx.Writer.Write(field.Value); + } + + /// <summary> /// Process portable object inverting handles if needed. /// </summary> /// <param name="outStream">Output stream.</param> @@ -740,33 +977,6 @@ namespace Apache.Ignite.Core.Impl.Portable } /// <summary> - /// Get's metadata field type ID for the given type. - /// </summary> - /// <param name="type">Type.</param> - /// <returns>Type ID.</returns> - private static int GetTypeId(Type type) - { - int typeId; - - if (TypeIds.TryGetValue(type, out typeId)) - return typeId; - - if (type.IsEnum) - return PortableUtils.TypeEnum; - - if (type.IsArray) - return type.GetElementType().IsEnum ? PortableUtils.TypeArrayEnum : PortableUtils.TypeArray; - - if (typeof (IDictionary).IsAssignableFrom(type)) - return PortableUtils.TypeDictionary; - - if (typeof (ICollection).IsAssignableFrom(type)) - return PortableUtils.TypeCollection; - - return PortableUtils.TypeObject; - } - - /// <summary> /// Transfer bytes from one stream to another. /// </summary> /// <param name="inStream">Input stream.</param> http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs index 2848df1..a8d7058 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs @@ -512,6 +512,7 @@ namespace Apache.Ignite.Core.Impl.Portable AddSystemType(PortableUtils.TypeComputeActionJob, w => new ComputeActionJob(w)); AddSystemType(PortableUtils.TypeContinuousQueryRemoteFilterHolder, w => new ContinuousQueryFilterHolder(w)); AddSystemType(PortableUtils.TypeSerializableHolder, w => new SerializableObjectHolder(w)); + AddSystemType(PortableUtils.TypeDateTimeHolder, w => new DateTimeHolder(w)); AddSystemType(PortableUtils.TypeCacheEntryProcessorHolder, w => new CacheEntryProcessorHolder(w)); AddSystemType(PortableUtils.TypeCacheEntryPredicateHolder, w => new CacheEntryFilterHolder(w)); AddSystemType(PortableUtils.TypeMessageListenerHolder, w => new MessageListenerHolder(w)); http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs index 2d50499..422d628 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs @@ -109,7 +109,7 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public bool ReadBoolean(string fieldName) { - return ReadField(fieldName, r => r.ReadBoolean()); + return ReadField(fieldName, r => r.ReadBoolean(), PortableUtils.TypeBool); } /** <inheritdoc /> */ @@ -121,19 +121,19 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public bool[] ReadBooleanArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadBooleanArray); + return ReadField(fieldName, PortableUtils.ReadBooleanArray, PortableUtils.TypeArrayBool); } /** <inheritdoc /> */ public bool[] ReadBooleanArray() { - return Read(PortableUtils.ReadBooleanArray); + return Read(PortableUtils.ReadBooleanArray, PortableUtils.TypeArrayBool); } /** <inheritdoc /> */ public byte ReadByte(string fieldName) { - return ReadField(fieldName, ReadByte); + return ReadField(fieldName, ReadByte, PortableUtils.TypeByte); } /** <inheritdoc /> */ @@ -145,19 +145,19 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public byte[] ReadByteArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadByteArray); + return ReadField(fieldName, PortableUtils.ReadByteArray, PortableUtils.TypeArrayByte); } /** <inheritdoc /> */ public byte[] ReadByteArray() { - return Read(PortableUtils.ReadByteArray); + return Read(PortableUtils.ReadByteArray, PortableUtils.TypeArrayByte); } /** <inheritdoc /> */ public short ReadShort(string fieldName) { - return ReadField(fieldName, ReadShort); + return ReadField(fieldName, ReadShort, PortableUtils.TypeShort); } /** <inheritdoc /> */ @@ -169,19 +169,19 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public short[] ReadShortArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadShortArray); + return ReadField(fieldName, PortableUtils.ReadShortArray, PortableUtils.TypeArrayShort); } /** <inheritdoc /> */ public short[] ReadShortArray() { - return Read(PortableUtils.ReadShortArray); + return Read(PortableUtils.ReadShortArray, PortableUtils.TypeArrayShort); } /** <inheritdoc /> */ public char ReadChar(string fieldName) { - return ReadField(fieldName, ReadChar); + return ReadField(fieldName, ReadChar, PortableUtils.TypeChar); } /** <inheritdoc /> */ @@ -193,19 +193,19 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public char[] ReadCharArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadCharArray); + return ReadField(fieldName, PortableUtils.ReadCharArray, PortableUtils.TypeArrayChar); } /** <inheritdoc /> */ public char[] ReadCharArray() { - return Read(PortableUtils.ReadCharArray); + return Read(PortableUtils.ReadCharArray, PortableUtils.TypeArrayChar); } /** <inheritdoc /> */ public int ReadInt(string fieldName) { - return ReadField(fieldName, ReadInt); + return ReadField(fieldName, ReadInt, PortableUtils.TypeInt); } /** <inheritdoc /> */ @@ -217,19 +217,19 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public int[] ReadIntArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadIntArray); + return ReadField(fieldName, PortableUtils.ReadIntArray, PortableUtils.TypeArrayInt); } /** <inheritdoc /> */ public int[] ReadIntArray() { - return Read(PortableUtils.ReadIntArray); + return Read(PortableUtils.ReadIntArray, PortableUtils.TypeArrayInt); } /** <inheritdoc /> */ public long ReadLong(string fieldName) { - return ReadField(fieldName, ReadLong); + return ReadField(fieldName, ReadLong, PortableUtils.TypeLong); } /** <inheritdoc /> */ @@ -241,19 +241,19 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public long[] ReadLongArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadLongArray); + return ReadField(fieldName, PortableUtils.ReadLongArray, PortableUtils.TypeArrayLong); } /** <inheritdoc /> */ public long[] ReadLongArray() { - return Read(PortableUtils.ReadLongArray); + return Read(PortableUtils.ReadLongArray, PortableUtils.TypeArrayLong); } /** <inheritdoc /> */ public float ReadFloat(string fieldName) { - return ReadField(fieldName, ReadFloat); + return ReadField(fieldName, ReadFloat, PortableUtils.TypeFloat); } /** <inheritdoc /> */ @@ -265,19 +265,19 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public float[] ReadFloatArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadFloatArray); + return ReadField(fieldName, PortableUtils.ReadFloatArray, PortableUtils.TypeArrayFloat); } /** <inheritdoc /> */ public float[] ReadFloatArray() { - return Read(PortableUtils.ReadFloatArray); + return Read(PortableUtils.ReadFloatArray, PortableUtils.TypeArrayFloat); } /** <inheritdoc /> */ public double ReadDouble(string fieldName) { - return ReadField(fieldName, ReadDouble); + return ReadField(fieldName, ReadDouble, PortableUtils.TypeDouble); } /** <inheritdoc /> */ @@ -289,133 +289,133 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public double[] ReadDoubleArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadDoubleArray); + return ReadField(fieldName, PortableUtils.ReadDoubleArray, PortableUtils.TypeArrayDouble); } /** <inheritdoc /> */ public double[] ReadDoubleArray() { - return Read(PortableUtils.ReadDoubleArray); + return Read(PortableUtils.ReadDoubleArray, PortableUtils.TypeArrayDouble); } /** <inheritdoc /> */ public decimal? ReadDecimal(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadDecimal); + return ReadField(fieldName, PortableUtils.ReadDecimal, PortableUtils.TypeDecimal); } /** <inheritdoc /> */ public decimal? ReadDecimal() { - return Read(PortableUtils.ReadDecimal); + return Read(PortableUtils.ReadDecimal, PortableUtils.TypeDecimal); } /** <inheritdoc /> */ public decimal?[] ReadDecimalArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadDecimalArray); + return ReadField(fieldName, PortableUtils.ReadDecimalArray, PortableUtils.TypeArrayDecimal); } /** <inheritdoc /> */ public decimal?[] ReadDecimalArray() { - return Read(PortableUtils.ReadDecimalArray); + return Read(PortableUtils.ReadDecimalArray, PortableUtils.TypeArrayDecimal); } /** <inheritdoc /> */ public DateTime? ReadTimestamp(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadTimestamp); + return ReadField(fieldName, PortableUtils.ReadTimestamp, PortableUtils.TypeTimestamp); } /** <inheritdoc /> */ public DateTime? ReadTimestamp() { - return Read(PortableUtils.ReadTimestamp); + return Read(PortableUtils.ReadTimestamp, PortableUtils.TypeTimestamp); } /** <inheritdoc /> */ public DateTime?[] ReadTimestampArray(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadTimestampArray); + return ReadField(fieldName, PortableUtils.ReadTimestampArray, PortableUtils.TypeArrayTimestamp); } /** <inheritdoc /> */ public DateTime?[] ReadTimestampArray() { - return Read(PortableUtils.ReadTimestampArray); + return Read(PortableUtils.ReadTimestampArray, PortableUtils.TypeArrayTimestamp); } /** <inheritdoc /> */ public string ReadString(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadString); + return ReadField(fieldName, PortableUtils.ReadString, PortableUtils.TypeString); } /** <inheritdoc /> */ public string ReadString() { - return Read(PortableUtils.ReadString); + return Read(PortableUtils.ReadString, PortableUtils.TypeString); } /** <inheritdoc /> */ public string[] ReadStringArray(string fieldName) { - return ReadField(fieldName, r => PortableUtils.ReadArray<string>(r, false)); + return ReadField(fieldName, r => PortableUtils.ReadArray<string>(r, false), PortableUtils.TypeArrayString); } /** <inheritdoc /> */ public string[] ReadStringArray() { - return Read(r => PortableUtils.ReadArray<string>(r, false)); + return Read(r => PortableUtils.ReadArray<string>(r, false), PortableUtils.TypeArrayString); } /** <inheritdoc /> */ public Guid? ReadGuid(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadGuid); + return ReadField(fieldName, PortableUtils.ReadGuid, PortableUtils.TypeGuid); } /** <inheritdoc /> */ public Guid? ReadGuid() { - return Read(PortableUtils.ReadGuid); + return Read(PortableUtils.ReadGuid, PortableUtils.TypeGuid); } /** <inheritdoc /> */ public Guid?[] ReadGuidArray(string fieldName) { - return ReadField(fieldName, r => PortableUtils.ReadArray<Guid?>(r, false)); + return ReadField(fieldName, r => PortableUtils.ReadArray<Guid?>(r, false), PortableUtils.TypeArrayGuid); } /** <inheritdoc /> */ public Guid?[] ReadGuidArray() { - return Read(r => PortableUtils.ReadArray<Guid?>(r, false)); + return Read(r => PortableUtils.ReadArray<Guid?>(r, false), PortableUtils.TypeArrayGuid); } /** <inheritdoc /> */ public T ReadEnum<T>(string fieldName) { - return ReadField(fieldName, PortableUtils.ReadEnum<T>); + return ReadField(fieldName, PortableUtils.ReadEnum<T>, PortableUtils.TypeEnum); } /** <inheritdoc /> */ public T ReadEnum<T>() { - return Read(PortableUtils.ReadEnum<T>); + return Read(PortableUtils.ReadEnum<T>, PortableUtils.TypeEnum); } /** <inheritdoc /> */ public T[] ReadEnumArray<T>(string fieldName) { - return ReadField(fieldName, r => PortableUtils.ReadArray<T>(r, true)); + return ReadField(fieldName, r => PortableUtils.ReadArray<T>(r, true), PortableUtils.TypeArrayEnum); } /** <inheritdoc /> */ public T[] ReadEnumArray<T>() { - return Read(r => PortableUtils.ReadArray<T>(r, true)); + return Read(r => PortableUtils.ReadArray<T>(r, true), PortableUtils.TypeArrayEnum); } /** <inheritdoc /> */ @@ -441,13 +441,13 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public T[] ReadArray<T>(string fieldName) { - return ReadField(fieldName, r => PortableUtils.ReadArray<T>(r, true)); + return ReadField(fieldName, r => PortableUtils.ReadArray<T>(r, true), PortableUtils.TypeArray); } /** <inheritdoc /> */ public T[] ReadArray<T>() { - return Read(r => PortableUtils.ReadArray<T>(r, true)); + return Read(r => PortableUtils.ReadArray<T>(r, true), PortableUtils.TypeArray); } /** <inheritdoc /> */ @@ -466,14 +466,14 @@ namespace Apache.Ignite.Core.Impl.Portable public ICollection ReadCollection(string fieldName, PortableCollectionFactory factory, PortableCollectionAdder adder) { - return ReadField(fieldName, r => PortableUtils.ReadCollection(r, factory, adder)); + return ReadField(fieldName, r => PortableUtils.ReadCollection(r, factory, adder), PortableUtils.TypeCollection); } /** <inheritdoc /> */ public ICollection ReadCollection(PortableCollectionFactory factory, PortableCollectionAdder adder) { - return Read(r => PortableUtils.ReadCollection(r, factory, adder)); + return Read(r => PortableUtils.ReadCollection(r, factory, adder), PortableUtils.TypeCollection); } /** <inheritdoc /> */ @@ -491,13 +491,13 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public IDictionary ReadDictionary(string fieldName, PortableDictionaryFactory factory) { - return ReadField(fieldName, r => PortableUtils.ReadDictionary(r, factory)); + return ReadField(fieldName, r => PortableUtils.ReadDictionary(r, factory), PortableUtils.TypeDictionary); } /** <inheritdoc /> */ public IDictionary ReadDictionary(PortableDictionaryFactory factory) { - return Read(r => PortableUtils.ReadDictionary(r, factory)); + return Read(r => PortableUtils.ReadDictionary(r, factory), PortableUtils.TypeDictionary); } /// <summary> @@ -716,9 +716,18 @@ namespace Apache.Ignite.Core.Impl.Portable _curStruct = oldStruct; _curRaw = oldRaw; + // Process wrappers. We could introduce a common interface, but for only 2 if-else is faster. var wrappedSerializable = obj as SerializableObjectHolder; - return wrappedSerializable != null ? (T) wrappedSerializable.Item : (T) obj; + if (wrappedSerializable != null) + return (T) wrappedSerializable.Item; + + var wrappedDateTime = obj as DateTimeHolder; + + if (wrappedDateTime != null) + return TypeCaster<T>.Cast(wrappedDateTime.Item); + + return (T) obj; } } finally @@ -742,7 +751,7 @@ namespace Apache.Ignite.Core.Impl.Portable { object hndObj; - if (_builder == null || !_builder.CachedField(hndPos, out hndObj)) + if (_builder == null || !_builder.TryGetCachedField(hndPos, out hndObj)) { if (_hnds == null || !_hnds.TryGetValue(hndPos, out hndObj)) { @@ -861,17 +870,24 @@ namespace Apache.Ignite.Core.Impl.Portable /// <summary> /// Determines whether header at current position is HDR_NULL. /// </summary> - private bool IsNullHeader() + private bool IsNotNullHeader(byte expHdr) { var hdr = ReadByte(); + + if (hdr == PortableUtils.HdrNull) + return false; + + if (expHdr != hdr) + throw new PortableException(string.Format("Invalid header on deserialization. " + + "Expected: {0} but was: {1}", expHdr, hdr)); - return hdr != PortableUtils.HdrNull; + 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) + private bool SeekField(string fieldName, byte expHdr) { if (_curRaw) throw new PortableException("Cannot read named fields after raw data is read."); @@ -881,47 +897,47 @@ namespace Apache.Ignite.Core.Impl.Portable if (!SeekField(fieldId)) return false; - return IsNullHeader(); + return IsNotNullHeader(expHdr); } /// <summary> /// Seeks specified field and invokes provided func. /// </summary> - private T ReadField<T>(string fieldName, Func<IPortableStream, T> readFunc) + private T ReadField<T>(string fieldName, Func<IPortableStream, T> readFunc, byte expHdr) { - return SeekField(fieldName) ? readFunc(Stream) : default(T); + return SeekField(fieldName, expHdr) ? readFunc(Stream) : default(T); } /// <summary> /// Seeks specified field and invokes provided func. /// </summary> - private T ReadField<T>(string fieldName, Func<PortableReaderImpl, T> readFunc) + private T ReadField<T>(string fieldName, Func<PortableReaderImpl, T> readFunc, byte expHdr) { - return SeekField(fieldName) ? readFunc(this) : default(T); + return SeekField(fieldName, expHdr) ? readFunc(this) : default(T); } /// <summary> /// Seeks specified field and invokes provided func. /// </summary> - private T ReadField<T>(string fieldName, Func<T> readFunc) + private T ReadField<T>(string fieldName, Func<T> readFunc, byte expHdr) { - return SeekField(fieldName) ? readFunc() : default(T); + return SeekField(fieldName, expHdr) ? readFunc() : default(T); } /// <summary> /// Reads header and invokes specified func if the header is not null. /// </summary> - private T Read<T>(Func<PortableReaderImpl, T> readFunc) + private T Read<T>(Func<PortableReaderImpl, T> readFunc, byte expHdr) { - return IsNullHeader() ? readFunc(this) : default(T); + return IsNotNullHeader(expHdr) ? readFunc(this) : default(T); } /// <summary> /// Reads header and invokes specified func if the header is not null. /// </summary> - private T Read<T>(Func<IPortableStream, T> readFunc) + private T Read<T>(Func<IPortableStream, T> readFunc, byte expHdr) { - return IsNullHeader() ? readFunc(Stream) : default(T); + return IsNotNullHeader(expHdr) ? readFunc(Stream) : default(T); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReflectiveRoutines.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReflectiveRoutines.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReflectiveRoutines.cs index d79cc0b..4aff797 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReflectiveRoutines.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReflectiveRoutines.cs @@ -254,11 +254,6 @@ namespace Apache.Ignite.Core.Impl.Portable writeAction = GetWriter<Guid?[]>(field, (f, w, o) => w.WriteGuidArray(f, o)); readAction = GetReader(field, (f, r) => r.ReadGuidArray(f)); } - else if (elemType == typeof(DateTime?)) - { - writeAction = GetWriter<DateTime?[]>(field, (f, w, o) => w.WriteTimestampArray(f, o)); - readAction = GetReader(field, (f, r) => r.ReadTimestampArray(f)); - } else if (elemType.IsEnum) { writeAction = GetWriter(field, MthdWriteEnumArray, elemType); @@ -308,16 +303,6 @@ namespace Apache.Ignite.Core.Impl.Portable writeAction = GetWriter<Guid?>(field, (f, w, o) => w.WriteGuid(f, o)); readAction = GetReader(field, (f, r) => r.ReadGuid(f)); } - else if (type == typeof(DateTime)) - { - writeAction = GetWriter<DateTime>(field, (f, w, o) => w.WriteTimestamp(f, o)); - readAction = GetReader(field, (f, r) => r.ReadTimestamp(f)); - } - else if (nullable && nullableType == typeof(DateTime)) - { - writeAction = GetWriter<DateTime?>(field, (f, w, o) => w.WriteTimestamp(f, o)); - readAction = GetReader(field, (f, r) => r.ReadTimestamp(f)); - } else if (type.IsEnum) { writeAction = GetWriter<object>(field, (f, w, o) => w.WriteEnum(f, o), true); http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSystemHandlers.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSystemHandlers.cs index ed2e9ea..dabe5c8 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSystemHandlers.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSystemHandlers.cs @@ -42,10 +42,50 @@ namespace Apache.Ignite.Core.Impl.Portable new Dictionary<Type, PortableSystemWriteDelegate>(); /** Mutex for write handlers update. */ - private static readonly Object WriteHandlersMux = new Object(); + private static readonly object WriteHandlersMux = new object(); /** Read handlers. */ private static readonly IPortableSystemReader[] ReadHandlers = new IPortableSystemReader[255]; + + /** Type ids. */ + private static readonly Dictionary<Type, byte> TypeIds = new Dictionary<Type, byte> + { + {typeof (bool), PortableUtils.TypeBool}, + {typeof (byte), PortableUtils.TypeByte}, + {typeof (sbyte), PortableUtils.TypeByte}, + {typeof (short), PortableUtils.TypeShort}, + {typeof (ushort), PortableUtils.TypeShort}, + {typeof (char), PortableUtils.TypeChar}, + {typeof (int), PortableUtils.TypeInt}, + {typeof (uint), PortableUtils.TypeInt}, + {typeof (long), PortableUtils.TypeLong}, + {typeof (ulong), PortableUtils.TypeLong}, + {typeof (float), PortableUtils.TypeFloat}, + {typeof (double), PortableUtils.TypeDouble}, + {typeof (string), PortableUtils.TypeString}, + {typeof (decimal), PortableUtils.TypeDecimal}, + {typeof (Guid), PortableUtils.TypeGuid}, + {typeof (Guid?), PortableUtils.TypeGuid}, + {typeof (ArrayList), PortableUtils.TypeCollection}, + {typeof (Hashtable), PortableUtils.TypeDictionary}, + {typeof (DictionaryEntry), PortableUtils.TypeMapEntry}, + {typeof (bool[]), PortableUtils.TypeArrayBool}, + {typeof (byte[]), PortableUtils.TypeArrayByte}, + {typeof (sbyte[]), PortableUtils.TypeArrayByte}, + {typeof (short[]), PortableUtils.TypeArrayShort}, + {typeof (ushort[]), PortableUtils.TypeArrayShort}, + {typeof (char[]), PortableUtils.TypeArrayChar}, + {typeof (int[]), PortableUtils.TypeArrayInt}, + {typeof (uint[]), PortableUtils.TypeArrayInt}, + {typeof (long[]), PortableUtils.TypeArrayLong}, + {typeof (ulong[]), PortableUtils.TypeArrayLong}, + {typeof (float[]), PortableUtils.TypeArrayFloat}, + {typeof (double[]), PortableUtils.TypeArrayDouble}, + {typeof (string[]), PortableUtils.TypeArrayString}, + {typeof (decimal?[]), PortableUtils.TypeArrayDecimal}, + {typeof (Guid?[]), PortableUtils.TypeArrayGuid}, + {typeof (object[]), PortableUtils.TypeArray} + }; /// <summary> /// Initializes the <see cref="PortableSystemHandlers"/> class. @@ -214,8 +254,6 @@ namespace Apache.Ignite.Core.Impl.Portable return WriteDecimalArray; if (elemType == typeof(string)) return WriteStringArray; - if (elemType == typeof(DateTime?)) - return WriteTimestampArray; if (elemType == typeof(Guid?)) return WriteGuidArray; // Enums. @@ -231,10 +269,34 @@ namespace Apache.Ignite.Core.Impl.Portable // We know how to write enums. return WriteEnum; + if (type.IsSerializable) + return WriteSerializable; + return null; } /// <summary> + /// Find write handler for type. + /// </summary> + /// <param name="type">Type.</param> + /// <returns>Write handler or NULL.</returns> + public static byte GetTypeId(Type type) + { + byte res; + + if (TypeIds.TryGetValue(type, out res)) + return res; + + if (type.IsEnum) + return PortableUtils.TypeEnum; + + if (type.IsArray && type.GetElementType().IsEnum) + return PortableUtils.TypeArrayEnum; + + return PortableUtils.TypeObject; + } + + /// <summary> /// Add write handler for type. /// </summary> /// <param name="type"></param> @@ -295,9 +357,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// <param name="obj">Value.</param> private static void WriteDate(PortableWriterImpl ctx, object obj) { - ctx.Stream.WriteByte(PortableUtils.TypeTimestamp); - - PortableUtils.WriteTimestamp((DateTime)obj, ctx.Stream); + ctx.Write(new DateTimeHolder((DateTime) obj)); } /// <summary> @@ -481,18 +541,6 @@ namespace Apache.Ignite.Core.Impl.Portable } /// <summary> - /// Write nullable date array. - /// </summary> - /// <param name="ctx">Context.</param> - /// <param name="obj">Value.</param> - private static void WriteTimestampArray(PortableWriterImpl ctx, object obj) - { - ctx.Stream.WriteByte(PortableUtils.TypeArrayTimestamp); - - PortableUtils.WriteTimestampArray((DateTime?[])obj, ctx.Stream); - } - - /// <summary> /// Write string array. /// </summary> /// <param name="ctx">Context.</param> @@ -586,6 +634,16 @@ namespace Apache.Ignite.Core.Impl.Portable PortableUtils.WriteEnum(ctx.Stream, (Enum)obj); } + /// <summary> + /// Writes serializable. + /// </summary> + /// <param name="writer">The writer.</param> + /// <param name="o">The object.</param> + private static void WriteSerializable(PortableWriterImpl writer, object o) + { + writer.Write(new SerializableObjectHolder(o)); + } + /** * <summary>Read enum array.</summary> */ http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs index 9df180d..c241b96 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs @@ -80,7 +80,24 @@ namespace Apache.Ignite.Core.Impl.Portable /** <inheritdoc /> */ public T GetField<T>(string fieldName) { - return Field<T>(fieldName, null); + int pos; + + return TryGetFieldPosition(fieldName, out pos) ? GetField<T>(pos, null) : default(T); + } + + /// <summary> + /// Gets field value on the given object. + /// </summary> + /// <param name="pos">Position.</param> + /// <param name="builder">Builder.</param> + /// <returns>Field value.</returns> + public T GetField<T>(int pos, PortableBuilderImpl builder) + { + IPortableStream stream = new PortableHeapStream(_data); + + stream.Seek(pos, SeekOrigin.Begin); + + return _marsh.Unmarshal<T>(stream, PortableMode.ForcePortable, builder); } /** <inheritdoc /> */ @@ -139,42 +156,15 @@ namespace Apache.Ignite.Core.Impl.Portable get { return _offset; } } - /// <summary> - /// Get field with builder. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="fieldName"></param> - /// <param name="builder"></param> - /// <returns></returns> - public T Field<T>(string fieldName, PortableBuilderImpl builder) + public bool TryGetFieldPosition(string fieldName, out int pos) { - IPortableTypeDescriptor desc = _marsh.GetDescriptor(true, _typeId); + var desc = _marsh.GetDescriptor(true, _typeId); InitializeFields(); int fieldId = PortableUtils.FieldId(_typeId, fieldName, desc.NameConverter, desc.Mapper); - int pos; - - if (_fields.TryGetValue(fieldId, out pos)) - { - if (builder != null) - { - // Read in scope of build process. - T res; - - if (!builder.CachedField(pos, out res)) - { - res = Field0<T>(pos, builder); - - builder.CacheField(pos, res); - } - - return res; - } - return Field0<T>(pos, null); - } - return default(T); + return _fields.TryGetValue(fieldId, out pos); } /// <summary> @@ -194,21 +184,6 @@ namespace Apache.Ignite.Core.Impl.Portable } } - /// <summary> - /// Gets field value on the given object. - /// </summary> - /// <param name="pos">Position.</param> - /// <param name="builder">Builder.</param> - /// <returns>Field value.</returns> - private T Field0<T>(int pos, PortableBuilderImpl builder) - { - IPortableStream stream = new PortableHeapStream(_data); - - stream.Seek(pos, SeekOrigin.Begin); - - return _marsh.Unmarshal<T>(stream, PortableMode.ForcePortable, builder); - } - /** <inheritdoc /> */ public override int GetHashCode() { @@ -247,8 +222,8 @@ namespace Apache.Ignite.Core.Impl.Portable // 3. Check if objects have the same field values. foreach (KeyValuePair<int, int> field in _fields) { - object fieldVal = Field0<object>(field.Value, null); - object thatFieldVal = that.Field0<object>(that._fields[field.Key], null); + object fieldVal = GetField<object>(field.Value, null); + object thatFieldVal = that.GetField<object>(that._fields[field.Key], null); if (!Equals(fieldVal, thatFieldVal)) return false; @@ -332,7 +307,7 @@ namespace Apache.Ignite.Core.Impl.Portable { sb.Append(fieldName).Append('='); - ToString0(sb, Field0<object>(fieldPos, null), handled); + ToString0(sb, GetField<object>(fieldPos, null), handled); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs index dd72a8c..c9d6172 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs @@ -26,8 +26,6 @@ namespace Apache.Ignite.Core.Impl.Portable using System.IO; using System.Reflection; using System.Runtime.InteropServices; - using System.Runtime.Serialization.Formatters.Binary; - using System.Security.Policy; using System.Text; using Apache.Ignite.Core.Impl.Common; @@ -189,9 +187,12 @@ namespace Apache.Ignite.Core.Impl.Portable /** Type: Compute job wrapper. */ public const byte TypeComputeJobWrapper = 86; - /** Type: Compute job wrapper. */ + /** Type: Serializable wrapper. */ public const byte TypeSerializableHolder = 87; + /** Type: DateTime wrapper. */ + public const byte TypeDateTimeHolder = 93; + /** Type: action wrapper. */ public const byte TypeComputeActionJob = 88; @@ -204,15 +205,9 @@ namespace Apache.Ignite.Core.Impl.Portable /** Type: message filter holder. */ public const byte TypeMessageListenerHolder = 92; - /** Type: message filter holder. */ - public const byte TypePortableOrSerializableHolder = 93; - /** Type: stream receiver holder. */ public const byte TypeStreamReceiverHolder = 94; - /** Type: DateTime. */ - public const byte TypeDateTime = 95; - /** Collection: custom. */ public const byte CollectionCustom = 0; @@ -1753,7 +1748,11 @@ namespace Apache.Ignite.Core.Impl.Portable */ private static void ToJavaDate(DateTime date, out long high, out int low) { - long diff = date.ToUniversalTime().Ticks - JavaDateTicks; + if (date.Kind != DateTimeKind.Utc) + throw new InvalidOperationException( + "DateTime is not UTC. Only UTC DateTime can be used for interop with other platforms."); + + long diff = date.Ticks - JavaDateTicks; high = diff / TimeSpan.TicksPerMillisecond; http://git-wip-us.apache.org/repos/asf/ignite/blob/05e739f1/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs index d5fb6ec..ab7adaa 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs @@ -951,6 +951,15 @@ namespace Apache.Ignite.Core.Impl.Portable /// <param name="val">Object array.</param> public void WriteArray<T>(T[] val) { + WriteArrayInternal(val); + } + + /// <summary> + /// Write object array. + /// </summary> + /// <param name="val">Object array.</param> + public void WriteArrayInternal(Array val) + { if (val == null) WriteNullRawField(); else @@ -1025,7 +1034,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// <summary> /// Write NULL field. /// </summary> - public void WriteNullField() + private void WriteNullField() { _stream.WriteInt(1); _stream.WriteByte(PU.HdrNull); @@ -1034,7 +1043,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// <summary> /// Write NULL raw field. /// </summary> - public void WriteNullRawField() + private void WriteNullRawField() { _stream.WriteByte(PU.HdrNull); } @@ -1173,18 +1182,12 @@ namespace Apache.Ignite.Core.Impl.Portable else { // Are we dealing with a well-known type? - PortableSystemWriteDelegate handler = PortableSystemHandlers.GetWriteHandler(type); + var handler = PortableSystemHandlers.GetWriteHandler(type); - if (handler != null) - handler.Invoke(this, obj); - else - { - if (type.IsSerializable) - Write(new SerializableObjectHolder(obj)); - else - // We did our best, object cannot be marshalled. - throw new PortableException("Unsupported object type [type=" + type + ", object=" + obj + ']'); - } + if (handler == null) // We did our best, object cannot be marshalled. + throw new PortableException("Unsupported object type [type=" + type + ", object=" + obj + ']'); + + handler(this, obj); } } @@ -1193,7 +1196,7 @@ namespace Apache.Ignite.Core.Impl.Portable /// </summary> /// <param name="val">Object.</param> /// <param name="type">Type.</param> - public unsafe void WritePrimitive<T>(T val, Type type) + private unsafe void WritePrimitive<T>(T val, Type type) { // .Net defines 14 primitive types. We support 12 - excluding IntPtr and UIntPtr. // Types check sequence is designed to minimize comparisons for the most frequent types.
