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 <voze...@gridgain.com> Authored: Wed Oct 7 11:44:24 2015 +0300 Committer: vozerov-gridgain <voze...@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; } + } + } +}