If you read Fabiola’s recent post on the NI QMH you may have noticed that she referred to our own in house variant of this framework. It is something we’re calling the Delacor Queued Message Handler.
Like many application frameworks that grow organically, there were many challenges encountered along the journey.
When we were creating the Delacor Queued Message Handler (DQMH) we needed a way of keeping track of the clone instances currently running (for reasons that shall become apparent in a later post) and we decided to use a variant lookup table inside an Action Engine (Hereafter referred to as AE because I’m lazy) and then expose a public API (Application Programming Interface) for this AE.
In several subsequent conversations I’ve been asked….”What the heck is a Variant? / What the heck is a Variant Attribute? / What’s that funny purple wire you’re using?”
Frankly, I’m not surprised. For a lot of developers I’ve talked to over the years, Variants are reserved solely for passing data to and from databases using the National Instruments Database Connectivity Toolkit, or when reading / writing cell values in Microsoft Excel.
This is a shame because since 2006 NI R&D have been telling us about the performance benefits of variant attributes in posts such as this nugget by Darren Nattinger.
I’m sure many of you find yourself needing some in-memory storage of data to be used by your application, perhaps a database of calibration values to be used by measurements, a list of allowed users and their passwords, etc. The point is, this is something we often need to do and when we need to find a particular record we end up performing some kind of a look up.
The above code is a familiar sight in customer code that I often see. They end up performing some kind of linear search on a data collection they are passing around their application. In the case where User Information is large, the performance will be accordingly less than optimal.
So, at risk of repeating what Darren and many others have said, I am going to look at how one could implement a look-up-table using Variant Attributes inside an AE. Not only will this better performance but it will also provide a neat API.
So lets get started and take a wander over to the Cluster, Class & Variant palette and into the Variant sub palette;
The primitives we’re really interested in here are Get Variant Attribute and Set Variant Attribute on the bottom row and it’s the “Attribute” part that we’re going to be taking advantage of.
In LabVIEW, a Variant can hold any kind of data, so we’re going to create some named attributes of this Variant data and then take advantage of the high performance algorithm which LabVIEW uses under the hood to return them at a later point in time. If you’re interested in quantifying the actually performance benefits, then there’s some further discussion on this here.
In our previous example we would have populated the User Information array (of clusters) and then performed a search to match the required item. When working with variant attributes we need to handle three areas;
1. Seeding / Populating the attributes
2. Persisting the Variant Data (and therefore it’s attributes)
3. Searching for a particular attribute
To populate the attributes we make a call to the Set Variant Attribute primitive. Continuing our previous example, we will add an attribute for each User as it’s the Username that is the primary search parameter for this example.
For each User in the database we would call Set Variant Attribute and add that User as a named attribute of the Variant. Of course, this means we need to persist the variant somehow. The obvious way is through the use of a Shift register or Feedback Node. I like the Shift register in this case as I feel it leads to more readable code.
So now we’ve got something that looks a little like this;
Now we need to be able to Search for a particular Variant Attribute. We can do this by attribute name and in the case of our example this is the name of the user we are interested in. We make a call to Get Variant Attribute and provide the Username as the attribute name (remember that this is how we set the attribute in the previous code sample).
We can then check the password of the user and if it’s correct we can return the access level. Now if we put this code into an AE then we have a pretty neat component that we can use throughout our application to manage our users. For those of you who want to learn more about Component Oriented Design please check out this book by my good friend Steve Watts. It’s well worth a read.
Typically we would, as a minimum, require the following functionality from such an AE
- Add User
- Return User (By Username)
Let’s create such an AE with those states:
Let’s now Add our AE (and it’s Function -Typedef Enum) to a Virtual Folder in a LabVIEW Project Library and Set its access scope to Private.
Finally, let’s create our Public API. Our AE has three functions (or modes of operation) so let’s create three Public API methods. For those of you who are new to LabVIEW this is a great way of hiding the implementation and protecting the users of your code from any changes you may make to the underlying behaviour. Provided you don’t change the public API, how the code is implemented in the AE itself is somewhat irrelevant to the end user of your library.
Here are our three public methods:
And our User Manager Library:
So we’ve used the Variant Attributes and AE to provide us with a high performance (relative to linear array searching) means of adding and retrieving records from a data store and provided this functionality in a simple to use API.