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/07 11:59:28 UTC

[1/4] ignite git commit: IGNITE-1282: WIP on optos.

Repository: ignite
Updated Branches:
  refs/heads/ignite-1282-opto [created] 3548457c2


IGNITE-1282: WIP on optos.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/9da45ed3
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/9da45ed3
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/9da45ed3

Branch: refs/heads/ignite-1282-opto
Commit: 9da45ed3e6f7c79a47bbd71fa3db64094cb96e68
Parents: 49c495b
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Wed Oct 7 10:36:29 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Wed Oct 7 10:36:29 2015 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.csproj                   |   5 +
 .../Impl/Portable/IPortableTypeDescriptor.cs    |  15 +
 .../Metadata/Opto/PortableTypeStructure.cs      | 317 +++++++++++++++++++
 .../Metadata/Opto/PortableTypeStructureEntry.cs | 127 ++++++++
 .../Opto/PortableTypeStructureJumpTable.cs      | 115 +++++++
 .../Opto/PortableTypeStructureUpdate.cs         |  84 +++++
 .../Impl/Portable/PortableFullTypeDescriptor.cs |  21 ++
 .../Portable/PortableSurrogateTypeDescriptor.cs |  24 +-
 .../Impl/Portable/PortableUtils.cs              |   4 +
 .../Impl/Portable/PortableWriterImpl.cs         |  61 +++-
 10 files changed, 770 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/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 855dda8..d412181 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -250,6 +250,10 @@
     <Compile Include="Impl\Portable\IPortableTypeDescriptor.cs" />
     <Compile Include="Impl\Portable\IPortableWriteAware.cs" />
     <Compile Include="Impl\Portable\Metadata\IPortableMetadataHandler.cs" />
+    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructureEntry.cs" />
+    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructure.cs" />
+    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructureJumpTable.cs" />
+    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructureUpdate.cs" />
     <Compile Include="Impl\Portable\Metadata\PortableHashsetMetadataHandler.cs" />
     <Compile Include="Impl\Portable\Metadata\PortableMetadataHolder.cs" />
     <Compile Include="Impl\Portable\Metadata\PortableMetadataImpl.cs" />
@@ -367,6 +371,7 @@
       <Link>resources\release\x86\ignite.common.dll</Link>
     </EmbeddedResource>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
index 62597d5..389238c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
@@ -18,6 +18,8 @@
 namespace Apache.Ignite.Core.Impl.Portable
 {
     using System;
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
     using Apache.Ignite.Core.Portable;
 
     /// <summary>
@@ -104,5 +106,18 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             get;
         }
