ThinkGeo.com    |     Documentation    |     Premium Support

duplicateReference Hashcode in Serializers

Hi,


Previously, I logged a post in where I found in a serialized data file a hash code for a duplicateReference that had been reused for elements in which it didn't apply.  This post is called "Deserializing Error for Layer Overlay".  We did not find a solution with our test project, but chocked it up to version of MapSuite.


Since then, I have continued to get similar errors, but not always for the same elements.  I've seen instances where Fonts are being cross-referenced to featureSources, featureSources for featureSourceColumns and other similar unmatched types.


Essentially, the only thing that I can conclude is that there is an error somewhere in the code where the serializer writes data and decides to replace an element with a duplicateReference flag in order to save disk space with the output file.


Since this error seems to be a shot in the dark to find, can you please provide me with a solution in which the serializer will simply write the XML stream as is with no duplicateReference replacement flags?  I do not currently see any options when calling the .Serialize method.


I am using version 6.0.0.75 in case this issue has been addressed since then.


Thanks,


Damian



Hi Damian, 
  
 I read the post “Deserializing Error for Layer Overlay” and it seems that you just provided the serialized xml file which already contains the error hashcode and we didn’t get the original one. could you please send a full sample to us to have a test? The requirements for the sample are: 
 1), Runnable. 
 2), Contains the original data, not the xml files,  e.g. all the overlays you mentioned in that post. 
  
 Only in this way, we can work with the exactly same scenario as yours and recreate the issue. 
  
 Thanks in advance, 
  
 Edgar

Edgar, 
  
 Sorry for the delayed reply. I forgot to add myself to the topic notification.  Wish this was a default when submitting a post. 
  
 I’ve resent the data to support email as it’s too big to attach, but I do not want to go down this rabbit hole again.  I have some people getting rather upset when their files refuse to load because they are being serialized incorrectly. 
  
 There is no test project that replicates the issue, only my active distribution software which I will not be sending you.  However, since there is nothing that I can do to interrupt the Serialize method, I really don’t see why there is a need for this.  You really need to be checking into your code as to how duplicate references are assigned. 
  
 My question is clear.  Can I get a solution where I can force the serializer to stop substituting duplicate references when writing data? 
  
 After I get to a point where I have files written out correctly and no more users screaming at me, I will be happy to spend more time investigating the duplicate references and will help as much as possible to provide you data and test projects to replicate the issue in your environment. 
  
 Regards, 
 Damian

Hi Damian,


I got your data and did the following test with 6.0.0.75,


1), Change the hashCode at line 320860 and 320876 from 22170731 to 22170732.



2), Run your sample and deserialize the modified file to an object, it works fine.


3), Serialize the object to a new file.


4), Rerun the sample and choose the new file to deserialize and display, it works fine.


 


It runs without any exception, so I think our serializer has no problem, but the wrong hashCode in your data must be caused by some run time error etc., is it possible for you to modify the wrong hasCode to a unique one e.g. 22170732?


Hope it helps,


Edgar



Edgar, 
  
 Reassigning the hash code for the duplicate reference to a made up number which is not assigned elsewhere obviously removes the exception, but it doesn’t fix the problem for 2 reasons. 
  
 1.  I can’t detect if a hash code has been assigned incorrectly until the Serializer yields an exception.  Not helpful as it just indicates a problem to the user which they don’t know how to fix.  Further, it would be programmatically irritating to have to write some code to read the file and pair duplicates to their hash codes to test their type compatibility and then to further replace them with made up numbers. 
  
 2.  In this case, the duplicate reference is not replacing a lot of XML parameters since we’re talking about a column type that only has a name property.  In some cases, the hash code is substituted for a completely different type which many parameters are required.  For instance, I have seen a duplicate hash code used for a zoomLevelSet.  When these parameters are not all defined, replacing the hash code with a made up number only means the object will not display properly. 
  
 None of my code does anything or writes out anything to the Serialized file (or assigns hash codes), so how can this be something I’m doing in code?  There are no runtime errors during the serialization of the files. If there were, then how could the serializer complete the closing XML statement? 
  
 So, back to my question.  Can I have a solution where the Serializer does not assign duplicate hash codes?  I would also kindly request that you look at how hash codes are reused when serializing to see if there aren’t any obvious problems.  We’re looking for a limit error here as it doesn’t manifest until the files contain 1000’s of objects.  Maybe, if you are writing data in chunks, some variable is getting reinitialized for each chunk instead of applying for the whole process. 
  
 In the meantime, I will document the errors that I see and provide this to help better define the problem. 
  
 I really do need a solution for this issue. 
  
 Damian

