You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/10/22 11:27:38 UTC
[46/50] [abbrv] ignite git commit: Merge branch 'ignite-1282' into
ignite-1651
http://git-wip-us.apache.org/repos/asf/ignite/blob/ec58b87c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
----------------------------------------------------------------------
diff --cc modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
index 0000000,c65038c..17d7cc6
mode 000000,100644..100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
@@@ -1,0 -1,915 +1,918 @@@
+ /*
+ * 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.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.IO;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+ using Apache.Ignite.Core.Impl.Portable.Metadata;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Portable builder implementation.
+ /// </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>();
+
+ /** Offset: length. */
+ private const int OffsetLen = 10;
+
+ /** Portables. */
+ private readonly PortablesImpl _portables;
+
+ /** */
+ private readonly PortableBuilderImpl _parent;
+
+ /** Initial portable object. */
+ private readonly PortableUserObject _obj;
+
+ /** Type descriptor. */
+ private readonly IPortableTypeDescriptor _desc;
+
+ /** Values. */
+ private IDictionary<string, PortableBuilderField> _vals;
+
+ /** Contextual fields. */
+ private IDictionary<int, object> _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.TypeGuid;
+ TypeIds[typeof(Guid[])] = PortableUtils.TypeArrayGuid;
+ TypeIds[typeof(Guid?[])] = PortableUtils.TypeArrayGuid;
+
+ // 4. Date.
+ TypeIds[typeof(DateTime)] = PortableUtils.TypeDate;
+ TypeIds[typeof(DateTime?)] = PortableUtils.TypeDate;
+ TypeIds[typeof(DateTime[])] = PortableUtils.TypeArrayDate;
+ TypeIds[typeof(DateTime?[])] = PortableUtils.TypeArrayDate;
+ }
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="portables">Portables.</param>
+ /// <param name="parent">Parent builder.</param>
+ /// <param name="obj">Initial portable object.</param>
+ /// <param name="desc">Type descriptor.</param>
+ public PortableBuilderImpl(PortablesImpl portables, PortableBuilderImpl parent,
+ PortableUserObject obj, IPortableTypeDescriptor desc)
+ {
+ _portables = portables;
+ _parent = parent ?? this;
+ _obj = obj;
+ _desc = desc;
+
+ _hashCode = obj.GetHashCode();
+ }
+
+ /** <inheritDoc /> */
+ public IPortableBuilder SetHashCode(int hashCode)
+ {
+ _hashCode = hashCode;
+
+ return this;
+ }
+
+ /** <inheritDoc /> */
+ public T GetField<T>(string name)
+ {
+ 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);
+
+ if (_vals == null)
+ _vals = new Dictionary<string, PortableBuilderField>(2);
+
+ _vals[name] = new PortableBuilderField(typeof(T), val);
+
+ return val;
+ }
+
+ /** <inheritDoc /> */
+ public IPortableBuilder SetField<T>(string name, T val)
+ {
+ return SetField0(name, new PortableBuilderField(typeof(T), val));
+ }
+
+ /** <inheritDoc /> */
+ public IPortableBuilder RemoveField(string name)
+ {
+ return SetField0(name, PortableBuilderField.RmvMarker);
+ }
+
+ /** <inheritDoc /> */
+ public IPortableObject Build()
+ {
+ PortableHeapStream inStream = new PortableHeapStream(_obj.Data);
+
+ inStream.Seek(_obj.Offset, SeekOrigin.Begin);
+
+ // Assume that resulting length will be no less than header + [fields_cnt] * 12;
+ int len = PortableUtils.FullHdrLen + (_vals == null ? 0 : _vals.Count * 12);
+
+ PortableHeapStream outStream = new PortableHeapStream(len);
+
+ PortableWriterImpl writer = _portables.Marshaller.StartMarshal(outStream);
+
+ writer.Builder(this);
+
+ // All related builders will work in this context with this writer.
+ _parent._ctx = new Context(writer);
+
+ try
+ {
+ // Write.
+ writer.Write(this);
+
+ // Process metadata.
+ _portables.Marshaller.FinishMarshal(writer);
+
+ // Create portable object once metadata is processed.
+ return new PortableUserObject(_portables.Marshaller, outStream.InternalArray, 0,
+ _desc.TypeId, _hashCode);
+ }
+ finally
+ {
+ // Cleanup.
+ _parent._ctx.Closed = true;
+ }
+ }
+
+ /// <summary>
+ /// Create child builder.
+ /// </summary>
+ /// <param name="obj">Portable object.</param>
+ /// <returns>Child builder.</returns>
+ public PortableBuilderImpl Child(PortableUserObject obj)
+ {
+ var desc = _portables.Marshaller.GetDescriptor(true, obj.TypeId);
+
+ return new PortableBuilderImpl(_portables, null, obj, desc);
+ }
+
+ /// <summary>
+ /// Get cache field.
+ /// </summary>
+ /// <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)
+ {
+ if (_parent._cache != null)
+ {
+ object res;
+
+ if (_parent._cache.TryGetValue(pos, out res))
+ {
+ val = res != null ? (T)res : default(T);
+
+ return true;
+ }
+ }
+
+ val = default(T);
+
+ return false;
+ }
+
+ /// <summary>
+ /// Add field to cache test.
+ /// </summary>
+ /// <param name="pos">Position.</param>
+ /// <param name="val">Value.</param>
+ public void CacheField(int pos, object val)
+ {
+ if (_parent._cache == null)
+ _parent._cache = new Dictionary<int, object>(2);
+
+ _parent._cache[pos] = val;
+ }
+
+ /// <summary>
+ /// Internal set field routine.
+ /// </summary>
+ /// <param name="fieldName">Name.</param>
+ /// <param name="val">Value.</param>
+ /// <returns>This builder.</returns>
+ private IPortableBuilder SetField0(string fieldName, PortableBuilderField val)
+ {
+ if (_vals == null)
+ _vals = new Dictionary<string, PortableBuilderField>();
+
+ _vals[fieldName] = val;
+
+ return this;
+ }
+
+ /// <summary>
+ /// Mutate portable object.
+ /// </summary>
+ /// <param name="inStream">Input stream with initial object.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="desc">Portable type descriptor.</param>
+ /// <param name="hashCode">Hash code.</param>
+ /// <param name="vals">Values.</param>
+ internal void Mutate(
+ PortableHeapStream inStream,
+ PortableHeapStream outStream,
+ IPortableTypeDescriptor desc,
+ int hashCode,
+ IDictionary<string, PortableBuilderField> vals)
+ {
+ // Set correct builder to writer frame.
+ PortableBuilderImpl oldBuilder = _parent._ctx.Writer.Builder(_parent);
+
+ int streamPos = inStream.Position;
+
+ try
+ {
+ // Prepare fields.
+ IPortableMetadataHandler metaHnd = _portables.Marshaller.GetMetadataHandler(desc);
+
+ IDictionary<int, object> vals0;
+
+ if (vals == null || vals.Count == 0)
+ vals0 = EmptyVals;
+ else
+ {
+ vals0 = new Dictionary<int, object>(vals.Count);
+
+ foreach (KeyValuePair<string, PortableBuilderField> valEntry in vals)
+ {
+ int fieldId = PortableUtils.FieldId(desc.TypeId, valEntry.Key, desc.NameConverter, desc.Mapper);
+
+ if (vals0.ContainsKey(fieldId))
+ 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;
+
+ // 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, TypeId(valEntry.Value.Type));
+ }
+ }
+
+ // Actual processing.
+ Mutate0(_parent._ctx, inStream, outStream, true, hashCode, vals0);
+
+ // 3. Handle metadata.
+ if (metaHnd != null)
+ {
+ IDictionary<string, int> meta = metaHnd.OnObjectWriteFinished();
+
+ if (meta != null)
+ _parent._ctx.Writer.SaveMetadata(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, meta);
+ }
+ }
+ finally
+ {
+ // Restore builder frame.
+ _parent._ctx.Writer.Builder(oldBuilder);
+
+ inStream.Seek(streamPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Internal mutation routine.
+ /// </summary>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="ctx">Context.</param>
+ /// <param name="changeHash">WHether hash should be changed.</param>
+ /// <param name="hash">New hash.</param>
+ /// <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)
+ {
+ int inStartPos = inStream.Position;
+ int outStartPos = outStream.Position;
+
+ byte inHdr = inStream.ReadByte();
+
+ if (inHdr == PortableUtils.HdrNull)
+ outStream.WriteByte(PortableUtils.HdrNull);
+ else if (inHdr == PortableUtils.HdrHnd)
+ {
+ int inHnd = inStream.ReadInt();
+
+ int oldPos = inStartPos - inHnd;
+ int newPos;
+
+ if (ctx.OldToNew(oldPos, out newPos))
+ {
+ // Handle is still valid.
+ outStream.WriteByte(PortableUtils.HdrHnd);
+ outStream.WriteInt(outStartPos - newPos);
+ }
+ else
+ {
+ // Handle is invalid, write full object.
+ int inRetPos = inStream.Position;
+
+ inStream.Seek(oldPos, SeekOrigin.Begin);
+
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+ inStream.Seek(inRetPos, SeekOrigin.Begin);
+ }
+ }
+ else if (inHdr == PortableUtils.HdrFull)
+ {
++ PortableUtils.ValidateProtocolVersion(inStream);
++
+ byte inUsrFlag = inStream.ReadByte();
+ int inTypeId = inStream.ReadInt();
+ int inHash = inStream.ReadInt();
+ int inLen = inStream.ReadInt();
+ int inRawOff = inStream.ReadInt();
+
+ int hndPos;
+
+ if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos))
+ {
+ // Object could be cached in parent builder.
+ object cachedVal;
+
+ if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) {
+ ctx.Writer.Write(cachedVal);
+ }
+ else
+ {
+ // New object, write in full form.
+ outStream.WriteByte(PortableUtils.HdrFull);
++ outStream.WriteByte(PortableUtils.ProtoVer);
+ outStream.WriteByte(inUsrFlag);
+ outStream.WriteInt(inTypeId);
+ outStream.WriteInt(changeHash ? hash : inHash);
+
+ // Skip length and raw offset as they are not known at this point.
+ outStream.Seek(8, SeekOrigin.Current);
+
+ // Write regular fields.
+ while (inStream.Position < inStartPos + inRawOff)
+ {
+ int inFieldId = inStream.ReadInt();
+ int inFieldLen = inStream.ReadInt();
+ int inFieldDataPos = inStream.Position;
+
+ object fieldVal;
+
+ bool fieldFound = vals.TryGetValue(inFieldId, out fieldVal);
+
+ if (!fieldFound || fieldVal != PortableBuilderField.RmvMarkerObj)
+ {
+ outStream.WriteInt(inFieldId);
+
+ int fieldLenPos = outStream.Position; // Here we will write length later.
+
+ outStream.Seek(4, SeekOrigin.Current);
+
+ if (fieldFound)
+ {
+ // Replace field with new value.
+ if (fieldVal != PortableBuilderField.RmvMarkerObj)
+ ctx.Writer.Write(fieldVal);
+
+ vals.Remove(inFieldId);
+ }
+ else
+ {
+ // 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);
+ else
+ // Filed is not tracked, re-write as is.
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ }
+
+ int fieldEndPos = outStream.Position;
+
+ outStream.Seek(fieldLenPos, SeekOrigin.Begin);
+ outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
+ outStream.Seek(fieldEndPos, SeekOrigin.Begin);
+ }
+
+ // Position intput stream pointer after the field.
+ inStream.Seek(inFieldDataPos + inFieldLen, SeekOrigin.Begin);
+ }
+
+ // Write remaining new fields.
+ foreach (KeyValuePair<int, object> valEntry in vals)
+ {
+ if (valEntry.Value != PortableBuilderField.RmvMarkerObj)
+ {
+ outStream.WriteInt(valEntry.Key);
+
+ int fieldLenPos = outStream.Position; // Here we will write length later.
+
+ outStream.Seek(4, SeekOrigin.Current);
+
+ ctx.Writer.Write(valEntry.Value);
+
+ int fieldEndPos = outStream.Position;
+
+ outStream.Seek(fieldLenPos, SeekOrigin.Begin);
+ outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
+ outStream.Seek(fieldEndPos, SeekOrigin.Begin);
+ }
+ }
+
+ // Write raw data.
+ int rawPos = outStream.Position;
+
+ outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inLen - inRawOff);
+
+ // Write length and raw data offset.
+ int outResPos = outStream.Position;
+
+ outStream.Seek(outStartPos + OffsetLen, SeekOrigin.Begin);
+
+ outStream.WriteInt(outResPos - outStartPos); // Length.
+ outStream.WriteInt(rawPos - outStartPos); // Raw offset.
+
+ outStream.Seek(outResPos, SeekOrigin.Begin);
+ }
+ }
+ else
+ {
+ // Object has already been written, write as handle.
+ outStream.WriteByte(PortableUtils.HdrHnd);
+ outStream.WriteInt(outStartPos - hndPos);
+ }
+
+ // Synchronize input stream position.
+ inStream.Seek(inStartPos + inLen, SeekOrigin.Begin);
+ }
+ else
+ {
+ // Try writing as well-known type with fixed size.
+ outStream.WriteByte(inHdr);
+
+ if (!WriteAsPredefined(inHdr, inStream, outStream, ctx))
+ throw new IgniteException("Unexpected header [position=" + (inStream.Position - 1) +
+ ", header=" + inHdr + ']');
+ }
+ }
+
+ /// <summary>
+ /// Process portable object inverting handles if needed.
+ /// </summary>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="port">Portable.</param>
+ internal void ProcessPortable(IPortableStream outStream, PortableUserObject port)
+ {
+ // Special case: writing portable object with correct inversions.
+ PortableHeapStream inStream = new PortableHeapStream(port.Data);
+
+ inStream.Seek(port.Offset, SeekOrigin.Begin);
+
+ // Use fresh context to ensure correct portable inversion.
+ Mutate0(new Context(), inStream, outStream, false, 0, EmptyVals);
+ }
+
+ /// <summary>
+ /// Process child builder.
+ /// </summary>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="builder">Builder.</param>
+ internal void ProcessBuilder(IPortableStream outStream, PortableBuilderImpl builder)
+ {
+ PortableHeapStream inStream = new PortableHeapStream(builder._obj.Data);
+
+ inStream.Seek(builder._obj.Offset, SeekOrigin.Begin);
+
+ // Builder parent context might be null only in one case: if we never met this group of
+ // builders before. In this case we set context to their parent and track it. Context
+ // cleanup will be performed at the very end of build process.
+ if (builder._parent._ctx == null || builder._parent._ctx.Closed)
+ builder._parent._ctx = new Context(_parent._ctx);
+
+ builder.Mutate(inStream, outStream as PortableHeapStream, builder._desc,
+ builder._hashCode, builder._vals);
+ }
+
+ /// <summary>
+ /// Write object as a predefined type if possible.
+ /// </summary>
+ /// <param name="hdr">Header.</param>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="ctx">Context.</param>
+ /// <returns><c>True</c> if was written.</returns>
+ private bool WriteAsPredefined(byte hdr, PortableHeapStream inStream, IPortableStream outStream,
+ Context ctx)
+ {
+ switch (hdr)
+ {
+ case PortableUtils.TypeByte:
+ TransferBytes(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeShort:
+ TransferBytes(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeInt:
+ TransferBytes(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeLong:
+ TransferBytes(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeFloat:
+ TransferBytes(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeDouble:
+ TransferBytes(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeChar:
+ TransferBytes(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeBool:
+ TransferBytes(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeDecimal:
+ TransferBytes(inStream, outStream, 4); // Transfer scale
+
+ int magLen = inStream.ReadInt(); // Transfer magnitude length.
+
+ outStream.WriteInt(magLen);
+
+ TransferBytes(inStream, outStream, magLen); // Transfer magnitude.
+
+ break;
+
+ case PortableUtils.TypeString:
+ PortableUtils.WriteString(PortableUtils.ReadString(inStream), outStream);
+
+ break;
+
+ case PortableUtils.TypeGuid:
+ TransferBytes(inStream, outStream, 16);
+
+ break;
+
+ case PortableUtils.TypeDate:
+ TransferBytes(inStream, outStream, 12);
+
+ break;
+
+ case PortableUtils.TypeArrayByte:
+ TransferArray(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeArrayShort:
+ TransferArray(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeArrayInt:
+ TransferArray(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeArrayLong:
+ TransferArray(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeArrayFloat:
+ TransferArray(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeArrayDouble:
+ TransferArray(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeArrayChar:
+ TransferArray(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeArrayBool:
+ TransferArray(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeArrayDecimal:
+ case PortableUtils.TypeArrayString:
+ case PortableUtils.TypeArrayGuid:
+ case PortableUtils.TypeArrayDate:
+ case PortableUtils.TypeArrayEnum:
+ case PortableUtils.TypeArray:
+ int arrLen = inStream.ReadInt();
+
+ outStream.WriteInt(arrLen);
+
+ for (int i = 0; i < arrLen; i++)
+ Mutate0(ctx, inStream, outStream, false, 0, null);
+
+ break;
+
+ case PortableUtils.TypeCollection:
+ int colLen = inStream.ReadInt();
+
+ outStream.WriteInt(colLen);
+
+ outStream.WriteByte(inStream.ReadByte());
+
+ for (int i = 0; i < colLen; i++)
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+ break;
+
+ case PortableUtils.TypeDictionary:
+ int dictLen = inStream.ReadInt();
+
+ outStream.WriteInt(dictLen);
+
+ outStream.WriteByte(inStream.ReadByte());
+
+ for (int i = 0; i < dictLen; i++)
+ {
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ }
+
+ break;
+
+ case PortableUtils.TypeMapEntry:
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+ break;
+
+ case PortableUtils.TypePortable:
+ TransferArray(inStream, outStream, 1); // Data array.
+ TransferBytes(inStream, outStream, 4); // Offset in array.
+
+ break;
+
+ case PortableUtils.TypeEnum:
+ TransferBytes(inStream, outStream, 4); // Integer ordinal.
+
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Get's metadata field type ID for the given type.
+ /// </summary>
+ /// <param name="type">Type.</param>
+ /// <returns>Type ID.</returns>
+ private static int TypeId(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;
+ PortableCollectionInfo colInfo = PortableCollectionInfo.Info(type);
+
+ return colInfo.IsAny ? colInfo.IsCollection || colInfo.IsGenericCollection ?
+ PortableUtils.TypeCollection : PortableUtils.TypeDictionary : PortableUtils.TypeObject;
+ }
+
+ /// <summary>
+ /// Transfer bytes from one stream to another.
+ /// </summary>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="cnt">Bytes count.</param>
+ private static void TransferBytes(PortableHeapStream inStream, IPortableStream outStream, int cnt)
+ {
+ outStream.Write(inStream.InternalArray, inStream.Position, cnt);
+
+ inStream.Seek(cnt, SeekOrigin.Current);
+ }
+
+ /// <summary>
+ /// Transfer array of fixed-size elements from one stream to another.
+ /// </summary>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="elemSize">Element size.</param>
+ private static void TransferArray(PortableHeapStream inStream, IPortableStream outStream,
+ int elemSize)
+ {
+ int len = inStream.ReadInt();
+
+ outStream.WriteInt(len);
+
+ TransferBytes(inStream, outStream, elemSize * len);
+ }
+
+ /// <summary>
+ /// Mutation ocntext.
+ /// </summary>
+ private class Context
+ {
+ /** Map from object position in old portable to position in new portable. */
+ private IDictionary<int, int> _oldToNew;
+
+ /** Parent context. */
+ private readonly Context _parent;
+
+ /** Portable writer. */
+ private readonly PortableWriterImpl _writer;
+
+ /** Children contexts. */
+ private ICollection<Context> _children;
+
+ /** Closed flag; if context is closed, it can no longer be used. */
+ private bool _closed;
+
+ /// <summary>
+ /// Constructor for parent context where writer invocation is not expected.
+ /// </summary>
+ public Context()
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Constructor for parent context.
+ /// </summary>
+ /// <param name="writer">Writer</param>
+ public Context(PortableWriterImpl writer)
+ {
+ _writer = writer;
+ }
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="parent">Parent context.</param>
+ public Context(Context parent)
+ {
+ _parent = parent;
+
+ _writer = parent._writer;
+
+ if (parent._children == null)
+ parent._children = new List<Context>();
+
+ parent._children.Add(this);
+ }
+
+ /// <summary>
+ /// Add another old-to-new position mapping.
+ /// </summary>
+ /// <param name="oldPos">Old position.</param>
+ /// <param name="newPos">New position.</param>
+ /// <param name="hndPos">Handle position.</param>
+ /// <returns><c>True</c> if ampping was added, <c>false</c> if mapping already existed and handle
+ /// position in the new object is returned.</returns>
+ public bool AddOldToNew(int oldPos, int newPos, out int hndPos)
+ {
+ if (_oldToNew == null)
+ _oldToNew = new Dictionary<int, int>();
+
+ if (_oldToNew.TryGetValue(oldPos, out hndPos))
+ return false;
+ _oldToNew[oldPos] = newPos;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Get mapping of old position to the new one.
+ /// </summary>
+ /// <param name="oldPos">Old position.</param>
+ /// <param name="newPos">New position.</param>
+ /// <returns><c>True</c> if mapping exists.</returns>
+ public bool OldToNew(int oldPos, out int newPos)
+ {
+ return _oldToNew.TryGetValue(oldPos, out newPos);
+ }
+
+ /// <summary>
+ /// Writer.
+ /// </summary>
+ public PortableWriterImpl Writer
+ {
+ get { return _writer; }
+ }
+
+ /// <summary>
+ /// Closed flag.
+ /// </summary>
+ public bool Closed
+ {
+ get
+ {
+ return _closed;
+ }
+ set
+ {
+ Context ctx = this;
+
+ while (ctx != null)
+ {
+ ctx._closed = value;
+
+ if (_children != null) {
+ foreach (Context child in _children)
+ child.Closed = value;
+ }
+
+ ctx = ctx._parent;
+ }
+ }
+ }
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/ignite/blob/ec58b87c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
----------------------------------------------------------------------
diff --cc modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
index 0000000,fe5f5c9..ff9aa34
mode 000000,100644..100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
@@@ -1,0 -1,1017 +1,1020 @@@
+ /*
+ * 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.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.IO;
+ using System.Runtime.Serialization;
+ using Apache.Ignite.Core.Impl.Common;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Portable reader implementation.
+ /// </summary>
+ internal class PortableReaderImpl : IPortableReader, IPortableRawReader
+ {
+ /** Marshaller. */
+ private readonly PortableMarshaller _marsh;
+
+ /** Type descriptors. */
+ private readonly IDictionary<long, IPortableTypeDescriptor> _descs;
+
+ /** Parent builder. */
+ private readonly PortableBuilderImpl _builder;
+
+ /** Handles. */
+ private PortableReaderHandleDictionary _hnds;
+
+ /** Current type ID. */
+ private int _curTypeId;
+
+ /** Current position. */
+ private int _curPos;
+
+ /** Current raw data offset. */
+ private int _curRawOffset;
+
+ /** Current converter. */
+ private IPortableNameMapper _curConverter;
+
+ /** Current mapper. */
+ private IPortableIdMapper _curMapper;
+
+ /** Current raw flag. */
+ private bool _curRaw;
+
+ /** Detach flag. */
+ private bool _detach;
+
+ /** Portable read mode. */
+ private PortableMode _mode;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="marsh">Marshaller.</param>
+ /// <param name="descs">Descriptors.</param>
+ /// <param name="stream">Input stream.</param>
+ /// <param name="mode">The mode.</param>
+ /// <param name="builder">Builder.</param>
+ public PortableReaderImpl
+ (PortableMarshaller marsh,
+ IDictionary<long, IPortableTypeDescriptor> descs,
+ IPortableStream stream,
+ PortableMode mode,
+ PortableBuilderImpl builder)
+ {
+ _marsh = marsh;
+ _descs = descs;
+ _mode = mode;
+ _builder = builder;
+
+ Stream = stream;
+ }
+
+ /// <summary>
+ /// Gets the marshaller.
+ /// </summary>
+ public PortableMarshaller Marshaller
+ {
+ get { return _marsh; }
+ }
+
+ /** <inheritdoc /> */
+ public IPortableRawReader GetRawReader()
+ {
+ MarkRaw();
+
+ return this;
+ }
+
+ /** <inheritdoc /> */
+ public bool ReadBoolean(string fieldName)
+ {
+ return ReadField(fieldName, r => r.ReadBoolean());
+ }
+
+ /** <inheritdoc /> */
+ public bool ReadBoolean()
+ {
+ return Stream.ReadBool();
+ }
+
+ /** <inheritdoc /> */
+ public bool[] ReadBooleanArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadBooleanArray);
+ }
+
+ /** <inheritdoc /> */
+ public bool[] ReadBooleanArray()
+ {
+ return Read(PortableUtils.ReadBooleanArray);
+ }
+
+ /** <inheritdoc /> */
+ public byte ReadByte(string fieldName)
+ {
+ return ReadField(fieldName, ReadByte);
+ }
+
+ /** <inheritdoc /> */
+ public byte ReadByte()
+ {
+ return Stream.ReadByte();
+ }
+
+ /** <inheritdoc /> */
+ public byte[] ReadByteArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadByteArray);
+ }
+
+ /** <inheritdoc /> */
+ public byte[] ReadByteArray()
+ {
+ return Read(PortableUtils.ReadByteArray);
+ }
+
+ /** <inheritdoc /> */
+ public short ReadShort(string fieldName)
+ {
+ return ReadField(fieldName, ReadShort);
+ }
+
+ /** <inheritdoc /> */
+ public short ReadShort()
+ {
+ return Stream.ReadShort();
+ }
+
+ /** <inheritdoc /> */
+ public short[] ReadShortArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadShortArray);
+ }
+
+ /** <inheritdoc /> */
+ public short[] ReadShortArray()
+ {
+ return Read(PortableUtils.ReadShortArray);
+ }
+
+ /** <inheritdoc /> */
+ public char ReadChar(string fieldName)
+ {
+ return ReadField(fieldName, ReadChar);
+ }
+
+ /** <inheritdoc /> */
+ public char ReadChar()
+ {
+ return Stream.ReadChar();
+ }
+
+ /** <inheritdoc /> */
+ public char[] ReadCharArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadCharArray);
+ }
+
+ /** <inheritdoc /> */
+ public char[] ReadCharArray()
+ {
+ return Read(PortableUtils.ReadCharArray);
+ }
+
+ /** <inheritdoc /> */
+ public int ReadInt(string fieldName)
+ {
+ return ReadField(fieldName, ReadInt);
+ }
+
+ /** <inheritdoc /> */
+ public int ReadInt()
+ {
+ return Stream.ReadInt();
+ }
+
+ /** <inheritdoc /> */
+ public int[] ReadIntArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadIntArray);
+ }
+
+ /** <inheritdoc /> */
+ public int[] ReadIntArray()
+ {
+ return Read(PortableUtils.ReadIntArray);
+ }
+
+ /** <inheritdoc /> */
+ public long ReadLong(string fieldName)
+ {
+ return ReadField(fieldName, ReadLong);
+ }
+
+ /** <inheritdoc /> */
+ public long ReadLong()
+ {
+ return Stream.ReadLong();
+ }
+
+ /** <inheritdoc /> */
+ public long[] ReadLongArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadLongArray);
+ }
+
+ /** <inheritdoc /> */
+ public long[] ReadLongArray()
+ {
+ return Read(PortableUtils.ReadLongArray);
+ }
+
+ /** <inheritdoc /> */
+ public float ReadFloat(string fieldName)
+ {
+ return ReadField(fieldName, ReadFloat);
+ }
+
+ /** <inheritdoc /> */
+ public float ReadFloat()
+ {
+ return Stream.ReadFloat();
+ }
+
+ /** <inheritdoc /> */
+ public float[] ReadFloatArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadFloatArray);
+ }
+
+ /** <inheritdoc /> */
+ public float[] ReadFloatArray()
+ {
+ return Read(PortableUtils.ReadFloatArray);
+ }
+
+ /** <inheritdoc /> */
+ public double ReadDouble(string fieldName)
+ {
+ return ReadField(fieldName, ReadDouble);
+ }
+
+ /** <inheritdoc /> */
+ public double ReadDouble()
+ {
+ return Stream.ReadDouble();
+ }
+
+ /** <inheritdoc /> */
+ public double[] ReadDoubleArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadDoubleArray);
+ }
+
+ /** <inheritdoc /> */
+ public double[] ReadDoubleArray()
+ {
+ return Read(PortableUtils.ReadDoubleArray);
+ }
+
+ /** <inheritdoc /> */
+ public decimal? ReadDecimal(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public decimal? ReadDecimal()
+ {
+ return Read(PortableUtils.ReadDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public decimal?[] ReadDecimalArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadDecimalArray);
+ }
+
+ /** <inheritdoc /> */
+ public decimal?[] ReadDecimalArray()
+ {
+ return Read(PortableUtils.ReadDecimalArray);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate(string fieldName)
+ {
+ return ReadDate(fieldName, false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate(string fieldName, bool local)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadDate(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate()
+ {
+ return ReadDate(false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate(bool local)
+ {
+ return Read(r => PortableUtils.ReadDate(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray(string fieldName)
+ {
+ return ReadDateArray(fieldName, false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray(string fieldName, bool local)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadDateArray(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray()
+ {
+ return ReadDateArray(false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray(bool local)
+ {
+ return Read(r => PortableUtils.ReadDateArray(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public string ReadString(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadString);
+ }
+
+ /** <inheritdoc /> */
+ public string ReadString()
+ {
+ return Read(PortableUtils.ReadString);
+ }
+
+ /** <inheritdoc /> */
+ public string[] ReadStringArray(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<string>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public string[] ReadStringArray()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<string>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public Guid? ReadGuid(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadGuid);
+ }
+
+ /** <inheritdoc /> */
+ public Guid? ReadGuid()
+ {
+ return Read(PortableUtils.ReadGuid);
+ }
+
+ /** <inheritdoc /> */
+ public Guid?[] ReadGuidArray(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<Guid?>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public Guid?[] ReadGuidArray()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<Guid?>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public T ReadEnum<T>(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadEnum<T>);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadEnum<T>()
+ {
+ return Read(PortableUtils.ReadEnum<T>);
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadEnumArray<T>(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadEnumArray<T>()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public T ReadObject<T>(string fieldName)
+ {
+ if (_curRaw)
+ throw new PortableException("Cannot read named fields after raw data is read.");
+
+ int fieldId = PortableUtils.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+
+ if (SeekField(fieldId))
+ return Deserialize<T>();
+
+ return default(T);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadObject<T>()
+ {
+ return Deserialize<T>();
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadObjectArray<T>(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadObjectArray<T>()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(string fieldName)
+ {
+ return ReadCollection(fieldName, null, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection()
+ {
+ return ReadCollection(null, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(string fieldName, PortableCollectionFactory factory,
+ PortableCollectionAdder adder)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadCollection(r, factory, adder));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(PortableCollectionFactory factory,
+ PortableCollectionAdder adder)
+ {
+ return Read(r => PortableUtils.ReadCollection(r, factory, adder));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>(string fieldName)
+ {
+ return ReadGenericCollection<T>(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>()
+ {
+ return ReadGenericCollection((PortableGenericCollectionFactory<T>) null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>(string fieldName,
+ PortableGenericCollectionFactory<T> factory)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericCollection(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>(PortableGenericCollectionFactory<T> factory)
+ {
+ return Read(r => PortableUtils.ReadGenericCollection(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(string fieldName)
+ {
+ return ReadDictionary(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary()
+ {
+ return ReadDictionary((PortableDictionaryFactory)null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(string fieldName, PortableDictionaryFactory factory)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadDictionary(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(PortableDictionaryFactory factory)
+ {
+ return Read(r => PortableUtils.ReadDictionary(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>(string fieldName)
+ {
+ return ReadGenericDictionary<TK, TV>(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>()
+ {
+ return ReadGenericDictionary((PortableGenericDictionaryFactory<TK, TV>) null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>(string fieldName,
+ PortableGenericDictionaryFactory<TK, TV> factory)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericDictionary(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>(PortableGenericDictionaryFactory<TK, TV> factory)
+ {
+ return Read(r => PortableUtils.ReadGenericDictionary(r, factory));
+ }
+
+ /// <summary>
+ /// Enable detach mode for the next object read.
+ /// </summary>
+ public void DetachNext()
+ {
+ _detach = true;
+ }
+
+ /// <summary>
+ /// Deserialize object.
+ /// </summary>
+ /// <returns>Deserialized object.</returns>
+ public T Deserialize<T>()
+ {
+ int pos = Stream.Position;
+
+ byte hdr = Stream.ReadByte();
+
+ var doDetach = _detach; // save detach flag into a var and reset so it does not go deeper
+
+ _detach = false;
+
+ switch (hdr)
+ {
+ case PortableUtils.HdrNull:
+ if (default(T) != null)
+ throw new PortableException(string.Format("Invalid data on deserialization. " +
+ "Expected: '{0}' But was: null", typeof (T)));
+
+ return default(T);
+
+ case PortableUtils.HdrHnd:
+ return ReadHandleObject<T>(pos);
+
+ case PortableUtils.HdrFull:
+ return ReadFullObject<T>(pos);
+
+ case PortableUtils.TypePortable:
+ return ReadPortableObject<T>(doDetach);
+ }
+
+ if (PortableUtils.IsPredefinedType(hdr))
+ return PortableSystemHandlers.ReadSystemType<T>(hdr, this);
+
+ throw new PortableException("Invalid header on deserialization [pos=" + pos + ", hdr=" + hdr + ']');
+ }
+
+ /// <summary>
+ /// Reads the portable object.
+ /// </summary>
+ private T ReadPortableObject<T>(bool doDetach)
+ {
+ var len = Stream.ReadInt();
+
+ var portablePos = Stream.Position;
+
+ if (_mode != PortableMode.Deserialize)
+ return TypeCaster<T>.Cast(ReadAsPortable(portablePos, len, doDetach));
+
+ Stream.Seek(len, SeekOrigin.Current);
+
+ var offset = Stream.ReadInt();
+
+ var retPos = Stream.Position;
+
+ Stream.Seek(portablePos + offset, SeekOrigin.Begin);
+
+ _mode = PortableMode.KeepPortable;
+
+ try
+ {
+ return Deserialize<T>();
+ }
+ finally
+ {
+ _mode = PortableMode.Deserialize;
+
+ Stream.Seek(retPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the portable object in portable form.
+ /// </summary>
+ private PortableUserObject ReadAsPortable(int dataPos, int dataLen, bool doDetach)
+ {
+ try
+ {
+ Stream.Seek(dataLen + dataPos, SeekOrigin.Begin);
+
+ var offs = Stream.ReadInt(); // offset inside data
+
+ var pos = dataPos + offs;
+
+ if (!doDetach)
+ return GetPortableUserObject(pos, pos, Stream.Array());
+
- Stream.Seek(pos + 10, SeekOrigin.Begin);
++ Stream.Seek(pos + PortableUtils.OffsetLen, SeekOrigin.Begin);
+
+ var len = Stream.ReadInt();
+
+ Stream.Seek(pos, SeekOrigin.Begin);
+
+ return GetPortableUserObject(pos, 0, Stream.ReadByteArray(len));
+ }
+ finally
+ {
+ Stream.Seek(dataPos + dataLen + 4, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the full object.
+ /// </summary>
+ [SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "hashCode")]
+ private T ReadFullObject<T>(int pos)
+ {
++ // Validate protocol version.
++ PortableUtils.ValidateProtocolVersion(Stream);
++
+ // Read header.
+ bool userType = Stream.ReadBool();
+ int typeId = Stream.ReadInt();
+ // ReSharper disable once UnusedVariable
+ int hashCode = Stream.ReadInt();
+ int len = Stream.ReadInt();
+ int rawOffset = Stream.ReadInt();
+
+ try
+ {
+ // Already read this object?
+ object hndObj;
+
+ if (_hnds != null && _hnds.TryGetValue(pos, out hndObj))
+ return (T) hndObj;
+
+ if (userType && _mode == PortableMode.ForcePortable)
+ {
+ PortableUserObject portObj;
+
+ if (_detach)
+ {
+ Stream.Seek(pos, SeekOrigin.Begin);
+
+ portObj = GetPortableUserObject(pos, 0, Stream.ReadByteArray(len));
+ }
+ else
+ portObj = GetPortableUserObject(pos, pos, Stream.Array());
+
+ T obj = _builder == null ? TypeCaster<T>.Cast(portObj) : TypeCaster<T>.Cast(_builder.Child(portObj));
+
+ AddHandle(pos, obj);
+
+ return obj;
+ }
+ else
+ {
+ // Find descriptor.
+ IPortableTypeDescriptor desc;
+
+ if (!_descs.TryGetValue(PortableUtils.TypeKey(userType, typeId), out desc))
+ throw new PortableException("Unknown type ID: " + typeId);
+
+ // Instantiate object.
+ if (desc.Type == null)
+ throw new PortableException("No matching type found for object [typeId=" +
+ desc.TypeId + ", typeName=" + desc.TypeName + ']');
+
+ // Preserve old frame.
+ int oldTypeId = _curTypeId;
+ int oldPos = _curPos;
+ int oldRawOffset = _curRawOffset;
+ IPortableNameMapper oldConverter = _curConverter;
+ IPortableIdMapper oldMapper = _curMapper;
+ bool oldRaw = _curRaw;
+
+ // Set new frame.
+ _curTypeId = typeId;
+ _curPos = pos;
+ _curRawOffset = rawOffset;
+ _curConverter = desc.NameConverter;
+ _curMapper = desc.Mapper;
+ _curRaw = false;
+
+ // Read object.
+ object obj;
+
+ var sysSerializer = desc.Serializer as IPortableSystemTypeSerializer;
+
+ if (sysSerializer != null)
+ obj = sysSerializer.ReadInstance(this);
+ else
+ {
+ try
+ {
+ obj = FormatterServices.GetUninitializedObject(desc.Type);
+
+ // Save handle.
+ AddHandle(pos, obj);
+ }
+ catch (Exception e)
+ {
+ throw new PortableException("Failed to create type instance: " +
+ desc.Type.AssemblyQualifiedName, e);
+ }
+
+ desc.Serializer.ReadPortable(obj, this);
+ }
+
+ // Restore old frame.
+ _curTypeId = oldTypeId;
+ _curPos = oldPos;
+ _curRawOffset = oldRawOffset;
+ _curConverter = oldConverter;
+ _curMapper = oldMapper;
+ _curRaw = oldRaw;
+
+ var wrappedSerializable = obj as SerializableObjectHolder;
+
+ return wrappedSerializable != null ? (T) wrappedSerializable.Item : (T) obj;
+ }
+ }
+ finally
+ {
+ // Advance stream pointer.
+ Stream.Seek(pos + len, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the handle object.
+ /// </summary>
+ private T ReadHandleObject<T>(int pos)
+ {
+ // Get handle position.
+ int hndPos = pos - Stream.ReadInt();
+
+ int retPos = Stream.Position;
+
+ try
+ {
+ object hndObj;
+
+ if (_builder == null || !_builder.CachedField(hndPos, out hndObj))
+ {
+ if (_hnds == null || !_hnds.TryGetValue(hndPos, out hndObj))
+ {
+ // No such handler, i.e. we trying to deserialize inner object before deserializing outer.
+ Stream.Seek(hndPos, SeekOrigin.Begin);
+
+ hndObj = Deserialize<T>();
+ }
+
+ // Notify builder that we deserialized object on other location.
+ if (_builder != null)
+ _builder.CacheField(hndPos, hndObj);
+ }
+
+ return (T) hndObj;
+ }
+ finally
+ {
+ // Position stream to correct place.
+ Stream.Seek(retPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Adds a handle to the dictionary.
+ /// </summary>
+ /// <param name="pos">Position.</param>
+ /// <param name="obj">Object.</param>
+ private void AddHandle(int pos, object obj)
+ {
+ if (_hnds == null)
+ _hnds = new PortableReaderHandleDictionary(pos, obj);
+ else
+ _hnds.Add(pos, obj);
+ }
+
+ /// <summary>
+ /// Underlying stream.
+ /// </summary>
+ public IPortableStream Stream
+ {
+ get;
+ private set;
+ }
+
+ /// <summary>
+ /// Mark current output as raw.
+ /// </summary>
+ private void MarkRaw()
+ {
+ if (!_curRaw)
+ {
+ _curRaw = true;
+
+ Stream.Seek(_curPos + _curRawOffset, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Seek field with the given ID in the current object.
+ /// </summary>
+ /// <param name="fieldId">Field ID.</param>
+ /// <returns>True in case the field was found and position adjusted, false otherwise.</returns>
+ private bool SeekField(int fieldId)
+ {
+ // This method is expected to be called when stream pointer is set either before
+ // the field or on raw data offset.
- int start = _curPos + 18;
++ int start = _curPos + PortableUtils.FullHdrLen;
+ int end = _curPos + _curRawOffset;
+
+ int initial = Stream.Position;
+
+ int cur = initial;
+
+ while (cur < end)
+ {
+ int id = Stream.ReadInt();
+
+ if (fieldId == id)
+ {
+ // Field is found, return.
+ Stream.Seek(4, SeekOrigin.Current);
+
+ return true;
+ }
+
+ Stream.Seek(Stream.ReadInt(), SeekOrigin.Current);
+
+ cur = Stream.Position;
+ }
+
+ Stream.Seek(start, SeekOrigin.Begin);
+
+ cur = start;
+
+ while (cur < initial)
+ {
+ int id = Stream.ReadInt();
+
+ if (fieldId == id)
+ {
+ // Field is found, return.
+ Stream.Seek(4, SeekOrigin.Current);
+
+ return true;
+ }
+
+ Stream.Seek(Stream.ReadInt(), SeekOrigin.Current);
+
+ cur = Stream.Position;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Determines whether header at current position is HDR_NULL.
+ /// </summary>
+ private bool IsNullHeader()
+ {
+ var hdr = ReadByte();
+
+ return hdr != PortableUtils.HdrNull;
+ }
+
+ /// <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)
+ {
+ if (_curRaw)
+ throw new PortableException("Cannot read named fields after raw data is read.");
+
+ var fieldId = PortableUtils.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+
+ if (!SeekField(fieldId))
+ return false;
+
+ return IsNullHeader();
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<IPortableStream, T> readFunc)
+ {
+ return SeekField(fieldName) ? readFunc(Stream) : default(T);
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<PortableReaderImpl, T> readFunc)
+ {
+ return SeekField(fieldName) ? readFunc(this) : default(T);
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<T> readFunc)
+ {
+ return SeekField(fieldName) ? 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)
+ {
+ return IsNullHeader() ? 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)
+ {
+ return IsNullHeader() ? readFunc(Stream) : default(T);
+ }
+
+ /// <summary>
+ /// Gets the portable user object from a byte array.
+ /// </summary>
+ /// <param name="pos">Position in the current stream.</param>
+ /// <param name="offs">Offset in the byte array.</param>
+ /// <param name="bytes">Bytes.</param>
+ private PortableUserObject GetPortableUserObject(int pos, int offs, byte[] bytes)
+ {
- Stream.Seek(pos + 2, SeekOrigin.Begin);
++ Stream.Seek(pos + PortableUtils.OffsetTypeId, SeekOrigin.Begin);
+
+ var id = Stream.ReadInt();
+
+ var hash = Stream.ReadInt();
+
+ return new PortableUserObject(_marsh, bytes, offs, id, hash);
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/ignite/blob/ec58b87c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs
----------------------------------------------------------------------
diff --cc modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs
index 0000000,891f261..2bf5ab8
mode 000000,100644..100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUserObject.cs
@@@ -1,0 -1,385 +1,385 @@@
+ /*
+ * 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.Collections;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Runtime.CompilerServices;
+ using System.Text;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// User portable object.
+ /// </summary>
+ internal class PortableUserObject : IPortableObject
+ {
+ /** Marshaller. */
+ private readonly PortableMarshaller _marsh;
+
+ /** Raw data of this portable object. */
+ private readonly byte[] _data;
+
+ /** Offset in data array. */
+ private readonly int _offset;
+
+ /** Type ID. */
+ private readonly int _typeId;
+
+ /** Hash code. */
+ private readonly int _hashCode;
+
+ /** Fields. */
+ private volatile IDictionary<int, int> _fields;
+
+ /** Deserialized value. */
+ private object _deserialized;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PortableUserObject"/> class.
+ /// </summary>
+ /// <param name="marsh">Marshaller.</param>
+ /// <param name="data">Raw data of this portable object.</param>
+ /// <param name="offset">Offset in data array.</param>
+ /// <param name="typeId">Type ID.</param>
+ /// <param name="hashCode">Hash code.</param>
+ public PortableUserObject(PortableMarshaller marsh, byte[] data, int offset, int typeId, int hashCode)
+ {
+ _marsh = marsh;
+
+ _data = data;
+ _offset = offset;
+
+ _typeId = typeId;
+ _hashCode = hashCode;
+ }
+
+ /** <inheritdoc /> */
+ public int TypeId
+ {
+ get { return _typeId; }
+ }
+
+ /** <inheritdoc /> */
+ public T GetField<T>(string fieldName)
+ {
+ return Field<T>(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public T Deserialize<T>()
+ {
+ return Deserialize<T>(PortableMode.Deserialize);
+ }
+
+ /// <summary>
+ /// Internal deserialization routine.
+ /// </summary>
+ /// <param name="mode">The mode.</param>
+ /// <returns>
+ /// Deserialized object.
+ /// </returns>
+ private T Deserialize<T>(PortableMode mode)
+ {
+ if (_deserialized == null)
+ {
+ IPortableStream stream = new PortableHeapStream(_data);
+
+ stream.Seek(_offset, SeekOrigin.Begin);
+
+ T res = _marsh.Unmarshal<T>(stream, mode);
+
+ IPortableTypeDescriptor desc = _marsh.GetDescriptor(true, _typeId);
+
+ if (!desc.KeepDeserialized)
+ return res;
+
+ _deserialized = res;
+ }
+
+ return (T)_deserialized;
+ }
+
+ /** <inheritdoc /> */
+ public IPortableMetadata GetMetadata()
+ {
+ return _marsh.GetMetadata(_typeId);
+ }
+
+ /// <summary>
+ /// Raw data of this portable object.
+ /// </summary>
+ public byte[] Data
+ {
+ get { return _data; }
+ }
+
+ /// <summary>
+ /// Offset in data array.
+ /// </summary>
+ public int Offset
+ {
+ 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)
+ {
+ IPortableTypeDescriptor 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);
+ }
+
+ /// <summary>
+ /// Lazy fields initialization routine.
+ /// </summary>
+ private void InitializeFields()
+ {
+ if (_fields == null)
+ {
+ IPortableStream stream = new PortableHeapStream(_data);
+
- stream.Seek(_offset + 14, SeekOrigin.Begin);
++ stream.Seek(_offset + PortableUtils.OffsetRawOff, SeekOrigin.Begin);
+
+ int rawDataOffset = stream.ReadInt();
+
+ _fields = PortableUtils.ObjectFields(stream, _typeId, rawDataOffset);
+ }
+ }
+
+ /// <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()
+ {
+ return _hashCode;
+ }
+
+ /** <inheritdoc /> */
+ public override bool Equals(object obj)
+ {
+ if (this == obj)
+ return true;
+
+ PortableUserObject that = obj as PortableUserObject;
+
+ if (that != null)
+ {
+ if (_data == that._data && _offset == that._offset)
+ return true;
+
+ // 1. Check hash code and type IDs.
+ if (_hashCode == that._hashCode && _typeId == that._typeId)
+ {
+ // 2. Check if objects have the same field sets.
+ InitializeFields();
+ that.InitializeFields();
+
+ if (_fields.Keys.Count != that._fields.Keys.Count)
+ return false;
+
+ foreach (int id in _fields.Keys)
+ {
+ if (!that._fields.Keys.Contains(id))
+ return false;
+ }
+
+ // 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);
+
+ if (!Equals(fieldVal, thatFieldVal))
+ return false;
+ }
+
+ // 4. Check if objects have the same raw data.
+ IPortableStream stream = new PortableHeapStream(_data);
- stream.Seek(_offset + 10, SeekOrigin.Begin);
++ stream.Seek(_offset + PortableUtils.OffsetLen, SeekOrigin.Begin);
+ int len = stream.ReadInt();
+ int rawOffset = stream.ReadInt();
+
+ IPortableStream thatStream = new PortableHeapStream(that._data);
- thatStream.Seek(_offset + 10, SeekOrigin.Begin);
++ thatStream.Seek(_offset + PortableUtils.OffsetLen, SeekOrigin.Begin);
+ int thatLen = thatStream.ReadInt();
+ int thatRawOffset = thatStream.ReadInt();
+
+ return PortableUtils.CompareArrays(_data, _offset + rawOffset, len - rawOffset, that._data,
+ that._offset + thatRawOffset, thatLen - thatRawOffset);
+ }
+ }
+
+ return false;
+ }
+
+ /** <inheritdoc /> */
+ public override string ToString()
+ {
+ return ToString(new Dictionary<int, int>());
+ }
+
+ /// <summary>
+ /// ToString implementation.
+ /// </summary>
+ /// <param name="handled">Already handled objects.</param>
+ /// <returns>Object string.</returns>
+ private string ToString(IDictionary<int, int> handled)
+ {
+ int idHash;
+
+ bool alreadyHandled = handled.TryGetValue(_offset, out idHash);
+
+ if (!alreadyHandled)
+ idHash = RuntimeHelpers.GetHashCode(this);
+
+ StringBuilder sb;
+
+ IPortableTypeDescriptor desc = _marsh.GetDescriptor(true, _typeId);
+
+ IPortableMetadata meta;
+
+ try
+ {
+ meta = _marsh.GetMetadata(_typeId);
+ }
+ catch (IgniteException)
+ {
+ meta = null;
+ }
+
+ if (meta == null)
+ sb = new StringBuilder("PortableObject [typeId=").Append(_typeId).Append(", idHash=" + idHash);
+ else
+ {
+ sb = new StringBuilder(meta.TypeName).Append(" [idHash=" + idHash);
+
+ if (!alreadyHandled)
+ {
+ handled[_offset] = idHash;
+
+ InitializeFields();
+
+ foreach (string fieldName in meta.Fields)
+ {
+ sb.Append(", ");
+
+ int fieldId = PortableUtils.FieldId(_typeId, fieldName, desc.NameConverter, desc.Mapper);
+
+ int fieldPos;
+
+ if (_fields.TryGetValue(fieldId, out fieldPos))
+ {
+ sb.Append(fieldName).Append('=');
+
+ ToString0(sb, Field0<object>(fieldPos, null), handled);
+ }
+ }
+ }
+ else
+ sb.Append(", ...");
+ }
+
+ sb.Append(']');
+
+ return sb.ToString();
+ }
+
+ /// <summary>
+ /// Internal ToString routine with correct collections printout.
+ /// </summary>
+ /// <param name="sb">String builder.</param>
+ /// <param name="obj">Object to print.</param>
+ /// <param name="handled">Already handled objects.</param>
+ /// <returns>The same string builder.</returns>
+ private static void ToString0(StringBuilder sb, object obj, IDictionary<int, int> handled)
+ {
+ IEnumerable col = (obj is string) ? null : obj as IEnumerable;
+
+ if (col == null)
+ {
+ PortableUserObject obj0 = obj as PortableUserObject;
+
+ sb.Append(obj0 == null ? obj : obj0.ToString(handled));
+ }
+ else
+ {
+ sb.Append('[');
+
+ bool first = true;
+
+ foreach (object elem in col)
+ {
+ if (first)
+ first = false;
+ else
+ sb.Append(", ");
+
+ ToString0(sb, elem, handled);
+ }
+
+ sb.Append(']');
+ }
+ }
+ }
+ }