+
+        /// <summary>
+        /// Type structure.
+        /// </summary>
+        PortableTypeStructure TypeStructure { get; }
+
+        /// <summary>
+        /// Update type structure.
+        /// </summary>
+        /// <param name="exp">Expected type structure.</param>
+        /// <param name="pathIdx">Path index.</param>
+        /// <param name="updates">Recorded updates.</param>
+        void UpdateStrcuture(PortableTypeStructure exp, int pathIdx, IList<PortableTypeStructureUpdate> updates);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs
new file mode 100644
index 0000000..cdc0859
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs
@@ -0,0 +1,317 @@
+/*
+ * 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.Metadata.Opto
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Portable type structure. Cache field IDs and metadata to improve marshalling performance.
+    /// Every object write contains a set of field writes. Every unique ordered set of written fields
+    /// produce write "path". We cache these paths allowing for very fast traverse over object structure
+    /// without expensive map lookups and field ID calculations. 
+    /// </summary>
+    internal class PortableTypeStructure
+    {
+        /// <summary>
+        /// Create empty type structure.
+        /// </summary>
+        /// <returns>Empty type structure.</returns>
+        public static PortableTypeStructure CreateEmpty()
+        {
+            return new PortableTypeStructure(new[] { new PortableTypeStructureEntry[0] }, 
+                new PortableTypeStructureJumpTable[1], new Dictionary<string, byte>());
+        }
+
+        /** Entries. */
+        private readonly PortableTypeStructureEntry[][] _paths;
+
+        /** Jumps. */
+        private readonly PortableTypeStructureJumpTable[] _jumps;
+
+        /** Field types. */
+        private readonly IDictionary<string, byte> _fieldTypes; 
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="paths">Paths.</param>
+        /// <param name="jumps">Jumps.</param>
+        /// <param name="fieldTypes">Field types.</param>
+        private PortableTypeStructure(PortableTypeStructureEntry[][] paths,
+            PortableTypeStructureJumpTable[] jumps, IDictionary<string, byte> fieldTypes)
+        {
+            _paths = paths;
+            _jumps = jumps;
+            _fieldTypes = fieldTypes;
+        }
+
+        /// <summary>
+        /// Gets field ID if possible.
+        /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <param name="fieldType">Field type.</param>
+        /// <param name="pathIdx">Path index, changes during jumps.</param>
+        /// <param name="actionIdx">Action index.</param>
+        /// <returns>Field ID or zero in case there are no matching path.</returns>
+        public int GetFieldId(string fieldName, byte fieldType, ref int pathIdx, int actionIdx)
+        {
+            Debug.Assert(pathIdx <= _paths.Length);
+
+            // Get path.
+            PortableTypeStructureEntry[] path = _paths[pathIdx];
+
+            if (actionIdx < path.Length)
+            {
+                // Get entry matching the action index.
+                PortableTypeStructureEntry entry = path[actionIdx];
+
+                if (entry.IsExpected(fieldName, fieldType))
+                    // Entry matches our expectations, return.
+                    return entry.Id;
+                else if (entry.IsJumpTable)
+                {
+                    // Entry is a pointer to a jump table.
+                    Debug.Assert(entry.Id < _jumps.Length);
+
+                    PortableTypeStructureJumpTable jmpTbl = _jumps[entry.Id];
+
+                    int pathIdx0 = jmpTbl.GetPathIndex(fieldName);
+
+                    if (pathIdx0 < 0)
+                        return 0;
+
+                    Debug.Assert(pathIdx < _paths.Length);
+
+                    entry = _paths[pathIdx][actionIdx];
+
+                    entry.ValidateType(fieldType);
+
+                    pathIdx = pathIdx0;
+
+                    return entry.Id;
+                }
+            }
+
+            // Failed to find anything because this is a new field.
+            return 0;
+        }
+
+        /// <summary>
+        /// Merge updates into a new type structure.
+        /// </summary>
+        /// <param name="exp">Expected type structure to apply updates to </param>
+        /// <param name="pathIdx">Path index.</param>
+        /// <param name="updates">Updates.</param>
+        /// <returns>New type structure with updates.</returns>
+        public PortableTypeStructure Merge(PortableTypeStructure exp, int pathIdx, 
+            IList<PortableTypeStructureUpdate> updates)
+        {
+            if (updates.Count == 0)
+                return this;
+
+            // Algorithm ensures that updates are applied to the same type structure,
+            // where they were initially observed. This allow us to keep structure
+            // internals simpler and more efficient. On the other hand, this imposes
+            // some performance hit because in case of concurrent update, recorded
+            // changes will be discarded and recorded again during the next write
+            // on the same path. This should occur only during application warmup.
+
+            // Note that field types are merged anyway to avoid metadata clashes.
+            PortableTypeStructure res = MergeFieldTypes(updates);
+
+            if (ReferenceEquals(exp, this))
+            {
+                PortableTypeStructureUpdate firstUpdate = updates[0];
+
+                if (firstUpdate.Index == 0)
+                {
+                    // Special case: the very first structure update. Simply attach all updates.
+                    Debug.Assert(_paths.Length == 1);
+                    Debug.Assert(_paths[0].Length == 0);
+                    Debug.Assert(pathIdx == 0);
+
+                    PortableTypeStructureEntry[][] newPaths = CopyPaths(updates.Count, 0);
+
+                    ApplyUpdatesToPath(newPaths[0], updates);
+
+                    res = new PortableTypeStructure(newPaths, _jumps, res._fieldTypes);
+                }
+                else
+                {
+                    // Get entry where updates should start.
+                    PortableTypeStructureEntry[] path = _paths[pathIdx];
+
+                    PortableTypeStructureEntry startEntry = default(PortableTypeStructureEntry);
+
+                    if (firstUpdate.Index < path.Length)
+                        startEntry = path[firstUpdate.Index];
+
+                    if (startEntry.IsEmpty)
+                    {
+                        // We are on the empty/non-existend entry. Continue the path without branching.
+                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 0);
+
+                        ApplyUpdatesToPath(newPaths[pathIdx], updates);
+
+                        res = new PortableTypeStructure(newPaths, _jumps, res._fieldTypes);
+                    }
+                    else if (startEntry.IsJumpTable)
+                    {
+                        // We are on the jump table. Add a new path and record it in the jump table.
+
+                        // 1. Preapare new structures.
+                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 1);
+                        var newJumps = CopyJumps(0);
+
+                        // New path will be the last one.
+                        int newPathIdx = newPaths.Length - 1;
+
+                        // Apply updats to the new path.
+                        ApplyUpdatesToPath(newPaths[newPathIdx], updates);
+
+                        // Add new jump to the table.
+                        newJumps[startEntry.Id] = 
+                            newJumps[startEntry.Id].CopyAndAdd(firstUpdate.FieldName, newPathIdx);
+
+                        res = new PortableTypeStructure(newPaths, newJumps, res._fieldTypes);
+                    }
+                    else
+                    {
+                        // We are on existing entry. Need to create a new jump table here and two new paths.
+
+                        // 1. Preapare new structures.
+                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 2);
+                        var newJumps = CopyJumps(1);
+
+                        // Old path will be moved here.
+                        int oldPathIdx = newPaths.Length - 2;
+
+                        // New path will reside here.
+                        int newPathIdx = newPaths.Length - 1;
+
+                        // Create new jump table.
+                        int newJumpIdx = newJumps.Length - 1;
+
+                        newJumps[newJumpIdx] = new PortableTypeStructureJumpTable(startEntry.Name, oldPathIdx,
+                            firstUpdate.FieldName, newPathIdx);
+
+                        // Re-create old path in two steps: move old path to the new place, then clean the old path.
+                        for (int i = firstUpdate.Index; i < path.Length; i++)
+                        {
+                            newPaths[oldPathIdx][i] = newPaths[pathIdx][i];
+
+                            newPaths[pathIdx][i] = new PortableTypeStructureEntry();
+                        }
+
+                        // Apply updats to the new path.
+                        ApplyUpdatesToPath(newPaths[newPaths.Length - 1], updates);
+
+                        res = new PortableTypeStructure(newPaths, newJumps, res._fieldTypes);
+                    }
+
+                }
+            }
+
+            return res;
+        }
+
+        /// <summary>
+        /// Copy and possible expand paths.
+        /// </summary>
+        /// <param name="minLen">Minimum length.</param>
+        /// <param name="additionalPaths">Amount of additional paths required.</param>
+        /// <returns>Result.</returns>
+        private PortableTypeStructureEntry[][] CopyPaths(int minLen, int additionalPaths)
+        {
+            var newPaths = new PortableTypeStructureEntry[_paths.Length + additionalPaths][];
+
+            int newPathLen = Math.Max(_paths[0].Length, minLen);
+
+            for (int i = 0; i < _paths.Length; i++)
+            {
+                newPaths[i] = new PortableTypeStructureEntry[newPathLen];
+
+                Array.Copy(_paths[i], newPaths[i], _paths[i].Length);
+            }
+
+            return newPaths;
+        }
+
+        /// <summary>
+        /// Copy and possible expand jump tables.
+        /// </summary>
+        /// <param name="additionalJumps">Additional jumps.</param>
+        /// <returns>Result.</returns>
+        private PortableTypeStructureJumpTable[] CopyJumps(int additionalJumps)
+        {
+            var newJumps = new PortableTypeStructureJumpTable[_jumps.Length + additionalJumps];
+
+            for (int i = 0; i < _jumps.Length; i++)
+                newJumps[i] = _jumps[i].Copy();
+
+            return newJumps;
+        }
+
+        /// <summary>
+        /// Apply updates to path.
+        /// </summary>
+        /// <param name="path">Path.</param>
+        /// <param name="updates">Updates.</param>
+        private static void ApplyUpdatesToPath(IList<PortableTypeStructureEntry> path,
+            IEnumerable<PortableTypeStructureUpdate> updates)
+        {
+            foreach (var u in updates)
+                path[u.Index] = new PortableTypeStructureEntry(u.FieldName, u.FieldId, u.FieldType);
+        }
+
+        /// <summary>
+        /// Merge field types.
+        /// </summary>
+        /// <param name="updates">Updates.</param>
+        /// <returns>Type structure with applied updates.</returns>
+        private PortableTypeStructure MergeFieldTypes(IList<PortableTypeStructureUpdate> updates)
+        {
+            IDictionary<string, byte> newFieldTypes = new Dictionary<string, byte>(_fieldTypes);
+
+            foreach (PortableTypeStructureUpdate update in updates)
+            {
+                byte expType;
+
+                if (_fieldTypes.TryGetValue(update.FieldName, out expType))
+                {
+                    // This is an old field.
+                    if (expType != update.FieldType)
+                    {
+                        throw new PortableException("Field type mismatch detected [fieldName=" + update.FieldName +
+                            ", expectedType=" + expType + ", actualType=" + update.FieldType + ']');
+                    }
+                }
+                else
+                    // This is a new field.
+                    newFieldTypes[update.FieldName] = update.FieldType;
+            }
+
+            return newFieldTypes.Count == _fieldTypes.Count ? 
+                this : new PortableTypeStructure(_paths, _jumps, newFieldTypes);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs
new file mode 100644
index 0000000..e939d56
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs
@@ -0,0 +1,127 @@
+/*
+ * 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.Metadata.Opto
+{
+    using System.Diagnostics;
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Portable type structure entry. Might be either a normal field or a reference to jump table.
+    /// </summary>
+    internal struct PortableTypeStructureEntry
+    {
+        /** Field name. */
+        private readonly string _name;
+
+        /** Field ID. */
+        private readonly int _id;
+
+        /** Field type. */
+        private readonly byte _type;
+        
+        /// <summary>
+        /// Constructor for jump table entry.
+        /// </summary>
+        /// <param name="jumpTblIdx"></param>
+        public PortableTypeStructureEntry(int jumpTblIdx)
+        {
+            Debug.Assert(jumpTblIdx > 0);
+
+            _name = null;
+            _id = jumpTblIdx;
+            _type = 0;
+        }
+
+        /// <summary>
+        /// Constructor for field entry.
+        /// </summary>
+        /// <param name="name">Field name.</param>
+        /// <param name="id">Field ID.</param>
+        /// <param name="type">Field type.</param>
+        public PortableTypeStructureEntry(string name, int id, byte type)
+        {
+            Debug.Assert(name != null);
+
+            _name = name;
+            _id = id;
+            _type = type;
+        }
+
+        /// <summary>
+        /// Check whether current field entry matches passed arguments.
+        /// </summary>
+        /// <param name="name"></param>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public bool IsExpected(string name, byte type)
+        {
+            if (!ReferenceEquals(_name, name) && !_name.Equals(name))
+                return false;
+
+            ValidateType(type);
+
+            return true;
+        }
+
+        /// <summary>
+        /// Valide field type.
+        /// </summary>
+        /// <param name="type">Expected type.</param>
+        public void ValidateType(byte type)
+        {
+            if (_type != type)
+            {
+                throw new PortableException("Field type mismatch detected [fieldName=" + _name +
+                    ", expectedType=" + _type + ", actualType=" + type + ']');
+            }
+        }
+
+        /// <summary>
+        /// Whether this is an empty entry.
+        /// </summary>
+        /// <returns></returns>
+        public bool IsEmpty
+        {
+            get { return _id == 0; }
+        }
+
+        /// <summary>
+        /// Whether this is a jump table.
+        /// </summary>
+        public bool IsJumpTable
+        {
+            get { return _name == null && _id >= 0; }
+        }
+
+        /// <summary>
+        /// Field name.
+        /// </summary>
+        public string Name
+        {
+            get { return _name; }
+        }
+
+        /// <summary>
+        /// Field ID.
+        /// </summary>
+        public int Id
+        {
+            get { return _id; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs
new file mode 100644
index 0000000..b2409db
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs
@@ -0,0 +1,115 @@
+/*
+ * 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.Metadata.Opto
+{
+    using System;
+    using System.Diagnostics;
+
+    /// <summary>
+    /// Jump table.
+    /// </summary>
+    internal class PortableTypeStructureJumpTable
+    {
+        /** Names. */
+        private readonly string[] _names;
+
+        /** Path indexes. */
+        private readonly int[] _pathIdxs;
+
+        /// <summary>
+        /// Create jump table with two entries.
+        /// </summary>
+        /// <param name="firstName">First name.</param>
+        /// <param name="firstPathIdx">First path index.</param>
+        /// <param name="secondName">Second name.</param>
+        /// <param name="secondPathIdx">Second path index.</param>
+        public PortableTypeStructureJumpTable(string firstName, int firstPathIdx, 
+            string secondName, int secondPathIdx)
+        {
+            _names = new[] { firstName, secondName };
+            _pathIdxs = new[] { firstPathIdx, secondPathIdx };
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="names">Field names.</param>
+        /// <param name="pathIdxs">Path indexes.</param>
+        private PortableTypeStructureJumpTable(string[] names, int[] pathIdxs)
+        {
+            Debug.Assert(_names.Length > 1);
+            Debug.Assert(_names.Length == pathIdxs.Length);
+            
+            _names = names;
+            _pathIdxs = pathIdxs;
+        }
+
+        /// <summary>
+        /// Get path index for the given field.
+        /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <returns>Path index.</returns>
+        public int GetPathIndex(string fieldName)
+        {
+            Debug.Assert(fieldName != null);
+            
+            // Optimistically assume that field name is a literal.
+            for (var i = 0; i < _names.Length; i++)
+            {
+                if (ReferenceEquals(fieldName, _names[i]))
+                    return _pathIdxs[i];
+            }
+
+            // Fallback to slow-path with normal string comparison.
+            for (var i = 0; i < _names.Length; i++)
+            {
+                if (fieldName.Equals(_names[i]))
+                    return _pathIdxs[i];
+            }
+
+            // No path found for the field.
+            return -1;
+        }
+
+        /// <summary>
+        /// Copy jump table.
+        /// </summary>
+        /// <returns>New jump table.</returns>
+        public PortableTypeStructureJumpTable Copy()
+        {
+            return new PortableTypeStructureJumpTable(_names, _pathIdxs);
+        }
+
+        /// <summary>
+        /// Copy jump table with additional jump.
+        /// </summary>
+        /// <param name="name">Field name.</param>
+        /// <param name="pathIdx">Path index.</param>
+        /// <returns>New jump table.</returns>
+        public PortableTypeStructureJumpTable CopyAndAdd(string name, int pathIdx)
+        {
+            var newNames = new string[_names.Length + 1];
+            var pathIdxs = new int[_pathIdxs.Length + 1];
+
+            Array.Copy(_names, newNames, _names.Length);
+            Array.Copy(_pathIdxs, pathIdxs, _pathIdxs.Length);
+
+            return new PortableTypeStructureJumpTable(newNames, pathIdxs);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs
new file mode 100644
index 0000000..56e0c12
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs
@@ -0,0 +1,84 @@
+/*
+ * 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.Metadata.Opto
+{
+    /// <summary>
+    /// Portable type structure update descriptor.
+    /// </summary>
+    class PortableTypeStructureUpdate
+    {
+        /** Field name. */
+        private readonly string _fieldName;
+
+        /** Field ID. */
+        private readonly int _fieldId;
+
+        /** Field type. */
+        private readonly byte _fieldType;
+
+        /** Field index. */
+        private readonly int _idx;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <param name="fieldId">Field ID.</param>
+        /// <param name="fieldType">Field type.</param>
+        /// <param name="idx">Index.</param>
+        public PortableTypeStructureUpdate(string fieldName, int fieldId, byte fieldType, int idx)
+        {
+            _fieldName = fieldName;
+            _fieldId = fieldId;
+            _fieldType = fieldType;
+            _idx = idx;
+        }
+
+        /// <summary>
+        /// Field name.
+        /// </summary>
+        public string FieldName
+        {
+            get { return _fieldName; }
+        }
+
+        /// <summary>
+        /// Field ID.
+        /// </summary>
+        public int FieldId
+        {
+            get { return _fieldId; }
+        }
+
+        /// <summary>
+        /// Field type.
+        /// </summary>
+        public byte FieldType
+        {
+            get { return _fieldType; }
+        }
+
+        /// <summary>
+        /// Index.
+        /// </summary>
+        public int Index
+        {
+            get { return _idx; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
index 79b860f..d1a714b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
@@ -18,6 +18,8 @@
 namespace Apache.Ignite.Core.Impl.Portable
 {
     using System;
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
     using Apache.Ignite.Core.Portable;
 
     /// <summary>
@@ -55,6 +57,9 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Affinity field key name. */
         private readonly string _affKeyFieldName;
 
+        /** Type structure. */
+        private volatile PortableTypeStructure _typeStruct = PortableTypeStructure.CreateEmpty();
+
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -171,5 +176,21 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             get { return _affKeyFieldName; }
         }
+
+        /** <inheritDoc /> */
+        public PortableTypeStructure TypeStructure
+        {
+            get { return _typeStruct; }
+        }
+
+        /** <inheritDoc /> */
+        public void UpdateStrcuture(PortableTypeStructure exp, int pathIdx, 
+            IList<PortableTypeStructureUpdate> updates)
+        {
+            lock (this)
+            {
+                _typeStruct = _typeStruct.Merge(exp, pathIdx, updates);
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
index 9842c46..adbb6bb 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
@@ -18,10 +18,13 @@
 namespace Apache.Ignite.Core.Impl.Portable
 {
     using System;
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
     using Apache.Ignite.Core.Portable;
 
     /// <summary>
-    /// Surrogate type descriptor. Used in cases when type if identified by name and is not provided in configuration.
+    /// Surrogate type descriptor. Used in cases when type if identified by name and 
+    /// is not provided in configuration.
     /// </summary>
     internal class PortableSurrogateTypeDescriptor : IPortableTypeDescriptor
     {
@@ -34,6 +37,9 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Type name. */
         private readonly string _name;
 
+        /** Type structure. */
+        private volatile PortableTypeStructure _typeStruct = PortableTypeStructure.CreateEmpty();
+
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -117,5 +123,21 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             get { return null; }
         }
+
+        /** <inheritDoc /> */
+        public PortableTypeStructure TypeStructure
+        {
+            get { return _typeStruct; }
+        }
+
+        /** <inheritDoc /> */
+        public void UpdateStrcuture(PortableTypeStructure exp, int pathIdx,
+            IList<PortableTypeStructureUpdate> updates)
+        {
+            lock (this)
+            {
+                _typeStruct = _typeStruct.Merge(exp, pathIdx, updates);
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/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 2344db2..fb0b195 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
@@ -1799,6 +1799,10 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (id == 0)
                 id = StringHashCode(fieldName);
 
+            if (id == 0)
+                throw new PortableException("Field ID is zero (please provide ID mapper or change field name) " + 
+                    "[typeId=" + typeId + ", fieldName=" + fieldName + ", idMapper=" + idMapper + ']');
+
             return id;
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/9da45ed3/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 69523c9..6a0917a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
@@ -24,6 +24,7 @@ namespace Apache.Ignite.Core.Impl.Portable
 
     using Apache.Ignite.Core.Impl.Portable.IO;
     using Apache.Ignite.Core.Impl.Portable.Metadata;
+    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
     using Apache.Ignite.Core.Portable;
 
     using PU = PortableUtils;
@@ -62,6 +63,12 @@ namespace Apache.Ignite.Core.Impl.Portable
         
         /** Current raw position. */
         private long _curRawPos;
+
+        private PortableTypeStructure _curTypeStruct;
+        private int _curPathIdx;
+        private int _curActionIdx;
+        private bool _curNewStruct;
+        private List<PortableTypeStructureUpdate> _curUpdates; 
         
         /** Whether we are currently detaching an object. */
         private bool _detaching;
@@ -1303,6 +1310,12 @@ namespace Apache.Ignite.Core.Impl.Portable
                 IPortableIdMapper oldMapper = _curMapper;
                 IPortableMetadataHandler oldMetaHnd = _curMetaHnd;
                 long oldRawPos = _curRawPos;
+                
+                PortableTypeStructure oldTypeStruct = _curTypeStruct;
+                int oldPathIdx = _curPathIdx;
+                int oldActionIdx = _curActionIdx;
+                bool oldNewStruct = _curNewStruct;
+                var oldUpdates = _curUpdates;
 
                 // Push new frame.
                 _curTypeId = desc.TypeId;
@@ -1311,6 +1324,12 @@ namespace Apache.Ignite.Core.Impl.Portable
                 _curMetaHnd = desc.MetadataEnabled ? _marsh.MetadataHandler(desc) : null;
                 _curRawPos = 0;
 
+                _curTypeStruct = desc.TypeStructure;
+                _curPathIdx = 0;
+                _curActionIdx = 0;
+                _curNewStruct = false;
+                _curUpdates = null;
+
                 // Write object fields.
                 desc.Serializer.WritePortable(obj, this);
 
@@ -1333,12 +1352,22 @@ namespace Apache.Ignite.Core.Impl.Portable
                         SaveMetadata(_curTypeId, desc.TypeName, desc.AffinityKeyFieldName, meta);
                 }
 
+                // 14. Apply structure updates 
+                if (_curUpdates != null)
+                    desc.UpdateStrcuture(_curTypeStruct, _curPathIdx, _curUpdates);
+                
                 // Restore old frame.
                 _curTypeId = oldTypeId;
                 _curConverter = oldConverter;
                 _curMapper = oldMapper;
                 _curMetaHnd = oldMetaHnd;
                 _curRawPos = oldRawPos;
+
+                _curTypeStruct = oldTypeStruct;
+                _curPathIdx = oldPathIdx;
+                _curActionIdx = oldActionIdx;
+                _curNewStruct = oldNewStruct;
+                _curUpdates = oldUpdates;
             }
             else
             {
@@ -1595,10 +1624,38 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (_curRawPos != 0)
                 throw new PortableException("Cannot write named fields after raw data is written.");
 
-            int fieldId = PU.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+            int actionIdx = _curActionIdx++;
 
-            _stream.WriteInt(fieldId);
+            int fieldId;
+
+            if (!_curNewStruct)
+            {
+                fieldId = _curTypeStruct.GetFieldId(fieldName, fieldTypeId, ref _curPathIdx, actionIdx);
+
+                if (fieldId == 0)
+                {
+                    _curNewStruct = true;
+
+                    fieldId = PU.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+
+                    if (_curUpdates == null)
+                        _curUpdates = new List<PortableTypeStructureUpdate>();
 
+                    _curUpdates.Add(new PortableTypeStructureUpdate(fieldName, fieldId, fieldTypeId, actionIdx));
+                }
+            }
+            else
+            {
+                fieldId = PU.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+
+                if (_curUpdates == null)
+                    _curUpdates = new List<PortableTypeStructureUpdate>();
+
+                _curUpdates.Add(new PortableTypeStructureUpdate(fieldName, fieldId, fieldTypeId, actionIdx));
+            }
+
+            _stream.WriteInt(fieldId);
+            
             if (_curMetaHnd != null)
                 _curMetaHnd.OnFieldWrite(fieldId, fieldName, fieldTypeId);
         }


[4/4] ignite git commit: IGNITE-1282: Refactoring.

Posted by vo...@apache.org.
IGNITE-1282: Refactoring.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/3548457c
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/3548457c
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/3548457c

Branch: refs/heads/ignite-1282-opto
Commit: 3548457c234456f1a3695dac497ceb452c4971ed
Parents: b34084e
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Wed Oct 7 13:00:05 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Wed Oct 7 13:00:05 2015 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.Tests.csproj             |   1 +
 .../Portable/PortableStructureTest.cs           | 260 +++++++++++++++++++
 .../Impl/Portable/IPortableTypeDescriptor.cs    |   2 +-
 .../Impl/Portable/PortableFullTypeDescriptor.cs |   2 +-
 .../Portable/PortableSurrogateTypeDescriptor.cs |   2 +-
 .../Impl/Portable/PortableWriterImpl.cs         |   2 +-
 .../Portable/Structure/PortableStructure.cs     |  30 ++-
 .../Structure/PortableStructureEntry.cs         |   8 +-
 .../Structure/PortableStructureJumpTable.cs     |   4 +-
 9 files changed, 295 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index 90f3481..7cbe784 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -111,6 +111,7 @@
     <Compile Include="MarshallerTest.cs" />
     <Compile Include="MessagingTest.cs" />
     <Compile Include="PortableConfigurationTest.cs" />
+    <Compile Include="Portable\PortableStructureTest.cs" />
     <Compile Include="SerializationTest.cs" />
     <Compile Include="IgniteStartStopTest.cs" />
     <Compile Include="TestUtils.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableStructureTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableStructureTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableStructureTest.cs
new file mode 100644
index 0000000..46c9539
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableStructureTest.cs
@@ -0,0 +1,260 @@
+/*
+ * 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.Tests.Portable
+{
+    using System;
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Impl;
+    using Apache.Ignite.Core.Impl.Portable;
+    using Apache.Ignite.Core.Impl.Portable.Structure;
+    using Apache.Ignite.Core.Portable;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Contains tests for portable type structure.
+    /// </summary>
+    [TestFixture]
+    public class PortableStructureTest
+    {
+        /** Repeat count. */
+        public static readonly int RepeatCnt = 10;
+
+        public static readonly int ObjectsPerMode = 5;
+
+        /// <summary>
+        /// Test object write with different structures.
+        /// </summary>
+        [Test]
+        public void TestStructure()
+        {
+            for (int i = 1; i <= RepeatCnt; i++)
+            {
+                Console.WriteLine(">>> Iteration started: " + i);
+
+                // 1. Generate and shuffle objects.
+                IList<BranchedType> objs = new List<BranchedType>();
+
+                for (int j = 0; j < 6 * ObjectsPerMode; j++)
+                    objs.Add(new BranchedType((j%6) + 1));
+
+                objs = IgniteUtils.Shuffle(objs);
+
+                // 2. Create new marshaller.
+                PortableTypeConfiguration typeCfg = new PortableTypeConfiguration(typeof(BranchedType));
+
+                PortableConfiguration cfg = new PortableConfiguration
+                {
+                    TypeConfigurations = new List<PortableTypeConfiguration> { typeCfg }
+                };
+
+                PortableMarshaller marsh = new PortableMarshaller(cfg);
+
+                // 3. Marshal all data and ensure deserialized object is fine.
+                foreach (BranchedType obj in objs)
+                {
+                    Console.WriteLine(">>> Write object [mode=" + obj.mode + ']');
+
+                    byte[] data = marsh.Marshal(obj);
+
+                    BranchedType other = marsh.Unmarshal<BranchedType>(data);
+
+                    Assert.IsTrue(obj.Equals(other));
+                }
+                
+                Console.WriteLine();
+
+                // 4. Ensure that all fields are recorded.
+                IPortableTypeDescriptor desc = marsh.Descriptor(typeof (BranchedType));
+
+                PortableStructure typeStruct = desc.TypeStructure;
+
+                IDictionary<string, byte> fields = typeStruct.FieldTypes;
+
+                Assert.IsTrue(fields.Count == 8);
+
+                Assert.IsTrue(fields.ContainsKey("mode"));
+                Assert.IsTrue(fields.ContainsKey("f2"));
+                Assert.IsTrue(fields.ContainsKey("f3"));
+                Assert.IsTrue(fields.ContainsKey("f4"));
+                Assert.IsTrue(fields.ContainsKey("f5"));
+                Assert.IsTrue(fields.ContainsKey("f6"));
+                Assert.IsTrue(fields.ContainsKey("f7"));
+                Assert.IsTrue(fields.ContainsKey("f8"));
+            }
+        }
+    }
+
+    public class BranchedType : IPortableMarshalAware
+    {
+        public int mode;
+        public int f2;
+        public int f3;
+        public int f4;
+        public int f5;
+        public int f6;
+        public int f7;
+        public int f8;
+
+        public BranchedType(int mode)
+        {
+            this.mode = mode;
+
+            switch (mode)
+            {
+                case 1:
+                    f2 = 2;
+
+                    break;
+
+                case 2:
+                    f2 = 2;
+                    f3 = 3;
+                    f4 = 4;
+
+                    break;
+
+                case 3:
+                    f2 = 2;
+                    f3 = 3;
+                    f5 = 5;
+
+                    break;
+
+                case 4:
+                    f2 = 2;
+                    f3 = 3;
+                    f5 = 5;
+                    f6 = 6;
+
+                    break;
+
+                case 5:
+                    f2 = 2;
+                    f3 = 3;
+                    f7 = 7;
+
+                    break;
+
+                case 6:
+                    f8 = 8;
+
+                    break;
+            }
+        }
+
+        public void WritePortable(IPortableWriter writer)
+        {
+            writer.WriteInt("mode", mode);
+
+            switch (mode)
+            {
+                case 1:
+                    writer.WriteInt("f2", f2);
+
+                    break;
+
+                case 2:
+                    writer.WriteInt("f2", f2);
+                    writer.WriteInt("f3", f3);
+                    writer.WriteInt("f4", f4);
+
+                    break;
+
+                case 3:
+                    writer.WriteInt("f2", f2);
+                    writer.WriteInt("f3", f3);
+                    writer.WriteInt("f5", f5);
+
+                    break;
+
+                case 4:
+                    writer.WriteInt("f2", f2);
+                    writer.WriteInt("f3", f3);
+                    writer.WriteInt("f5", f5);
+                    writer.WriteInt("f6", f6);
+
+                    break;
+
+                case 5:
+                    writer.WriteInt("f2", f2);
+                    writer.WriteInt("f3", f3);
+                    writer.WriteInt("f7", f7);
+
+                    break;
+
+                case 6:
+                    writer.WriteInt("f8", f8);
+
+                    break;
+            }
+        }
+
+        public void ReadPortable(IPortableReader reader)
+        {
+            mode = reader.ReadInt("mode");
+
+            switch (mode)
+            {
+                case 1:
+                    f2 = reader.ReadInt("f2");
+
+                    break;
+
+                case 2:
+                    f2 = reader.ReadInt("f2");
+                    f3 = reader.ReadInt("f3");
+                    f4 = reader.ReadInt("f4");
+
+                    break;
+
+                case 3:
+                    f2 = reader.ReadInt("f2");
+                    f3 = reader.ReadInt("f3");
+                    f5 = reader.ReadInt("f5");
+
+                    break;
+
+                case 4:
+                    f2 = reader.ReadInt("f2");
+                    f3 = reader.ReadInt("f3");
+                    f5 = reader.ReadInt("f5");
+                    f6 = reader.ReadInt("f6");
+
+                    break;
+
+                case 5:
+                    f2 = reader.ReadInt("f2");
+                    f3 = reader.ReadInt("f3");
+                    f7 = reader.ReadInt("f7");
+
+                    break;
+
+                case 6:
+                    f8 = reader.ReadInt("f8");
+
+                    break;
+            }
+        }
+
+        public bool Equals(BranchedType other)
+        {
+            return mode == other.mode && f2 == other.f2 && f3 == other.f3 && f4 == other.f4 && f5 == other.f5 &&
+                   f6 == other.f6 && f7 == other.f7 && f8 == other.f8;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
index 8a84daf..d4bde4f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
@@ -118,6 +118,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <param name="exp">Expected type structure.</param>
         /// <param name="pathIdx">Path index.</param>
         /// <param name="updates">Recorded updates.</param>
-        void UpdateStrcuture(PortableStructure exp, int pathIdx, IList<PortableStructureUpdate> updates);
+        void UpdateStructure(PortableStructure exp, int pathIdx, IList<PortableStructureUpdate> updates);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
index 247a0b0..701147d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
@@ -184,7 +184,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         }
 
         /** <inheritDoc /> */
-        public void UpdateStrcuture(PortableStructure exp, int pathIdx, 
+        public void UpdateStructure(PortableStructure exp, int pathIdx, 
             IList<PortableStructureUpdate> updates)
         {
             lock (this)

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
index 103dd75..e786746 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
@@ -131,7 +131,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         }
 
         /** <inheritDoc /> */
-        public void UpdateStrcuture(PortableStructure exp, int pathIdx,
+        public void UpdateStructure(PortableStructure exp, int pathIdx,
             IList<PortableStructureUpdate> updates)
         {
             lock (this)

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/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 cafc69d..09ca45e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
@@ -1345,7 +1345,7 @@ namespace Apache.Ignite.Core.Impl.Portable
                 // Apply structure updates if any.
                 if (_curStructUpdates != null)
                 {
-                    desc.UpdateStrcuture(_curStruct, _curStructPath, _curStructUpdates);
+                    desc.UpdateStructure(_curStruct, _curStructPath, _curStructUpdates);
 
                     IPortableMetadataHandler metaHnd = _marsh.MetadataHandler(desc);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs
index c434110..aaeaadd 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs
@@ -99,9 +99,9 @@ namespace Apache.Ignite.Core.Impl.Portable.Structure
                     if (pathIdx0 < 0)
                         return 0;
 
-                    Debug.Assert(pathIdx < _paths.Length);
+                    Debug.Assert(pathIdx0 < _paths.Length);
 
-                    entry = _paths[pathIdx][actionIdx];
+                    entry = _paths[pathIdx0][actionIdx];
 
                     entry.ValidateType(fieldType);
 
@@ -219,7 +219,12 @@ namespace Apache.Ignite.Core.Impl.Portable.Structure
                         {
                             newPaths[oldPathIdx][i] = newPaths[pathIdx][i];
 
-                            newPaths[pathIdx][i] = new PortableStructureEntry();
+                            if (i == firstUpdate.Index)
+                                // Jump table must be placed here.
+                                newPaths[pathIdx][i] = new PortableStructureEntry(newJumpIdx);
+                            else
+                                // Just nullify.
+                                newPaths[pathIdx][i] = new PortableStructureEntry();
                         }
 
                         // Apply updats to the new path.
@@ -246,11 +251,12 @@ namespace Apache.Ignite.Core.Impl.Portable.Structure
 
             int newPathLen = Math.Max(_paths[0].Length, minLen);
 
-            for (int i = 0; i < _paths.Length; i++)
+            for (int i = 0; i < newPaths.Length; i++)
             {
                 newPaths[i] = new PortableStructureEntry[newPathLen];
 
-                Array.Copy(_paths[i], newPaths[i], _paths[i].Length);
+                if (i < _paths.Length)
+                    Array.Copy(_paths[i], newPaths[i], _paths[i].Length);
             }
 
             return newPaths;
@@ -265,8 +271,12 @@ namespace Apache.Ignite.Core.Impl.Portable.Structure
         {
             var newJumps = new PortableStructureJumpTable[_jumps.Length + additionalJumps];
 
-            for (int i = 0; i < _jumps.Length; i++)
+            for (int i = 1; i < _jumps.Length; i++)
+            {
+                // The very first jump is always null so that we can distinguish jump table 
+                // and empty value in PortableStructureEntry.
                 newJumps[i] = _jumps[i].Copy();
+            }
 
             return newJumps;
         }
@@ -313,5 +323,13 @@ namespace Apache.Ignite.Core.Impl.Portable.Structure
             return newFieldTypes.Count == _fieldTypes.Count ? 
                 this : new PortableStructure(_paths, _jumps, newFieldTypes);
         }
+
+        /// <summary>
+        /// Recorded field types.
+        /// </summary>
+        internal IDictionary<string, byte> FieldTypes
+        {
+            get { return _fieldTypes; }
+        } 
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs
index 5229a95..e3efc2a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs
@@ -66,12 +66,12 @@ namespace Apache.Ignite.Core.Impl.Portable.Structure
         /// <summary>
         /// Check whether current field entry matches passed arguments.
         /// </summary>
-        /// <param name="name"></param>
-        /// <param name="type"></param>
-        /// <returns></returns>
+        /// <param name="name">Field name.</param>
+        /// <param name="type">Field type.</param>
+        /// <returns>True if expected.</returns>
         public bool IsExpected(string name, byte type)
         {
-            if (!ReferenceEquals(_name, name) && !_name.Equals(name))
+            if (!ReferenceEquals(_name, name) && !name.Equals(_name))
                 return false;
 
             ValidateType(type);

http://git-wip-us.apache.org/repos/asf/ignite/blob/3548457c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs
index 85e71c4..9eab9d4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs
@@ -52,8 +52,8 @@ namespace Apache.Ignite.Core.Impl.Portable.Structure
         /// <param name="pathIdxs">Path indexes.</param>
         private PortableStructureJumpTable(string[] names, int[] pathIdxs)
         {
-            Debug.Assert(_names.Length > 1);
-            Debug.Assert(_names.Length == pathIdxs.Length);
+            Debug.Assert(names.Length > 1);
+            Debug.Assert(names.Length == pathIdxs.Length);
             
             _names = names;
             _pathIdxs = pathIdxs;


[3/4] ignite git commit: IGNITE-1282: Refactoring.

Posted by vo...@apache.org.
IGNITE-1282: Refactoring.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/b34084eb
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/b34084eb
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/b34084eb

Branch: refs/heads/ignite-1282-opto
Commit: b34084eb053f4f2bd249bf5a51f487988e3030ac
Parents: 11f7d09
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Wed Oct 7 11:44:24 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Wed Oct 7 11:44:24 2015 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.csproj                   |   8 +-
 .../Impl/Portable/IPortableTypeDescriptor.cs    |   6 +-
 .../Metadata/Opto/PortableTypeStructure.cs      | 317 -------------------
 .../Metadata/Opto/PortableTypeStructureEntry.cs | 127 --------
 .../Opto/PortableTypeStructureJumpTable.cs      | 115 -------
 .../Opto/PortableTypeStructureUpdate.cs         |  84 -----
 .../Impl/Portable/PortableFullTypeDescriptor.cs |  10 +-
 .../Portable/PortableSurrogateTypeDescriptor.cs |  10 +-
 .../Impl/Portable/PortableWriterImpl.cs         |  70 ++--
 .../Portable/Structure/PortableStructure.cs     | 317 +++++++++++++++++++
 .../Structure/PortableStructureEntry.cs         | 128 ++++++++
 .../Structure/PortableStructureJumpTable.cs     | 115 +++++++
 .../Structure/PortableStructureUpdate.cs        |  84 +++++
 13 files changed, 701 insertions(+), 690 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/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 d412181..e8ec7ed 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -250,10 +250,6 @@
     <Compile Include="Impl\Portable\IPortableTypeDescriptor.cs" />
     <Compile Include="Impl\Portable\IPortableWriteAware.cs" />
     <Compile Include="Impl\Portable\Metadata\IPortableMetadataHandler.cs" />
-    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructureEntry.cs" />
-    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructure.cs" />
-    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructureJumpTable.cs" />
-    <Compile Include="Impl\Portable\Metadata\Opto\PortableTypeStructureUpdate.cs" />
     <Compile Include="Impl\Portable\Metadata\PortableHashsetMetadataHandler.cs" />
     <Compile Include="Impl\Portable\Metadata\PortableMetadataHolder.cs" />
     <Compile Include="Impl\Portable\Metadata\PortableMetadataImpl.cs" />
@@ -279,6 +275,10 @@
     <Compile Include="Impl\Portable\PortableUtils.cs" />
     <Compile Include="Impl\Portable\PortableWriterImpl.cs" />
     <Compile Include="Impl\Portable\SerializableObjectHolder.cs" />
+    <Compile Include="Impl\Portable\Structure\PortableStructure.cs" />
+    <Compile Include="Impl\Portable\Structure\PortableStructureEntry.cs" />
+    <Compile Include="Impl\Portable\Structure\PortableStructureJumpTable.cs" />
+    <Compile Include="Impl\Portable\Structure\PortableStructureUpdate.cs" />
     <Compile Include="Impl\Portable\TypeResolver.cs" />
     <Compile Include="Impl\Resource\IResourceInjector.cs" />
     <Compile Include="Impl\Resource\ResourceFieldInjector.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
index 389238c..8a84daf 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/IPortableTypeDescriptor.cs
@@ -19,7 +19,7 @@ namespace Apache.Ignite.Core.Impl.Portable
 {
     using System;
     using System.Collections.Generic;
-    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
+    using Apache.Ignite.Core.Impl.Portable.Structure;
     using Apache.Ignite.Core.Portable;
 
     /// <summary>
@@ -110,7 +110,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <summary>
         /// Type structure.
         /// </summary>
-        PortableTypeStructure TypeStructure { get; }
+        PortableStructure TypeStructure { get; }
 
         /// <summary>
         /// Update type structure.
@@ -118,6 +118,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <param name="exp">Expected type structure.</param>
         /// <param name="pathIdx">Path index.</param>
         /// <param name="updates">Recorded updates.</param>
-        void UpdateStrcuture(PortableTypeStructure exp, int pathIdx, IList<PortableTypeStructureUpdate> updates);
+        void UpdateStrcuture(PortableStructure exp, int pathIdx, IList<PortableStructureUpdate> updates);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs
deleted file mode 100644
index cdc0859..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructure.cs
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * 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.Metadata.Opto
-{
-    using System;
-    using System.Collections.Generic;
-    using System.Diagnostics;
-    
-    using Apache.Ignite.Core.Portable;
-
-    /// <summary>
-    /// Portable type structure. Cache field IDs and metadata to improve marshalling performance.
-    /// Every object write contains a set of field writes. Every unique ordered set of written fields
-    /// produce write "path". We cache these paths allowing for very fast traverse over object structure
-    /// without expensive map lookups and field ID calculations. 
-    /// </summary>
-    internal class PortableTypeStructure
-    {
-        /// <summary>
-        /// Create empty type structure.
-        /// </summary>
-        /// <returns>Empty type structure.</returns>
-        public static PortableTypeStructure CreateEmpty()
-        {
-            return new PortableTypeStructure(new[] { new PortableTypeStructureEntry[0] }, 
-                new PortableTypeStructureJumpTable[1], new Dictionary<string, byte>());
-        }
-
-        /** Entries. */
-        private readonly PortableTypeStructureEntry[][] _paths;
-
-        /** Jumps. */
-        private readonly PortableTypeStructureJumpTable[] _jumps;
-
-        /** Field types. */
-        private readonly IDictionary<string, byte> _fieldTypes; 
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        /// <param name="paths">Paths.</param>
-        /// <param name="jumps">Jumps.</param>
-        /// <param name="fieldTypes">Field types.</param>
-        private PortableTypeStructure(PortableTypeStructureEntry[][] paths,
-            PortableTypeStructureJumpTable[] jumps, IDictionary<string, byte> fieldTypes)
-        {
-            _paths = paths;
-            _jumps = jumps;
-            _fieldTypes = fieldTypes;
-        }
-
-        /// <summary>
-        /// Gets field ID if possible.
-        /// </summary>
-        /// <param name="fieldName">Field name.</param>
-        /// <param name="fieldType">Field type.</param>
-        /// <param name="pathIdx">Path index, changes during jumps.</param>
-        /// <param name="actionIdx">Action index.</param>
-        /// <returns>Field ID or zero in case there are no matching path.</returns>
-        public int GetFieldId(string fieldName, byte fieldType, ref int pathIdx, int actionIdx)
-        {
-            Debug.Assert(pathIdx <= _paths.Length);
-
-            // Get path.
-            PortableTypeStructureEntry[] path = _paths[pathIdx];
-
-            if (actionIdx < path.Length)
-            {
-                // Get entry matching the action index.
-                PortableTypeStructureEntry entry = path[actionIdx];
-
-                if (entry.IsExpected(fieldName, fieldType))
-                    // Entry matches our expectations, return.
-                    return entry.Id;
-                else if (entry.IsJumpTable)
-                {
-                    // Entry is a pointer to a jump table.
-                    Debug.Assert(entry.Id < _jumps.Length);
-
-                    PortableTypeStructureJumpTable jmpTbl = _jumps[entry.Id];
-
-                    int pathIdx0 = jmpTbl.GetPathIndex(fieldName);
-
-                    if (pathIdx0 < 0)
-                        return 0;
-
-                    Debug.Assert(pathIdx < _paths.Length);
-
-                    entry = _paths[pathIdx][actionIdx];
-
-                    entry.ValidateType(fieldType);
-
-                    pathIdx = pathIdx0;
-
-                    return entry.Id;
-                }
-            }
-
-            // Failed to find anything because this is a new field.
-            return 0;
-        }
-
-        /// <summary>
-        /// Merge updates into a new type structure.
-        /// </summary>
-        /// <param name="exp">Expected type structure to apply updates to </param>
-        /// <param name="pathIdx">Path index.</param>
-        /// <param name="updates">Updates.</param>
-        /// <returns>New type structure with updates.</returns>
-        public PortableTypeStructure Merge(PortableTypeStructure exp, int pathIdx, 
-            IList<PortableTypeStructureUpdate> updates)
-        {
-            if (updates.Count == 0)
-                return this;
-
-            // Algorithm ensures that updates are applied to the same type structure,
-            // where they were initially observed. This allow us to keep structure
-            // internals simpler and more efficient. On the other hand, this imposes
-            // some performance hit because in case of concurrent update, recorded
-            // changes will be discarded and recorded again during the next write
-            // on the same path. This should occur only during application warmup.
-
-            // Note that field types are merged anyway to avoid metadata clashes.
-            PortableTypeStructure res = MergeFieldTypes(updates);
-
-            if (ReferenceEquals(exp, this))
-            {
-                PortableTypeStructureUpdate firstUpdate = updates[0];
-
-                if (firstUpdate.Index == 0)
-                {
-                    // Special case: the very first structure update. Simply attach all updates.
-                    Debug.Assert(_paths.Length == 1);
-                    Debug.Assert(_paths[0].Length == 0);
-                    Debug.Assert(pathIdx == 0);
-
-                    PortableTypeStructureEntry[][] newPaths = CopyPaths(updates.Count, 0);
-
-                    ApplyUpdatesToPath(newPaths[0], updates);
-
-                    res = new PortableTypeStructure(newPaths, _jumps, res._fieldTypes);
-                }
-                else
-                {
-                    // Get entry where updates should start.
-                    PortableTypeStructureEntry[] path = _paths[pathIdx];
-
-                    PortableTypeStructureEntry startEntry = default(PortableTypeStructureEntry);
-
-                    if (firstUpdate.Index < path.Length)
-                        startEntry = path[firstUpdate.Index];
-
-                    if (startEntry.IsEmpty)
-                    {
-                        // We are on the empty/non-existend entry. Continue the path without branching.
-                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 0);
-
-                        ApplyUpdatesToPath(newPaths[pathIdx], updates);
-
-                        res = new PortableTypeStructure(newPaths, _jumps, res._fieldTypes);
-                    }
-                    else if (startEntry.IsJumpTable)
-                    {
-                        // We are on the jump table. Add a new path and record it in the jump table.
-
-                        // 1. Preapare new structures.
-                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 1);
-                        var newJumps = CopyJumps(0);
-
-                        // New path will be the last one.
-                        int newPathIdx = newPaths.Length - 1;
-
-                        // Apply updats to the new path.
-                        ApplyUpdatesToPath(newPaths[newPathIdx], updates);
-
-                        // Add new jump to the table.
-                        newJumps[startEntry.Id] = 
-                            newJumps[startEntry.Id].CopyAndAdd(firstUpdate.FieldName, newPathIdx);
-
-                        res = new PortableTypeStructure(newPaths, newJumps, res._fieldTypes);
-                    }
-                    else
-                    {
-                        // We are on existing entry. Need to create a new jump table here and two new paths.
-
-                        // 1. Preapare new structures.
-                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 2);
-                        var newJumps = CopyJumps(1);
-
-                        // Old path will be moved here.
-                        int oldPathIdx = newPaths.Length - 2;
-
-                        // New path will reside here.
-                        int newPathIdx = newPaths.Length - 1;
-
-                        // Create new jump table.
-                        int newJumpIdx = newJumps.Length - 1;
-
-                        newJumps[newJumpIdx] = new PortableTypeStructureJumpTable(startEntry.Name, oldPathIdx,
-                            firstUpdate.FieldName, newPathIdx);
-
-                        // Re-create old path in two steps: move old path to the new place, then clean the old path.
-                        for (int i = firstUpdate.Index; i < path.Length; i++)
-                        {
-                            newPaths[oldPathIdx][i] = newPaths[pathIdx][i];
-
-                            newPaths[pathIdx][i] = new PortableTypeStructureEntry();
-                        }
-
-                        // Apply updats to the new path.
-                        ApplyUpdatesToPath(newPaths[newPaths.Length - 1], updates);
-
-                        res = new PortableTypeStructure(newPaths, newJumps, res._fieldTypes);
-                    }
-
-                }
-            }
-
-            return res;
-        }
-
-        /// <summary>
-        /// Copy and possible expand paths.
-        /// </summary>
-        /// <param name="minLen">Minimum length.</param>
-        /// <param name="additionalPaths">Amount of additional paths required.</param>
-        /// <returns>Result.</returns>
-        private PortableTypeStructureEntry[][] CopyPaths(int minLen, int additionalPaths)
-        {
-            var newPaths = new PortableTypeStructureEntry[_paths.Length + additionalPaths][];
-
-            int newPathLen = Math.Max(_paths[0].Length, minLen);
-
-            for (int i = 0; i < _paths.Length; i++)
-            {
-                newPaths[i] = new PortableTypeStructureEntry[newPathLen];
-
-                Array.Copy(_paths[i], newPaths[i], _paths[i].Length);
-            }
-
-            return newPaths;
-        }
-
-        /// <summary>
-        /// Copy and possible expand jump tables.
-        /// </summary>
-        /// <param name="additionalJumps">Additional jumps.</param>
-        /// <returns>Result.</returns>
-        private PortableTypeStructureJumpTable[] CopyJumps(int additionalJumps)
-        {
-            var newJumps = new PortableTypeStructureJumpTable[_jumps.Length + additionalJumps];
-
-            for (int i = 0; i < _jumps.Length; i++)
-                newJumps[i] = _jumps[i].Copy();
-
-            return newJumps;
-        }
-
-        /// <summary>
-        /// Apply updates to path.
-        /// </summary>
-        /// <param name="path">Path.</param>
-        /// <param name="updates">Updates.</param>
-        private static void ApplyUpdatesToPath(IList<PortableTypeStructureEntry> path,
-            IEnumerable<PortableTypeStructureUpdate> updates)
-        {
-            foreach (var u in updates)
-                path[u.Index] = new PortableTypeStructureEntry(u.FieldName, u.FieldId, u.FieldType);
-        }
-
-        /// <summary>
-        /// Merge field types.
-        /// </summary>
-        /// <param name="updates">Updates.</param>
-        /// <returns>Type structure with applied updates.</returns>
-        private PortableTypeStructure MergeFieldTypes(IList<PortableTypeStructureUpdate> updates)
-        {
-            IDictionary<string, byte> newFieldTypes = new Dictionary<string, byte>(_fieldTypes);
-
-            foreach (PortableTypeStructureUpdate update in updates)
-            {
-                byte expType;
-
-                if (_fieldTypes.TryGetValue(update.FieldName, out expType))
-                {
-                    // This is an old field.
-                    if (expType != update.FieldType)
-                    {
-                        throw new PortableException("Field type mismatch detected [fieldName=" + update.FieldName +
-                            ", expectedType=" + expType + ", actualType=" + update.FieldType + ']');
-                    }
-                }
-                else
-                    // This is a new field.
-                    newFieldTypes[update.FieldName] = update.FieldType;
-            }
-
-            return newFieldTypes.Count == _fieldTypes.Count ? 
-                this : new PortableTypeStructure(_paths, _jumps, newFieldTypes);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs
deleted file mode 100644
index e939d56..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureEntry.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.Metadata.Opto
-{
-    using System.Diagnostics;
-    using Apache.Ignite.Core.Portable;
-
-    /// <summary>
-    /// Portable type structure entry. Might be either a normal field or a reference to jump table.
-    /// </summary>
-    internal struct PortableTypeStructureEntry
-    {
-        /** Field name. */
-        private readonly string _name;
-
-        /** Field ID. */
-        private readonly int _id;
-
-        /** Field type. */
-        private readonly byte _type;
-        
-        /// <summary>
-        /// Constructor for jump table entry.
-        /// </summary>
-        /// <param name="jumpTblIdx"></param>
-        public PortableTypeStructureEntry(int jumpTblIdx)
-        {
-            Debug.Assert(jumpTblIdx > 0);
-
-            _name = null;
-            _id = jumpTblIdx;
-            _type = 0;
-        }
-
-        /// <summary>
-        /// Constructor for field entry.
-        /// </summary>
-        /// <param name="name">Field name.</param>
-        /// <param name="id">Field ID.</param>
-        /// <param name="type">Field type.</param>
-        public PortableTypeStructureEntry(string name, int id, byte type)
-        {
-            Debug.Assert(name != null);
-
-            _name = name;
-            _id = id;
-            _type = type;
-        }
-
-        /// <summary>
-        /// Check whether current field entry matches passed arguments.
-        /// </summary>
-        /// <param name="name"></param>
-        /// <param name="type"></param>
-        /// <returns></returns>
-        public bool IsExpected(string name, byte type)
-        {
-            if (!ReferenceEquals(_name, name) && !_name.Equals(name))
-                return false;
-
-            ValidateType(type);
-
-            return true;
-        }
-
-        /// <summary>
-        /// Valide field type.
-        /// </summary>
-        /// <param name="type">Expected type.</param>
-        public void ValidateType(byte type)
-        {
-            if (_type != type)
-            {
-                throw new PortableException("Field type mismatch detected [fieldName=" + _name +
-                    ", expectedType=" + _type + ", actualType=" + type + ']');
-            }
-        }
-
-        /// <summary>
-        /// Whether this is an empty entry.
-        /// </summary>
-        /// <returns></returns>
-        public bool IsEmpty
-        {
-            get { return _id == 0; }
-        }
-
-        /// <summary>
-        /// Whether this is a jump table.
-        /// </summary>
-        public bool IsJumpTable
-        {
-            get { return _name == null && _id >= 0; }
-        }
-
-        /// <summary>
-        /// Field name.
-        /// </summary>
-        public string Name
-        {
-            get { return _name; }
-        }
-
-        /// <summary>
-        /// Field ID.
-        /// </summary>
-        public int Id
-        {
-            get { return _id; }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs
deleted file mode 100644
index b2409db..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureJumpTable.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.Metadata.Opto
-{
-    using System;
-    using System.Diagnostics;
-
-    /// <summary>
-    /// Jump table.
-    /// </summary>
-    internal class PortableTypeStructureJumpTable
-    {
-        /** Names. */
-        private readonly string[] _names;
-
-        /** Path indexes. */
-        private readonly int[] _pathIdxs;
-
-        /// <summary>
-        /// Create jump table with two entries.
-        /// </summary>
-        /// <param name="firstName">First name.</param>
-        /// <param name="firstPathIdx">First path index.</param>
-        /// <param name="secondName">Second name.</param>
-        /// <param name="secondPathIdx">Second path index.</param>
-        public PortableTypeStructureJumpTable(string firstName, int firstPathIdx, 
-            string secondName, int secondPathIdx)
-        {
-            _names = new[] { firstName, secondName };
-            _pathIdxs = new[] { firstPathIdx, secondPathIdx };
-        }
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        /// <param name="names">Field names.</param>
-        /// <param name="pathIdxs">Path indexes.</param>
-        private PortableTypeStructureJumpTable(string[] names, int[] pathIdxs)
-        {
-            Debug.Assert(_names.Length > 1);
-            Debug.Assert(_names.Length == pathIdxs.Length);
-            
-            _names = names;
-            _pathIdxs = pathIdxs;
-        }
-
-        /// <summary>
-        /// Get path index for the given field.
-        /// </summary>
-        /// <param name="fieldName">Field name.</param>
-        /// <returns>Path index.</returns>
-        public int GetPathIndex(string fieldName)
-        {
-            Debug.Assert(fieldName != null);
-            
-            // Optimistically assume that field name is a literal.
-            for (var i = 0; i < _names.Length; i++)
-            {
-                if (ReferenceEquals(fieldName, _names[i]))
-                    return _pathIdxs[i];
-            }
-
-            // Fallback to slow-path with normal string comparison.
-            for (var i = 0; i < _names.Length; i++)
-            {
-                if (fieldName.Equals(_names[i]))
-                    return _pathIdxs[i];
-            }
-
-            // No path found for the field.
-            return -1;
-        }
-
-        /// <summary>
-        /// Copy jump table.
-        /// </summary>
-        /// <returns>New jump table.</returns>
-        public PortableTypeStructureJumpTable Copy()
-        {
-            return new PortableTypeStructureJumpTable(_names, _pathIdxs);
-        }
-
-        /// <summary>
-        /// Copy jump table with additional jump.
-        /// </summary>
-        /// <param name="name">Field name.</param>
-        /// <param name="pathIdx">Path index.</param>
-        /// <returns>New jump table.</returns>
-        public PortableTypeStructureJumpTable CopyAndAdd(string name, int pathIdx)
-        {
-            var newNames = new string[_names.Length + 1];
-            var pathIdxs = new int[_pathIdxs.Length + 1];
-
-            Array.Copy(_names, newNames, _names.Length);
-            Array.Copy(_pathIdxs, pathIdxs, _pathIdxs.Length);
-
-            return new PortableTypeStructureJumpTable(newNames, pathIdxs);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs
deleted file mode 100644
index 56e0c12..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/Opto/PortableTypeStructureUpdate.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.Metadata.Opto
-{
-    /// <summary>
-    /// Portable type structure update descriptor.
-    /// </summary>
-    class PortableTypeStructureUpdate
-    {
-        /** Field name. */
-        private readonly string _fieldName;
-
-        /** Field ID. */
-        private readonly int _fieldId;
-
-        /** Field type. */
-        private readonly byte _fieldType;
-
-        /** Field index. */
-        private readonly int _idx;
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        /// <param name="fieldName">Field name.</param>
-        /// <param name="fieldId">Field ID.</param>
-        /// <param name="fieldType">Field type.</param>
-        /// <param name="idx">Index.</param>
-        public PortableTypeStructureUpdate(string fieldName, int fieldId, byte fieldType, int idx)
-        {
-            _fieldName = fieldName;
-            _fieldId = fieldId;
-            _fieldType = fieldType;
-            _idx = idx;
-        }
-
-        /// <summary>
-        /// Field name.
-        /// </summary>
-        public string FieldName
-        {
-            get { return _fieldName; }
-        }
-
-        /// <summary>
-        /// Field ID.
-        /// </summary>
-        public int FieldId
-        {
-            get { return _fieldId; }
-        }
-
-        /// <summary>
-        /// Field type.
-        /// </summary>
-        public byte FieldType
-        {
-            get { return _fieldType; }
-        }
-
-        /// <summary>
-        /// Index.
-        /// </summary>
-        public int Index
-        {
-            get { return _idx; }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
index d1a714b..247a0b0 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
@@ -19,7 +19,7 @@ namespace Apache.Ignite.Core.Impl.Portable
 {
     using System;
     using System.Collections.Generic;
-    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
+    using Apache.Ignite.Core.Impl.Portable.Structure;
     using Apache.Ignite.Core.Portable;
 
     /// <summary>
@@ -58,7 +58,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         private readonly string _affKeyFieldName;
 
         /** Type structure. */
-        private volatile PortableTypeStructure _typeStruct = PortableTypeStructure.CreateEmpty();
+        private volatile PortableStructure _typeStruct = PortableStructure.CreateEmpty();
 
         /// <summary>
         /// Constructor.
@@ -178,14 +178,14 @@ namespace Apache.Ignite.Core.Impl.Portable
         }
 
         /** <inheritDoc /> */
-        public PortableTypeStructure TypeStructure
+        public PortableStructure TypeStructure
         {
             get { return _typeStruct; }
         }
 
         /** <inheritDoc /> */
-        public void UpdateStrcuture(PortableTypeStructure exp, int pathIdx, 
-            IList<PortableTypeStructureUpdate> updates)
+        public void UpdateStrcuture(PortableStructure exp, int pathIdx, 
+            IList<PortableStructureUpdate> updates)
         {
             lock (this)
             {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
index adbb6bb..103dd75 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableSurrogateTypeDescriptor.cs
@@ -19,7 +19,7 @@ namespace Apache.Ignite.Core.Impl.Portable
 {
     using System;
     using System.Collections.Generic;
-    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
+    using Apache.Ignite.Core.Impl.Portable.Structure;
     using Apache.Ignite.Core.Portable;
 
     /// <summary>
@@ -38,7 +38,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         private readonly string _name;
 
         /** Type structure. */
-        private volatile PortableTypeStructure _typeStruct = PortableTypeStructure.CreateEmpty();
+        private volatile PortableStructure _typeStruct = PortableStructure.CreateEmpty();
 
         /// <summary>
         /// Constructor.
@@ -125,14 +125,14 @@ namespace Apache.Ignite.Core.Impl.Portable
         }
 
         /** <inheritDoc /> */
-        public PortableTypeStructure TypeStructure
+        public PortableStructure TypeStructure
         {
             get { return _typeStruct; }
         }
 
         /** <inheritDoc /> */
-        public void UpdateStrcuture(PortableTypeStructure exp, int pathIdx,
-            IList<PortableTypeStructureUpdate> updates)
+        public void UpdateStrcuture(PortableStructure exp, int pathIdx,
+            IList<PortableStructureUpdate> updates)
         {
             lock (this)
             {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/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 9727377..cafc69d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
@@ -24,7 +24,7 @@ namespace Apache.Ignite.Core.Impl.Portable
 
     using Apache.Ignite.Core.Impl.Portable.IO;
     using Apache.Ignite.Core.Impl.Portable.Metadata;
-    using Apache.Ignite.Core.Impl.Portable.Metadata.Opto;
+    using Apache.Ignite.Core.Impl.Portable.Structure;
     using Apache.Ignite.Core.Portable;
 
     using PU = PortableUtils;
@@ -61,10 +61,17 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Current raw position. */
         private long _curRawPos;
 
-        private PortableTypeStructure _curTypeStruct;
-        private int _curPathIdx;
-        private int _curActionIdx;
-        private List<PortableTypeStructureUpdate> _curUpdates; 
+        /** Current type structure. */
+        private PortableStructure _curStruct;
+
+        /** Current type structure path index. */
+        private int _curStructPath;
+
+        /** Current type structure action index. */
+        private int _curStructAction;
+
+        /** Current type structure updates. */
+        private List<PortableStructureUpdate> _curStructUpdates; 
         
         /** Whether we are currently detaching an object. */
         private bool _detaching;
@@ -1306,10 +1313,10 @@ namespace Apache.Ignite.Core.Impl.Portable
                 IPortableIdMapper oldMapper = _curMapper;
                 long oldRawPos = _curRawPos;
                 
-                PortableTypeStructure oldTypeStruct = _curTypeStruct;
-                int oldPathIdx = _curPathIdx;
-                int oldActionIdx = _curActionIdx;
-                var oldUpdates = _curUpdates;
+                PortableStructure oldStruct = _curStruct;
+                int oldStructPath = _curStructPath;
+                int oldStructIdx = _curStructAction;
+                var oldStructUpdates = _curStructUpdates;
 
                 // Push new frame.
                 _curTypeId = desc.TypeId;
@@ -1317,10 +1324,10 @@ namespace Apache.Ignite.Core.Impl.Portable
                 _curMapper = desc.Mapper;
                 _curRawPos = 0;
 
-                _curTypeStruct = desc.TypeStructure;
-                _curPathIdx = 0;
-                _curActionIdx = 0;
-                _curUpdates = null;
+                _curStruct = desc.TypeStructure;
+                _curStructPath = 0;
+                _curStructAction = 0;
+                _curStructUpdates = null;
 
                 // Write object fields.
                 desc.Serializer.WritePortable(obj, this);
@@ -1335,16 +1342,16 @@ namespace Apache.Ignite.Core.Impl.Portable
                 else
                     _stream.WriteInt(pos + 14, len);
 
-                // 13. Apply structure updates if any.
-                if (_curUpdates != null)
+                // Apply structure updates if any.
+                if (_curStructUpdates != null)
                 {
-                    desc.UpdateStrcuture(_curTypeStruct, _curPathIdx, _curUpdates);
+                    desc.UpdateStrcuture(_curStruct, _curStructPath, _curStructUpdates);
 
                     IPortableMetadataHandler metaHnd = _marsh.MetadataHandler(desc);
 
                     if (metaHnd != null)
                     {
-                        foreach (var u in _curUpdates)
+                        foreach (var u in _curStructUpdates)
                             metaHnd.OnFieldWrite(u.FieldId, u.FieldName, u.FieldType);
 
                         IDictionary<string, int> meta = metaHnd.OnObjectWriteFinished();
@@ -1360,10 +1367,10 @@ namespace Apache.Ignite.Core.Impl.Portable
                 _curMapper = oldMapper;
                 _curRawPos = oldRawPos;
 
-                _curTypeStruct = oldTypeStruct;
-                _curPathIdx = oldPathIdx;
-                _curActionIdx = oldActionIdx;
-                _curUpdates = oldUpdates;
+                _curStruct = oldStruct;
+                _curStructPath = oldStructPath;
+                _curStructAction = oldStructIdx;
+                _curStructUpdates = oldStructUpdates;
             }
             else
             {
@@ -1620,19 +1627,19 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (_curRawPos != 0)
                 throw new PortableException("Cannot write named fields after raw data is written.");
 
-            int actionIdx = _curActionIdx++;
+            int action = _curStructAction++;
 
             int fieldId;
 
-            if (_curUpdates == null)
+            if (_curStructUpdates == null)
             {
-                fieldId = _curTypeStruct.GetFieldId(fieldName, fieldTypeId, ref _curPathIdx, actionIdx);
+                fieldId = _curStruct.GetFieldId(fieldName, fieldTypeId, ref _curStructPath, action);
 
                 if (fieldId == 0)
-                    fieldId = GetNewFieldId(fieldName, fieldTypeId, actionIdx);
+                    fieldId = GetNewFieldId(fieldName, fieldTypeId, action);
             }
             else
-                fieldId = GetNewFieldId(fieldName, fieldTypeId, actionIdx);
+                fieldId = GetNewFieldId(fieldName, fieldTypeId, action);
 
             _stream.WriteInt(fieldId);
         }
@@ -1640,15 +1647,18 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <summary>
         /// Get ID for the new field and save structure update.
         /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <param name="fieldTypeId">Field type ID.</param>
+        /// <param name="action">Action index.</param>
         /// <returns>Field ID.</returns>
-        private int GetNewFieldId(string fieldName, byte fieldTypeId, int actionIdx)
+        private int GetNewFieldId(string fieldName, byte fieldTypeId, int action)
         {
             int fieldId = PU.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
 
-            if (_curUpdates == null)
-                _curUpdates = new List<PortableTypeStructureUpdate>();
+            if (_curStructUpdates == null)
+                _curStructUpdates = new List<PortableStructureUpdate>();
 
-            _curUpdates.Add(new PortableTypeStructureUpdate(fieldName, fieldId, fieldTypeId, actionIdx));
+            _curStructUpdates.Add(new PortableStructureUpdate(fieldName, fieldId, fieldTypeId, action));
 
             return fieldId;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs
new file mode 100644
index 0000000..c434110
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructure.cs
@@ -0,0 +1,317 @@
+/*
+ * 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.Structure
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Portable type structure. Cache field IDs and metadata to improve marshalling performance.
+    /// Every object write contains a set of field writes. Every unique ordered set of written fields
+    /// produce write "path". We cache these paths allowing for very fast traverse over object structure
+    /// without expensive map lookups and field ID calculations. 
+    /// </summary>
+    internal class PortableStructure
+    {
+        /// <summary>
+        /// Create empty type structure.
+        /// </summary>
+        /// <returns>Empty type structure.</returns>
+        public static PortableStructure CreateEmpty()
+        {
+            return new PortableStructure(new[] { new PortableStructureEntry[0] }, 
+                new PortableStructureJumpTable[1], new Dictionary<string, byte>());
+        }
+
+        /** Entries. */
+        private readonly PortableStructureEntry[][] _paths;
+
+        /** Jumps. */
+        private readonly PortableStructureJumpTable[] _jumps;
+
+        /** Field types. */
+        private readonly IDictionary<string, byte> _fieldTypes; 
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="paths">Paths.</param>
+        /// <param name="jumps">Jumps.</param>
+        /// <param name="fieldTypes">Field types.</param>
+        private PortableStructure(PortableStructureEntry[][] paths,
+            PortableStructureJumpTable[] jumps, IDictionary<string, byte> fieldTypes)
+        {
+            _paths = paths;
+            _jumps = jumps;
+            _fieldTypes = fieldTypes;
+        }
+
+        /// <summary>
+        /// Gets field ID if possible.
+        /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <param name="fieldType">Field type.</param>
+        /// <param name="pathIdx">Path index, changes during jumps.</param>
+        /// <param name="actionIdx">Action index.</param>
+        /// <returns>Field ID or zero in case there are no matching path.</returns>
+        public int GetFieldId(string fieldName, byte fieldType, ref int pathIdx, int actionIdx)
+        {
+            Debug.Assert(pathIdx <= _paths.Length);
+
+            // Get path.
+            PortableStructureEntry[] path = _paths[pathIdx];
+
+            if (actionIdx < path.Length)
+            {
+                // Get entry matching the action index.
+                PortableStructureEntry entry = path[actionIdx];
+
+                if (entry.IsExpected(fieldName, fieldType))
+                    // Entry matches our expectations, return.
+                    return entry.Id;
+                else if (entry.IsJumpTable)
+                {
+                    // Entry is a pointer to a jump table.
+                    Debug.Assert(entry.Id < _jumps.Length);
+
+                    PortableStructureJumpTable jmpTbl = _jumps[entry.Id];
+
+                    int pathIdx0 = jmpTbl.GetPathIndex(fieldName);
+
+                    if (pathIdx0 < 0)
+                        return 0;
+
+                    Debug.Assert(pathIdx < _paths.Length);
+
+                    entry = _paths[pathIdx][actionIdx];
+
+                    entry.ValidateType(fieldType);
+
+                    pathIdx = pathIdx0;
+
+                    return entry.Id;
+                }
+            }
+
+            // Failed to find anything because this is a new field.
+            return 0;
+        }
+
+        /// <summary>
+        /// Merge updates into a new type structure.
+        /// </summary>
+        /// <param name="exp">Expected type structure to apply updates to </param>
+        /// <param name="pathIdx">Path index.</param>
+        /// <param name="updates">Updates.</param>
+        /// <returns>New type structure with updates.</returns>
+        public PortableStructure Merge(PortableStructure exp, int pathIdx, 
+            IList<PortableStructureUpdate> updates)
+        {
+            if (updates.Count == 0)
+                return this;
+
+            // Algorithm ensures that updates are applied to the same type structure,
+            // where they were initially observed. This allow us to keep structure
+            // internals simpler and more efficient. On the other hand, this imposes
+            // some performance hit because in case of concurrent update, recorded
+            // changes will be discarded and recorded again during the next write
+            // on the same path. This should occur only during application warmup.
+
+            // Note that field types are merged anyway to avoid metadata clashes.
+            PortableStructure res = MergeFieldTypes(updates);
+
+            if (ReferenceEquals(exp, this))
+            {
+                PortableStructureUpdate firstUpdate = updates[0];
+
+                if (firstUpdate.Index == 0)
+                {
+                    // Special case: the very first structure update. Simply attach all updates.
+                    Debug.Assert(_paths.Length == 1);
+                    Debug.Assert(_paths[0].Length == 0);
+                    Debug.Assert(pathIdx == 0);
+
+                    PortableStructureEntry[][] newPaths = CopyPaths(updates.Count, 0);
+
+                    ApplyUpdatesToPath(newPaths[0], updates);
+
+                    res = new PortableStructure(newPaths, _jumps, res._fieldTypes);
+                }
+                else
+                {
+                    // Get entry where updates should start.
+                    PortableStructureEntry[] path = _paths[pathIdx];
+
+                    PortableStructureEntry startEntry = default(PortableStructureEntry);
+
+                    if (firstUpdate.Index < path.Length)
+                        startEntry = path[firstUpdate.Index];
+
+                    if (startEntry.IsEmpty)
+                    {
+                        // We are on the empty/non-existend entry. Continue the path without branching.
+                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 0);
+
+                        ApplyUpdatesToPath(newPaths[pathIdx], updates);
+
+                        res = new PortableStructure(newPaths, _jumps, res._fieldTypes);
+                    }
+                    else if (startEntry.IsJumpTable)
+                    {
+                        // We are on the jump table. Add a new path and record it in the jump table.
+
+                        // 1. Preapare new structures.
+                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 1);
+                        var newJumps = CopyJumps(0);
+
+                        // New path will be the last one.
+                        int newPathIdx = newPaths.Length - 1;
+
+                        // Apply updats to the new path.
+                        ApplyUpdatesToPath(newPaths[newPathIdx], updates);
+
+                        // Add new jump to the table.
+                        newJumps[startEntry.Id] = 
+                            newJumps[startEntry.Id].CopyAndAdd(firstUpdate.FieldName, newPathIdx);
+
+                        res = new PortableStructure(newPaths, newJumps, res._fieldTypes);
+                    }
+                    else
+                    {
+                        // We are on existing entry. Need to create a new jump table here and two new paths.
+
+                        // 1. Preapare new structures.
+                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 2);
+                        var newJumps = CopyJumps(1);
+
+                        // Old path will be moved here.
+                        int oldPathIdx = newPaths.Length - 2;
+
+                        // New path will reside here.
+                        int newPathIdx = newPaths.Length - 1;
+
+                        // Create new jump table.
+                        int newJumpIdx = newJumps.Length - 1;
+
+                        newJumps[newJumpIdx] = new PortableStructureJumpTable(startEntry.Name, oldPathIdx,
+                            firstUpdate.FieldName, newPathIdx);
+
+                        // Re-create old path in two steps: move old path to the new place, then clean the old path.
+                        for (int i = firstUpdate.Index; i < path.Length; i++)
+                        {
+                            newPaths[oldPathIdx][i] = newPaths[pathIdx][i];
+
+                            newPaths[pathIdx][i] = new PortableStructureEntry();
+                        }
+
+                        // Apply updats to the new path.
+                        ApplyUpdatesToPath(newPaths[newPaths.Length - 1], updates);
+
+                        res = new PortableStructure(newPaths, newJumps, res._fieldTypes);
+                    }
+
+                }
+            }
+
+            return res;
+        }
+
+        /// <summary>
+        /// Copy and possible expand paths.
+        /// </summary>
+        /// <param name="minLen">Minimum length.</param>
+        /// <param name="additionalPaths">Amount of additional paths required.</param>
+        /// <returns>Result.</returns>
+        private PortableStructureEntry[][] CopyPaths(int minLen, int additionalPaths)
+        {
+            var newPaths = new PortableStructureEntry[_paths.Length + additionalPaths][];
+
+            int newPathLen = Math.Max(_paths[0].Length, minLen);
+
+            for (int i = 0; i < _paths.Length; i++)
+            {
+                newPaths[i] = new PortableStructureEntry[newPathLen];
+
+                Array.Copy(_paths[i], newPaths[i], _paths[i].Length);
+            }
+
+            return newPaths;
+        }
+
+        /// <summary>
+        /// Copy and possible expand jump tables.
+        /// </summary>
+        /// <param name="additionalJumps">Additional jumps.</param>
+        /// <returns>Result.</returns>
+        private PortableStructureJumpTable[] CopyJumps(int additionalJumps)
+        {
+            var newJumps = new PortableStructureJumpTable[_jumps.Length + additionalJumps];
+
+            for (int i = 0; i < _jumps.Length; i++)
+                newJumps[i] = _jumps[i].Copy();
+
+            return newJumps;
+        }
+
+        /// <summary>
+        /// Apply updates to path.
+        /// </summary>
+        /// <param name="path">Path.</param>
+        /// <param name="updates">Updates.</param>
+        private static void ApplyUpdatesToPath(IList<PortableStructureEntry> path,
+            IEnumerable<PortableStructureUpdate> updates)
+        {
+            foreach (var u in updates)
+                path[u.Index] = new PortableStructureEntry(u.FieldName, u.FieldId, u.FieldType);
+        }
+
+        /// <summary>
+        /// Merge field types.
+        /// </summary>
+        /// <param name="updates">Updates.</param>
+        /// <returns>Type structure with applied updates.</returns>
+        private PortableStructure MergeFieldTypes(IList<PortableStructureUpdate> updates)
+        {
+            IDictionary<string, byte> newFieldTypes = new Dictionary<string, byte>(_fieldTypes);
+
+            foreach (PortableStructureUpdate update in updates)
+            {
+                byte expType;
+
+                if (_fieldTypes.TryGetValue(update.FieldName, out expType))
+                {
+                    // This is an old field.
+                    if (expType != update.FieldType)
+                    {
+                        throw new PortableException("Field type mismatch detected [fieldName=" + update.FieldName +
+                            ", expectedType=" + expType + ", actualType=" + update.FieldType + ']');
+                    }
+                }
+                else
+                    // This is a new field.
+                    newFieldTypes[update.FieldName] = update.FieldType;
+            }
+
+            return newFieldTypes.Count == _fieldTypes.Count ? 
+                this : new PortableStructure(_paths, _jumps, newFieldTypes);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs
new file mode 100644
index 0000000..5229a95
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureEntry.cs
@@ -0,0 +1,128 @@
+/*
+ * 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.Structure
+{
+    using System.Diagnostics;
+
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Portable type structure entry. Might be either a normal field or a reference to jump table.
+    /// </summary>
+    internal struct PortableStructureEntry
+    {
+        /** Field name. */
+        private readonly string _name;
+
+        /** Field ID. */
+        private readonly int _id;
+
+        /** Field type. */
+        private readonly byte _type;
+        
+        /// <summary>
+        /// Constructor for jump table entry.
+        /// </summary>
+        /// <param name="jumpTblIdx">Jump table index.</param>
+        public PortableStructureEntry(int jumpTblIdx)
+        {
+            Debug.Assert(jumpTblIdx > 0);
+
+            _name = null;
+            _id = jumpTblIdx;
+            _type = 0;
+        }
+
+        /// <summary>
+        /// Constructor for field entry.
+        /// </summary>
+        /// <param name="name">Field name.</param>
+        /// <param name="id">Field ID.</param>
+        /// <param name="type">Field type.</param>
+        public PortableStructureEntry(string name, int id, byte type)
+        {
+            Debug.Assert(name != null);
+
+            _name = name;
+            _id = id;
+            _type = type;
+        }
+
+        /// <summary>
+        /// Check whether current field entry matches passed arguments.
+        /// </summary>
+        /// <param name="name"></param>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public bool IsExpected(string name, byte type)
+        {
+            if (!ReferenceEquals(_name, name) && !_name.Equals(name))
+                return false;
+
+            ValidateType(type);
+
+            return true;
+        }
+
+        /// <summary>
+        /// Valide field type.
+        /// </summary>
+        /// <param name="type">Expected type.</param>
+        public void ValidateType(byte type)
+        {
+            if (_type != type)
+            {
+                throw new PortableException("Field type mismatch detected [fieldName=" + _name +
+                    ", expectedType=" + _type + ", actualType=" + type + ']');
+            }
+        }
+
+        /// <summary>
+        /// Whether this is an empty entry.
+        /// </summary>
+        /// <returns></returns>
+        public bool IsEmpty
+        {
+            get { return _id == 0; }
+        }
+
+        /// <summary>
+        /// Whether this is a jump table.
+        /// </summary>
+        public bool IsJumpTable
+        {
+            get { return _name == null && _id >= 0; }
+        }
+
+        /// <summary>
+        /// Field name.
+        /// </summary>
+        public string Name
+        {
+            get { return _name; }
+        }
+
+        /// <summary>
+        /// Field ID.
+        /// </summary>
+        public int Id
+        {
+            get { return _id; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs
new file mode 100644
index 0000000..85e71c4
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureJumpTable.cs
@@ -0,0 +1,115 @@
+/*
+ * 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.Structure
+{
+    using System;
+    using System.Diagnostics;
+
+    /// <summary>
+    /// Jump table.
+    /// </summary>
+    internal class PortableStructureJumpTable
+    {
+        /** Names. */
+        private readonly string[] _names;
+
+        /** Path indexes. */
+        private readonly int[] _pathIdxs;
+
+        /// <summary>
+        /// Create jump table with two entries.
+        /// </summary>
+        /// <param name="firstName">First name.</param>
+        /// <param name="firstPathIdx">First path index.</param>
+        /// <param name="secondName">Second name.</param>
+        /// <param name="secondPathIdx">Second path index.</param>
+        public PortableStructureJumpTable(string firstName, int firstPathIdx, 
+            string secondName, int secondPathIdx)
+        {
+            _names = new[] { firstName, secondName };
+            _pathIdxs = new[] { firstPathIdx, secondPathIdx };
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="names">Field names.</param>
+        /// <param name="pathIdxs">Path indexes.</param>
+        private PortableStructureJumpTable(string[] names, int[] pathIdxs)
+        {
+            Debug.Assert(_names.Length > 1);
+            Debug.Assert(_names.Length == pathIdxs.Length);
+            
+            _names = names;
+            _pathIdxs = pathIdxs;
+        }
+
+        /// <summary>
+        /// Get path index for the given field.
+        /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <returns>Path index.</returns>
+        public int GetPathIndex(string fieldName)
+        {
+            Debug.Assert(fieldName != null);
+            
+            // Optimistically assume that field name is a literal.
+            for (var i = 0; i < _names.Length; i++)
+            {
+                if (ReferenceEquals(fieldName, _names[i]))
+                    return _pathIdxs[i];
+            }
+
+            // Fallback to slow-path with normal string comparison.
+            for (var i = 0; i < _names.Length; i++)
+            {
+                if (fieldName.Equals(_names[i]))
+                    return _pathIdxs[i];
+            }
+
+            // No path found for the field.
+            return -1;
+        }
+
+        /// <summary>
+        /// Copy jump table.
+        /// </summary>
+        /// <returns>New jump table.</returns>
+        public PortableStructureJumpTable Copy()
+        {
+            return new PortableStructureJumpTable(_names, _pathIdxs);
+        }
+
+        /// <summary>
+        /// Copy jump table with additional jump.
+        /// </summary>
+        /// <param name="name">Field name.</param>
+        /// <param name="pathIdx">Path index.</param>
+        /// <returns>New jump table.</returns>
+        public PortableStructureJumpTable CopyAndAdd(string name, int pathIdx)
+        {
+            var newNames = new string[_names.Length + 1];
+            var pathIdxs = new int[_pathIdxs.Length + 1];
+
+            Array.Copy(_names, newNames, _names.Length);
+            Array.Copy(_pathIdxs, pathIdxs, _pathIdxs.Length);
+
+            return new PortableStructureJumpTable(newNames, pathIdxs);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b34084eb/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureUpdate.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureUpdate.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureUpdate.cs
new file mode 100644
index 0000000..fa239db
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/Structure/PortableStructureUpdate.cs
@@ -0,0 +1,84 @@
+/*
+ * 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.Structure
+{
+    /// <summary>
+    /// Portable type structure update descriptor.
+    /// </summary>
+    internal class PortableStructureUpdate
+    {
+        /** Field name. */
+        private readonly string _fieldName;
+
+        /** Field ID. */
+        private readonly int _fieldId;
+
+        /** Field type. */
+        private readonly byte _fieldType;
+
+        /** Field index. */
+        private readonly int _idx;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="fieldName">Field name.</param>
+        /// <param name="fieldId">Field ID.</param>
+        /// <param name="fieldType">Field type.</param>
+        /// <param name="idx">Index.</param>
+        public PortableStructureUpdate(string fieldName, int fieldId, byte fieldType, int idx)
+        {
+            _fieldName = fieldName;
+            _fieldId = fieldId;
+            _fieldType = fieldType;
+            _idx = idx;
+        }
+
+        /// <summary>
+        /// Field name.
+        /// </summary>
+        public string FieldName
+        {
+            get { return _fieldName; }
+        }
+
+        /// <summary>
+        /// Field ID.
+        /// </summary>
+        public int FieldId
+        {
+            get { return _fieldId; }
+        }
+
+        /// <summary>
+        /// Field type.
+        /// </summary>
+        public byte FieldType
+        {
+            get { return _fieldType; }
+        }
+
+        /// <summary>
+        /// Index.
+        /// </summary>
+        public int Index
+        {
+            get { return _idx; }
+        }
+    }
+}


[2/4] ignite git commit: IGNITE-1282: WIP on optos.

Posted by vo...@apache.org.
IGNITE-1282: WIP on optos.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/11f7d097
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/11f7d097
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/11f7d097

Branch: refs/heads/ignite-1282-opto
Commit: 11f7d097da6c83b1dac8427e8294b098d98db898
Parents: 9da45ed
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Wed Oct 7 11:31:38 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Wed Oct 7 11:31:38 2015 +0300

----------------------------------------------------------------------
 .../Portable/PortableWriteBenchmark.cs          |  2 +-
 .../Impl/Portable/PortableMarshaller.cs         |  1 +
 .../Impl/Portable/PortableWriterImpl.cs         | 73 +++++++++-----------
 3 files changed, 35 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/11f7d097/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
index 9fcfa46..5638195 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Portable/PortableWriteBenchmark.cs
@@ -46,7 +46,7 @@ namespace Apache.Ignite.Benchmarks.Portable
             {
                 TypeConfigurations = new List<PortableTypeConfiguration>
                 {
-                    new PortableTypeConfiguration(typeof (Address)) {MetadataEnabled = false}
+                    new PortableTypeConfiguration(typeof (Address)) {MetadataEnabled = true}
                 }
             });
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/11f7d097/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 c7a0b7b..c7262e1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs
@@ -309,6 +309,7 @@ namespace Apache.Ignite.Core.Impl.Portable
 
                 return new PortableHashsetMetadataHandler(ids, newType);
             }
+
             return null;
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/11f7d097/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 6a0917a..9727377 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
@@ -57,9 +57,6 @@ namespace Apache.Ignite.Core.Impl.Portable
 
         /** Current mapper. */
         private IPortableIdMapper _curMapper;
-
-        /** Current metadata handler. */
-        private IPortableMetadataHandler _curMetaHnd;
         
         /** Current raw position. */
         private long _curRawPos;
@@ -67,7 +64,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         private PortableTypeStructure _curTypeStruct;
         private int _curPathIdx;
         private int _curActionIdx;
-        private bool _curNewStruct;
         private List<PortableTypeStructureUpdate> _curUpdates; 
         
         /** Whether we are currently detaching an object. */
@@ -1308,26 +1304,22 @@ namespace Apache.Ignite.Core.Impl.Portable
                 int oldTypeId = _curTypeId;
                 IPortableNameMapper oldConverter = _curConverter;
                 IPortableIdMapper oldMapper = _curMapper;
-                IPortableMetadataHandler oldMetaHnd = _curMetaHnd;
                 long oldRawPos = _curRawPos;
                 
                 PortableTypeStructure oldTypeStruct = _curTypeStruct;
                 int oldPathIdx = _curPathIdx;
                 int oldActionIdx = _curActionIdx;
-                bool oldNewStruct = _curNewStruct;
                 var oldUpdates = _curUpdates;
 
                 // Push new frame.
                 _curTypeId = desc.TypeId;
                 _curConverter = desc.NameConverter;
                 _curMapper = desc.Mapper;
-                _curMetaHnd = desc.MetadataEnabled ? _marsh.MetadataHandler(desc) : null;
                 _curRawPos = 0;
 
                 _curTypeStruct = desc.TypeStructure;
                 _curPathIdx = 0;
                 _curActionIdx = 0;
-                _curNewStruct = false;
                 _curUpdates = null;
 
                 // Write object fields.
@@ -1343,30 +1335,34 @@ namespace Apache.Ignite.Core.Impl.Portable
                 else
                     _stream.WriteInt(pos + 14, len);
 
-                // 13. Collect metadata.
-                if (_curMetaHnd != null)
+                // 13. Apply structure updates if any.
+                if (_curUpdates != null)
                 {
-                    IDictionary<string, int> meta = _curMetaHnd.OnObjectWriteFinished();
+                    desc.UpdateStrcuture(_curTypeStruct, _curPathIdx, _curUpdates);
+
+                    IPortableMetadataHandler metaHnd = _marsh.MetadataHandler(desc);
+
+                    if (metaHnd != null)
+                    {
+                        foreach (var u in _curUpdates)
+                            metaHnd.OnFieldWrite(u.FieldId, u.FieldName, u.FieldType);
+
+                        IDictionary<string, int> meta = metaHnd.OnObjectWriteFinished();
 
-                    if (meta != null)
-                        SaveMetadata(_curTypeId, desc.TypeName, desc.AffinityKeyFieldName, meta);
+                        if (meta != null)
+                            SaveMetadata(_curTypeId, desc.TypeName, desc.AffinityKeyFieldName, meta);
+                    }
                 }
 
-                // 14. Apply structure updates 
-                if (_curUpdates != null)
-                    desc.UpdateStrcuture(_curTypeStruct, _curPathIdx, _curUpdates);
-                
                 // Restore old frame.
                 _curTypeId = oldTypeId;
                 _curConverter = oldConverter;
                 _curMapper = oldMapper;
-                _curMetaHnd = oldMetaHnd;
                 _curRawPos = oldRawPos;
 
                 _curTypeStruct = oldTypeStruct;
                 _curPathIdx = oldPathIdx;
                 _curActionIdx = oldActionIdx;
-                _curNewStruct = oldNewStruct;
                 _curUpdates = oldUpdates;
             }
             else
@@ -1628,36 +1624,33 @@ namespace Apache.Ignite.Core.Impl.Portable
 
             int fieldId;
 
-            if (!_curNewStruct)
+            if (_curUpdates == null)
             {
                 fieldId = _curTypeStruct.GetFieldId(fieldName, fieldTypeId, ref _curPathIdx, actionIdx);
 
                 if (fieldId == 0)
-                {
-                    _curNewStruct = true;
-
-                    fieldId = PU.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
-
-                    if (_curUpdates == null)
-                        _curUpdates = new List<PortableTypeStructureUpdate>();
-
-                    _curUpdates.Add(new PortableTypeStructureUpdate(fieldName, fieldId, fieldTypeId, actionIdx));
-                }
+                    fieldId = GetNewFieldId(fieldName, fieldTypeId, actionIdx);
             }
             else
-            {
-                fieldId = PU.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+                fieldId = GetNewFieldId(fieldName, fieldTypeId, actionIdx);
 
-                if (_curUpdates == null)
-                    _curUpdates = new List<PortableTypeStructureUpdate>();
+            _stream.WriteInt(fieldId);
+        }
 
-                _curUpdates.Add(new PortableTypeStructureUpdate(fieldName, fieldId, fieldTypeId, actionIdx));
-            }
+        /// <summary>
+        /// Get ID for the new field and save structure update.
+        /// </summary>
+        /// <returns>Field ID.</returns>
+        private int GetNewFieldId(string fieldName, byte fieldTypeId, int actionIdx)
+        {
+            int fieldId = PU.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
 
-            _stream.WriteInt(fieldId);
-            
-            if (_curMetaHnd != null)
-                _curMetaHnd.OnFieldWrite(fieldId, fieldName, fieldTypeId);
+            if (_curUpdates == null)
+                _curUpdates = new List<PortableTypeStructureUpdate>();
+
+            _curUpdates.Add(new PortableTypeStructureUpdate(fieldName, fieldId, fieldTypeId, actionIdx));
+
+            return fieldId;
         }
 
         /// <summary>