IGNITE-6627 .NET: Fix repeated known metadata updates
authorPavel Tupitsyn <ptupitsyn@apache.org>
Thu, 19 Oct 2017 09:36:39 +0000 (12:36 +0300)
committerPavel Tupitsyn <ptupitsyn@apache.org>
Thu, 19 Oct 2017 09:36:39 +0000 (12:36 +0300)
This closes #2876

modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/BasicSerializableObjectsTest.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructure.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs

index e9b5576..846cd4c 100644 (file)
@@ -44,12 +44,13 @@ namespace Apache.Ignite.Core.Tests.Binary.Serializable
         public void TestEmptyObjectOnline()
         {
             using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            using (var ignite2 = Ignition.Start(TestUtils.GetTestConfiguration(name: "1")))
             {
                 var cache = ignite.CreateCache<int, EmptyObject>("c");
 
                 cache[1] = new EmptyObject();
 
-                var res = cache[1];
+                var res = ignite2.GetCache<int, EmptyObject>("c")[1];
 
                 Assert.IsNotNull(res);
             }
index e38b5ba..50c8c27 100644 (file)
@@ -55,7 +55,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         private readonly string _affKeyFieldName;
 
         /** Type structure. */
-        private volatile BinaryStructure _writerTypeStruct = BinaryStructure.CreateEmpty();
+        private volatile BinaryStructure _writerTypeStruct;
 
         /** Type structure. */
         private volatile BinaryStructure _readerTypeStructure = BinaryStructure.CreateEmpty();
@@ -230,22 +230,27 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /** <inheritDoc /> */
-        public void UpdateWriteStructure(BinaryStructure exp, int pathIdx, 
-            IList<BinaryStructureUpdate> updates)
+        public void UpdateWriteStructure(int pathIdx, IList<BinaryStructureUpdate> updates)
         {
             lock (this)
             {
-                _writerTypeStruct = _writerTypeStruct.Merge(exp, pathIdx, updates);
+                if (_writerTypeStruct == null)
+                {
+                    // Null struct serves as an indication of a binary type that has never been sent to the cluster,
+                    // which is important for types without any fields.
+                    _writerTypeStruct = BinaryStructure.CreateEmpty();
+                }
+
+                _writerTypeStruct = _writerTypeStruct.Merge(pathIdx, updates);
             }
         }
 
         /** <inheritDoc /> */
-        public void UpdateReadStructure(BinaryStructure exp, int pathIdx, 
-            IList<BinaryStructureUpdate> updates)
+        public void UpdateReadStructure(int pathIdx, IList<BinaryStructureUpdate> updates)
         {
             lock (this)
             {
-                _readerTypeStructure = _readerTypeStructure.Merge(exp, pathIdx, updates);
+                _readerTypeStructure = _readerTypeStructure.Merge(pathIdx, updates);
             }
         }
 
index 737c7c4..6fece77 100644 (file)
@@ -134,20 +134,20 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /** <inheritDoc /> */
-        public void UpdateWriteStructure(BinaryStructure exp, int pathIdx, IList<BinaryStructureUpdate> updates)
+        public void UpdateWriteStructure(int pathIdx, IList<BinaryStructureUpdate> updates)
         {
             lock (this)
             {
-                _writerTypeStruct = _writerTypeStruct.Merge(exp, pathIdx, updates);
+                _writerTypeStruct = _writerTypeStruct.Merge(pathIdx, updates);
             }
         }
 
         /** <inheritDoc /> */
-        public void UpdateReadStructure(BinaryStructure exp, int pathIdx, IList<BinaryStructureUpdate> updates)
+        public void UpdateReadStructure(int pathIdx, IList<BinaryStructureUpdate> updates)
         {
             lock (this)
             {
-                _readerTypeStructure = _readerTypeStructure.Merge(exp, pathIdx, updates);
+                _readerTypeStructure = _readerTypeStructure.Merge(pathIdx, updates);
             }
         }
 
index 4bd7e73..840fc08 100644 (file)
@@ -90,18 +90,16 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Update write type structure.
         /// </summary>
-        /// <param name="exp">Expected type structure.</param>
         /// <param name="pathIdx">Path index.</param>
         /// <param name="updates">Recorded updates.</param>
-        void UpdateWriteStructure(BinaryStructure exp, int pathIdx, IList<BinaryStructureUpdate> updates);
+        void UpdateWriteStructure(int pathIdx, IList<BinaryStructureUpdate> updates);
 
         /// <summary>
         /// Update read type structure.
         /// </summary>
-        /// <param name="exp">Expected type structure.</param>
         /// <param name="pathIdx">Path index.</param>
         /// <param name="updates">Recorded updates.</param>
-        void UpdateReadStructure(BinaryStructure exp, int pathIdx, IList<BinaryStructureUpdate> updates);
+        void UpdateReadStructure(int pathIdx, IList<BinaryStructureUpdate> updates);
 
         /// <summary>
         /// Gets the schema.
index 92c841c..908059a 100644 (file)
@@ -118,14 +118,12 @@ namespace Apache.Ignite.Core.Impl.Binary.Structure
         /// <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 BinaryStructure Merge(BinaryStructure exp, int pathIdx, 
-            IList<BinaryStructureUpdate> updates)
+        public BinaryStructure Merge(int pathIdx, IList<BinaryStructureUpdate> updates)
         {
-            if (updates.Count == 0)
+            if (updates == null || updates.Count == 0)
                 return this;
 
             // Algorithm ensures that updates are applied to the same type structure,
@@ -137,102 +135,97 @@ namespace Apache.Ignite.Core.Impl.Binary.Structure
 
             // Note that field types are merged anyway to avoid metadata clashes.
             BinaryStructure res = MergeFieldTypes(updates);
+            BinaryStructureUpdate firstUpdate = updates[0];
 
-            if (ReferenceEquals(exp, this))
+            if (firstUpdate.Index == 0)
             {
-                BinaryStructureUpdate firstUpdate = updates[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);
 
-                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);
-
-                    var newPaths = CopyPaths(updates.Count, 0);
+                var newPaths = CopyPaths(updates.Count, 0);
 
-                    ApplyUpdatesToPath(newPaths[0], updates);
-
-                    res = new BinaryStructure(newPaths, _jumps, res._fieldTypes);
-                }
-                else
-                {
-                    // Get entry where updates should start.
-                    BinaryStructureEntry[] path = _paths[pathIdx];
+                ApplyUpdatesToPath(newPaths[0], updates);
 
-                    BinaryStructureEntry startEntry = default(BinaryStructureEntry);
-
-                    if (firstUpdate.Index < path.Length)
-                        startEntry = path[firstUpdate.Index];
+                res = new BinaryStructure(newPaths, _jumps, res._fieldTypes);
+            }
+            else
+            {
+                // Get entry where updates should start.
+                BinaryStructureEntry[] path = _paths[pathIdx];
 
-                    if (startEntry.IsEmpty)
-                    {
-                        // We are on the empty/non-existent entry. Continue the path without branching.
-                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 0);
+                BinaryStructureEntry startEntry = default(BinaryStructureEntry);
 
-                        ApplyUpdatesToPath(newPaths[pathIdx], updates);
+                if (firstUpdate.Index < path.Length)
+                    startEntry = path[firstUpdate.Index];
 
-                        res = new BinaryStructure(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. Prepare new structures.
-                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 1);
-                        var newJumps = CopyJumps(0);
+                if (startEntry.IsEmpty)
+                {
+                    // We are on the empty/non-existent entry. Continue the path without branching.
+                    var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 0);
 
-                        // New path will be the last one.
-                        int newPathIdx = newPaths.Length - 1;
+                    ApplyUpdatesToPath(newPaths[pathIdx], updates);
 
-                        // Apply updates to the new path.
-                        ApplyUpdatesToPath(newPaths[newPathIdx], updates);
+                    res = new BinaryStructure(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.
 
-                        // Add the jump to the table.
-                        newJumps[startEntry.Id] = 
-                            newJumps[startEntry.Id].CopyAndAdd(firstUpdate.FieldName, newPathIdx);
+                    // 1. Prepare new structures.
+                    var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 1);
+                    var newJumps = CopyJumps(0);
 
-                        res = new BinaryStructure(newPaths, newJumps, res._fieldTypes);
-                    }
-                    else
-                    {
-                        // We are on existing entry. Need to create a new jump table here and two new paths.
+                    // New path will be the last one.
+                    int newPathIdx = newPaths.Length - 1;
 
-                        // 1. Prepaare new structures.
-                        var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 2);
-                        var newJumps = CopyJumps(1);
+                    // Apply updates to the new path.
+                    ApplyUpdatesToPath(newPaths[newPathIdx], updates);
 