Edgar,


I've found another example for you, this time with Zoom Level Sets.


Attached is a new GeoSerializerTester program as I've since updated my code to work in UTM's and display in Spherical Mercator.  Also attached is a zip file with two text files that can be loaded into the GeoSerializerTester program.


When you load the first file, ZoomLevelHashCode.txt, you will see two points, but if you look at the file, there is actually a line and 2 points which should be displayed.


If you load the second file, ZoomLevelHashCodeFix.txt, you will see the 1 line, but only 1 of the 2 points.


The problem is because Hash Code 64792811 is assigned at zoomLevel03 of the line object, but for some reason, that zoomLevel has been incorrectly written out as a defaultPointStyle even though the object is a line.  The Hash Code is later used to reference zoomLevel01 of one of the point type objects.  Hence, that point displays when viewing the first file.


In the second file, I remove the erroneous reference to the defaultPointStyle in the line's zoom level set and hence the line displays correctly, but now not the point.  The only way to fix this and display all 3 objects would be to copy the defaultPointStyle code down to the point object and remove the hash codes.


So, the question is how did a point style get assigned within a line styles zoom level set?  The answer can not be anywhere but in the process where duplicateReference is assigned. 


In this case, we're just lucky that this didn't throw an exception in the serializer since an object can always have default zoom level sets for points, lines and area types regardless of their well known type. 


Further, this is only 1 case of about 20 similar cases all within the same originating file.  Basically, I boiled the attached files down to a mimumum to clarify the problem.


I hope this is some help to prove that something quite bad is happening when duplicateReferences are being assigned in the Serializer.


-Damian



ZoomLevelHashCodeExamples.zip (6.86 KB)
GeoSerializerTester.zip (50.6 KB)

Damian,


Sorry for confusing you, I didn't mean you did something in your code, but the hash code is unstable sometimes. I serached the MSDN and knew that .NET Frameworkd does not guarantee the hash code is unique, orz., we used to test it with the WorldMapkit which has thousands of layers and it works fine. Nevertheless we'll look for a solution to solve this. BTW, can you recreate the issue with the zoomlevel every time? If so, is it possible for you to provide the sample for us to have a test? We will appreciate that if you do so.


As the hash code is not unique, but it will still available for the following two scenarios:


1), Handling the repeat reference: FeatureLayer has a field "editTools"which type is EditTool, and a field "featureSource" which type is FeatureSource. and the EditTools has a field "featureSource" which is the same as FeatureLayer.FeatureSource, when serializing FeatureLayer, the FeatureSource will be serialized 3 times cause the FeatureLayer.FeatureSource, QueryTools.FeatureSource, EditTools.FeatureSource, so we are using the hash code to infer that the FeatureSource has already been serialized and tell the program not to serialize it again, this is used for making the result file's size smaller.


2), Handling the circular reference: assume there are two classes, class A { publc B b; }, class B { public A a; }, if we don't use the hash code two specify the serialized objects, this serialization will be endless, but by the hash code we can clearly know what object has been serialized, for this case 


A a = new A();


a.b = new B();


a.b.a = a;


the xml will be 



<A type="A" hashCode="25560520" circularReference="parentNode" duplicateReference="true">

  <b>

    <a type="A" circularReference="childNode" hashCode="25560520" duplicateReference="true" />

  </b>

</A>


 


Once we fixed this issue, we'll let you know.


Sorry for the inconvenience,


Edgar



Hi Edgar, 
  
 Thanks for looking into this.  I really appreciate it. 
  
 I will attempt to modify the test project to output the zoomLevel results consistently.  I’ll send that early next week if I am successful.  I have the feeling that it will produce them, but it won’t be the same effected element(s) each time. 
  
 Regards, 
 Damian

Hello Damian, 
  
 Ok, feel free to let us know your further information. 
  
 Regards, 
  
 Gary

Gary/Edgar,


I have a test project that recreates the issue fairly regularly.  I am sending it to support@thinkgeo.com with subject of this topic.


The project has 2 shape file overlays and a point type overlay and a line type overlay.  It also has two list boxes to display data about the lines and points.  The serializer stores all these data and reads it back accordingly.


