Jump to content

Old content remains in lvclass files


Recommended Posts

Hi,

 

I've decided to take the temperature on a known issue, that lvclass files retain knowledge of some of their old content after it's deleted.

 

Proof

For some reason I'm not allowed to upload lvclass files, so I'll describe it instead (using LV2014SP1):

 

1) Create a new class and save it on disk as class1.lvclass. No member data nor methods, file size on disk is 8 kB.

 

2) Add one piece of significantly sized (to easier see the issue) member data, I added a 1000x100 array of DBL (with random default data in it). Save the class again, and now class1.lvclass is 4604 kB (why so much, should be around 1000 kB?).

 

3) Delete all member data again and resave the class. File size on disk is now 1171 kB, I'd have expected 8 kB.

 

4) I can't ever get rid of that extra data in the lvclass file, not even when I "save as" to create a similar class.

 

Questions

A) What's the reason behind this issue?

 

B) Is there any way to really delete stuff from a class file, or is the only way to recreate every class from scratch if you want something truly gone?

 

C) Is there a list (perhaps internal to NI) of which problems this issue causes? Here I'm talking about stuff like this and numerous other threads about class data suddenly not being updated or member data or methods not being called correctly with DD.

 

Cheers,

Steen

Link to post

The LVClass remembers its previous states in its Mutation History. If I'm not mistaken, NI designed this to help VIs that use your class to adapt to the newer version.

 

There is currently no way to delete mutation history via the LabVIEW IDE itself. Your options are:

Link to post

(A) Don't know why its an unusual size.

(B) If you delete the entire genealogy section in the xml the size goes back to normal.

© I've never had this cause an issue, but I would imagine its not officially supported. The genealogy is probably unrelated to those issues you posted, but it will cause issues if you try to do unflatten on old data. I don't have a need for this feature, so I delete the data pretty regularly. Makes RT deploys a bit less painful too, or at least it does in my imagination.

Link to post

 

The LVClass remembers its previous states in its Mutation History. If I'm not mistaken, NI designed this to help VIs that use your class to adapt to the newer version.

 

There is currently no way to delete mutation history via the LabVIEW IDE itself. Your options are:

 

 

So a built-in feature. I'd still like some official response on these topics then:

 

- Exactly how does this help VIs adapt to a newer version? In my experience new versions of classes aren't more robust than new versions of clusters. And as far as I know clusters do not log around such huge sections of old state.

 

- Is the default value of each data field really necessary to store? Or could we shed 1.1 meg from the class in my example and just store the name and type of old data members?

 

- Is the history really necessary to drag with us onto new copies of a class? Typically I find I mostly copy a class to avoid doing some similar work again, not because I'm creating a new version of it.

 

/Steen 

(A) Don't know why its an unusual size.

(B) If you delete the entire genealogy section in the xml the size goes back to normal.

© I've never had this cause an issue, but I would imagine its not officially supported. The genealogy is probably unrelated to those issues you posted, but it will cause issues if you try to do unflatten on old data. I don't have a need for this feature, so I delete the data pretty regularly. Makes RT deploys a bit less painful too, or at least it does in my imagination.

 

A) Perhaps worth investigating internally at NI then?

B) Not something the average LV dev will or can do. And I have had devs ask me why their classes keep growing in size.

 

/Steen

Link to post

Every class (as opposed to every object) stores its default value.

 

Even when writing to a class via a static Accessor, overhead in combination with storing whether that object has default data or not leads to writes being slower than similarly designed clusters.

 

This "default data" behaviour also raises its head when flattening to XML as only the OBJECT data is saved, not the DEFAULTOBJECT data.  So every object points to a default instance of it's own class in memory where the default values are stored.  For this reason, mutation history may be more important as the objects themselves saved to disk have no idea of any changes made to the non-saved default values of previous generations if it's not stored within the mutation history.

 

I find it a very unwieldy construct but my opinion on the matter is most likely rather insignificant.

Link to post

Every class (as opposed to every object) stores its default value.

 

Even when writing to a class via a static Accessor, overhead in combination with storing whether that object has default data or not leads to writes being slower than similarly designed clusters.

 

Yeah I know that this is the main reason behind the slow object writes we experience when comparing with clusters. Reads are fast, writes not so much. But all is relative.

 

This "default data" behaviour also raises its head when flattening to XML as only the OBJECT data is saved, not the DEFAULTOBJECT data.  So every object points to a default instance of it's own class in memory where the default values are stored.  For this reason, mutation history may be more important as the objects themselves saved to disk have no idea of any changes made to the non-saved default values of previous generations if it's not stored within the mutation history.

 

Ok, I now understand the reason behind choice of mutation history. I'm not sure I like that very much. For one it is still not guaranteed not to fail (the mutation history is only intact as long as I don't delete it), and it forces a lot of comparison and will result in slower than otherwise necessary load times. And it is inconsistent with every other object type in LabVIEW. Not that we shouldn't change just because something else is already implemented...

 

I wonder what tipped the scales toward this design decision? Perhaps that classes were seen as containing large default data constructs primarily? It smells a bit like that shared variables are optimized for single point updates and suck for streaming (not comparing classes and SVs at all btw). I'd rather have the possibility to specify data with a 'static' keyword for instance, and only in those cases get this behavior. If I could do that I could decide when to trade in memory usage for performance and hard linking.

 

/Steen

Link to post

In the seven or so years I have been dabbling with LVOOP not once have I said, "gee I am so glad that a class maintains its mutation history". Maybe it's just the kind of applications I develop, dunno. I never serialise my classes directly to disk.

 