-                        // Old path will be moved here.
-                        int oldPathIdx = newPaths.Length - 2;
+                    // Add the jump to the table.
+                    newJumps[startEntry.Id] =
+                        newJumps[startEntry.Id].CopyAndAdd(firstUpdate.FieldName, newPathIdx);
 
-                        // New path will reside here.
-                        int newPathIdx = newPaths.Length - 1;
+                    res = new BinaryStructure(newPaths, newJumps, res._fieldTypes);
+                }
+                else
+                {
+                    // We are on existing entry. Need to create a new jump table here and two new paths.
 
-                        // Create new jump table.
-                        int newJumpIdx = newJumps.Length - 1;
+                    // 1. Prepaare new structures.
+                    var newPaths = CopyPaths(firstUpdate.Index + updates.Count, 2);
+                    var newJumps = CopyJumps(1);
 
-                        newJumps[newJumpIdx] = new BinaryStructureJumpTable(startEntry.Name, oldPathIdx,
-                            firstUpdate.FieldName, newPathIdx);
+                    // Old path will be moved here.
+                    int oldPathIdx = newPaths.Length - 2;
 
-                        // 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];
+                    // New path will reside here.
+                    int newPathIdx = newPaths.Length - 1;
 
-                            if (i == firstUpdate.Index)
-                                // Inject jump table ...
-                                newPaths[pathIdx][i] = new BinaryStructureEntry(newJumpIdx);
-                            else
-                                // ... or just reset.
-                                newPaths[pathIdx][i] = new BinaryStructureEntry();
-                        }
+                    // Create new jump table.
+                    int newJumpIdx = newJumps.Length - 1;
 