There are 4 buttons.


1.  Save


2.  Load


3.  Add Lines


4.  Add Points


If you use Load right now, it will pick-up the current SaveFile.txt in the Debug folder and you will see the most recent hash code error.


Now to replicate the issue for yourself, start anew by restarting the program.  When it finishes loading, you can use Add Lines/Points and just start creating obects on the screen.  I use the track overlay and then to speed things up write out 400 new feature layers starting with the base feature all separated by 500m in the x direction.  When you get to around 4000 lines and points, click the save button.  This will write out to a SaveFile.txt in the Debug directory and then clear the current overlays.  An example of what this should look like is in the attached image.


Now, click Load.  If there was a hash code problem, you will see an error message.


For me, I started getting errors regularly with around 3600 elements.  I do not know if this is CPU related, but I'm using x86 in Debug mode.  You may have to add more (or fewer) objects to see errors appear.


One thing that was clear when building this project was that you don't have a high likelihood of getting Exception errors using the Deserialize method just by serializing overlays.  It's when I added in the two list boxes and started capturing more data of different types in the serialized file that the frequency increased.  Consecuently, the bigger the file the more likeliness of an error.  In my program, I have a similar structure, but with more overlays and more tables, so I get even more errors.  Two were reported this morning alone from users and I had to "fix" their files by assigning the offending hash codes to unique values.


If you look in the Debug folder you will see two other SaveFiles which are other examples of serialized files with hash code errors using the same test program.  All these files generated in the last hour, so it shouldn't be hard for you to validate on your side.


Please help me to find a solution as fast as possible.


Regards,


Damian


 



Damian, 
  
 We changed the hashcode to Guid to specify the different object, now I think your problem would be solved, please reserialize the objects using 6.0.148.0 or 6.0.0.148 dlls. 
  
 Hope it helps, 
  
 Edgar

Hi Edgar,


I loaded the new library from production and I got a FormatException error running my sample and trying to save the file.


Here's the stack trace.


"   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)\r\n   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)\r\n   at System.Convert.ToInt32(String value)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.pCs=(Object pSs=, GeoObjectNode pis=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.sys=(IEnumerable tCs=, GeoObjectNode tSs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.sys=(IEnumerable tCs=, GeoObjectNode tSs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.sys=(IEnumerable tCs=, GeoObjectNode tSs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.sys=(IEnumerable tCs=, GeoObjectNode tSs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNodeCore(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateMemberNode(String memberName, Object memberValue, Type memberType, Object memberOwner, GeoObjectNode baseMemberNode)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.vSs=(Object vis=, GeoObjectNode vys=, FieldInfo wCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.tis=(Object tys=, GeoObjectNode uCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.jCs=(Object jSs=, GeoObjectNode jis=, String jys=, Type kCs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.iCs=(Object iSs=)\r\n   at ThinkGeo.MapSuite.Core.GeoObjectModeler.CreateModel(Object objectToModel, GeoObjectModelerMemberTypes memberTypes, BindingFlags bindingFlags, GeoObjectModelerDefaultValueMode defaultValueMode)\r\n   at ThinkGeo.MapSuite.Core.GeoSerializer.Serialize(Object objectToSerialize, Stream targetStream)\r\n   at GeoSerializerTest.SerializationFunctions.WriteSerializedOverlays(FileStream output, Collection`1 overlays, List`1 textValues, Collection`1 pointValues, Collection`1 lineValues) in C:\\Users\\dhite\\Documents\\Visual Studio 2010\\Projects\\GeoSerializerDuplicateHashCodeTester\\GeoSerializerTest\\SerializationFunctions.cs:line 61"


 


-Damian



Oh, the circular reference was missed, now it has been fixed, please get 6.0.149.0 or 6.0.0.149 and have a try. 
  
 Sorry for the inconvenience, 
  
 Edgar

Hi Edgar, 
  
 I’ve got the new version and tried it in my test project on roughly double the number of objects I expect in a normal project file and it’s working fine. 
  
 Sorry, I know you guys probably didn’t want to use GUID, but I really needed it for what we are doing. 
  
 Thanks again, 
 Damian

Damian, 
  
 Glad to hear that your project in working with the new version, and you’re right, the GUID is not the best solution cause the performance would be bad which is caused by generating the GUID if the objects count is very big, we’ll consider finding a better way to do it in the future. 
  
 Regards, 
  
 Edgar