Also have seen some terrible editor bugs that can be traced down to stale mutation history in a class.

Link to post

In the seven or so years I have been dabbling with LVOOP not once have I said, "gee I am so glad that a class maintains its mutation history". Maybe it's just the kind of applications I develop, dunno. I never serialise my classes directly to disk.

 

I've dabbled for about 1 year, and I haven't needed wanted mutation history either. I have a VI that recurses through my project folders, stripping out all mutation history before I commit my files into source control.

 

 

The current serialization system needs a major overhaul; AristosQueue has a side project to improve it: https://decibel.ni.com/content/docs/DOC-24015

Link to post

If I understand this correctly, one way to get rid of the mutation history is to not change the class.ctl.

If that's the case you could, for example, store a reference to your actual class data in this control, which you can then change as often as you wish without LabVIEW knowing about it. And that takes us, once again, to GDS :)

The problem with this approach is of course that flatten to string on an object doesn't work any more and you'd have to write your own flatten method, which flattens the data the reference points to instead of flattening the pointer value. Hmmm

Link to post
  • 1 year later...

Bump to this thread. I really do not like mutation history being stored.

I have a stupid LabVIEW bug where the IDE thinks I am using a class which I am not (really am not). I thought perhaps it was being referenced from the class mutation history. So I poked around in the history of some of my classes and am horrified at the history that exists! I don't know about others, but my standard framework has been adapted over time (several years for my current actor based framework). I still have references in the mutation history for application specific classes from my original project! Urgh... 

I suppose I have no excuse, I have known about this "feature" for a while, but it is easy to forget about.

Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Similar Content

    • By cyro2015
      Hi,
      I tried to create a template based on OOP for QMH. During development I have been confronted with infinite crashes of LabVIEW so I decided to slow down with this project and open it to the community. I finished my working example and stopped for now.
      So if anyone is interested to play around with the code, see attached ZIP file (LV 2020).
      Cu,
      Peter
       
      MHT.zip
    • By Marko Hakkarainen
      I had some time to learn about new interfaces and finally I could implement my collection class as I had envisioned. I didn’t want to use iterable and iterator names, because I thought that would have been too bold a claim.
      The original version of the collection class was (and is) used as a collection of sequence steps. Each element can be either a sequence command (send message, wait timer, wait complete etc.) or another collection of commands (sub-sequence). That’s the reasons for the labels and search method. Otherwise it is just a fancy (Rube Goldberg) array.
      Next method is recursive and it steps through all elements in the collection. Execute is only method, which requires override.
      For now, it’s at least an exercise in new interfaces. I don’t know if it’s useful enough to be in the code repository, but I can polish it up if needed.
       
      --
      Marko H
      Certified LabVIEW Architect
      www.optofidelity.com
      Iterable Collection LV2020.zip
    • By Ram Prakash
      Can anyone please tell what a DVR [ Data value reference ] is ? I want to know at what situation it will be used and what are the advantages we get by using DVR. I am really confused in this topic . If someone has any code in which they have worked with DVRs. kindly share it to me.
       
      Thank you.
    • By Ryan Vallieu
      I have seemingly found an issue with the shipping example code for Nested Malleable VIs.  Another user has verified that he saw the same behavior in 2019.
       
      I am working through the examples and the presentation from NIWeek 2019.  In running the Lesson 2b code (C:\Program Files (x86)\National Instruments\LabVIEW 2019\examples\Malleable VIs\Nested Malleable VIs) I found the Equals.vi in the class was not being leveraged and the search failed.  When I went to my LabVIEW 2018 machine and ran the Lesson 2b.vi the code worked to find the element by correctly leveraging the in-class Equals.vi.
      One difference I see is that in the 2018 example the Equal.vi is in the example folder with the code, and in 2019 the Equal.vi has been moved to VI.lib - otherwise the code looks to be the same.  The Equals.vi code looks identical, and the calling VIM look identical.  I posted on the LabVIEW NI.com forum here: 
      https://forums.ni.com/t5/LabVIEW/LabVIEW-2019-Malleable-VIs-Shipping-Examples-Lesson-2b-Nested/m-p/3966044/highlight/false#M1129678
       
      I am trying to determine what may have broken or changed between the implementation in 2018 and 2019, visually the code looks the same.
    • By Zyl
      Hi everybody,
       
      I'm running into something I don't really understand. Maybe you can help me here !
      I've got a LVLIB that is used as an 'Interface': it exposes public VIs which wrap around public functions of a private class (see code attached) . The class is private because I want to force the users to use the 'interface' functions.
      In one of my interface VI, I create a DVR on the private class (Interface_init). The DVR is stored into a typedef (FClass_DVR.ctl) and this typedef is the 'reference' that link all the interface public functions.
      In TestCode.vi (which is not part of the lvlib and illustrates the standard code that a user can create to use my driver), I can call my public interface functions and link them without any problem.

      But as soon as I create an indicator on that reference (to create a state-machine-context-cluster for example), my TestCode VI breaks !

      The error returned is : This VI cannot use the LabVIEW class control because of library access scope. The LabVIEW class is a private library item and can only be accessed from inside the same library or libraries contained in that library.
      I understand that the class is private. But the DVR is contained into a public control. Using an In Place structure on that DVR into TestCode would not work, since the class is private. So why is the DVR control problematic at that point ? Creating it do not breaks any access protection...
      Am I missing something ?
      DVR Private POC.zip
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.