-                        // Apply updates to the new path.
-                        ApplyUpdatesToPath(newPaths[newPaths.Length - 1], updates);
+                    newJumps[newJumpIdx] = new BinaryStructureJumpTable(startEntry.Name, oldPathIdx,
+                        firstUpdate.FieldName, newPathIdx);
 
-                        res = new BinaryStructure(newPaths, newJumps, res._fieldTypes);
+                    // 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];
+
+                        if (i == firstUpdate.Index)
+                            // Inject jump table ...
+                            newPaths[pathIdx][i] = new BinaryStructureEntry(newJumpIdx);
+                        else
+                            // ... or just reset.
+                            newPaths[pathIdx][i] = new BinaryStructureEntry();
                     }
 
+                    // Apply updates to the new path.
+                    ApplyUpdatesToPath(newPaths[newPaths.Length - 1], updates);
+
+                    res = new BinaryStructure(newPaths, newJumps, res._fieldTypes);
                 }
             }
 
index 3517342..ee2e7e1 100644 (file)
@@ -68,7 +68,7 @@ namespace Apache.Ignite.Core.Impl.Binary.Structure
         {
             _curStructAction++;
 
-            if (_curStructUpdates == null)
+            if (_curStructUpdates == null && _portStruct != null)
             {
                 var fieldId = _portStruct.GetFieldId(fieldName, fieldTypeId, ref _curStructPath,
                     _curStructAction);
@@ -86,7 +86,7 @@ namespace Apache.Ignite.Core.Impl.Binary.Structure
         public void UpdateReaderStructure()
         {
             if (_curStructUpdates != null)
-                _desc.UpdateReadStructure(_desc.ReaderTypeStructure, _curStructPath, _curStructUpdates);
+                _desc.UpdateReadStructure(_curStructPath, _curStructUpdates);
         }
 
         /// <summary>
@@ -97,7 +97,7 @@ namespace Apache.Ignite.Core.Impl.Binary.Structure
         {
             if (_curStructUpdates != null)
             {
-                _desc.UpdateWriteStructure(_desc.WriterTypeStructure, _curStructPath, _curStructUpdates);
+                _desc.UpdateWriteStructure(_curStructPath, _curStructUpdates);
 
                 var marsh = writer.Marshaller;
 
@@ -115,15 +115,13 @@ namespace Apache.Ignite.Core.Impl.Binary.Structure
                     writer.SaveMetadata(_desc, fields);
                 }
             }
-            else
+            else if (_desc.WriterTypeStructure == null)
             {
-                // Special case when the object is with no properties.
-                // Save meta to Marshaller.
+                // Empty object (no fields).
+                // Null WriterTypeStructure indicates that meta has never been sent for this type.
                 writer.Marshaller.GetBinaryTypeHandler(_desc);
-
-                // Save meta to cluster.
                 writer.SaveMetadata(_desc, null);
-                return;
+                _desc.UpdateWriteStructure(_curStructPath, null);
             }
         }