Sam Pride

Writing to Secondary Members using the PI-SDK

Blog Post created by Sam Pride on Apr 16, 2009

Manual entry data is an important aspect of many customer's PI servers, as is the need for Highly-Available and reliable systems. Unfortunately, using the PI-SDK to store manual entry data is not that straight-forward in a PI-HA environment. 

In the current release of the PI-SDK and the PI-Server, there is no out-of-the-box mechanism in place to replicate SDK writes to all members of the collective. Whilst there are features planned for future releases that will overcome these issues, we need to be able to ensure our manual entry data mechanisms work well with the existing PI version. The good news is, implementing a robust solution for Manual Entry Data (or any PI-SDK writes) in a HA environment is not overly complicated.  This blog post will hopefully outline the considerations and technical details for achieving this (and hopefully not confuse you too much!)

As mentioned previously, the PI-SDK will only write to one collective member at a time. This is further complicated by the fact that, when connecting to a named server, the SDK actually connects to the collective itself and there is no guarantee you will actually connect (or stay connected) to your desired server. To overcome this limitation, the PI-SDK provides a new Interface, IPICollective, which allows us to gather information on the Collective and target an individual server.

The IPICollective interface is a secondary interface supported by the PISDK.Server object that provides extra functionality for dealing with PI Collectives. The IPICollective allows us to access the Collective-specific information (such as the Collective Name, the members in the Collective etc) and also provides some handy methods for establishing and managing connections to various members of the collective.  We will investigate the interesting/important members of IPICollective through a quick example.


The following snippet of code contains a function called OpenMember. This function will try to connect to a collective member if the server name is a member of a collective, else it will connect directly to the PI Server. As this method returns a connected (hopefully) PISDK.Server object, you can use it in place of your regular Server.Open() calls.




.csharpcode, .csharpcode pre {      font-size: small;      color: black;      font-family: Consolas, "Courier New", Courier, Monospace;      background-color: #ffffff;      /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt {      background-color: #f4f4f4;      width: 100%;      margin: 0em; } .csharpcode .lnum { color: #606060; }

ProtectedFunction OpenMember(ByVal _serverName AsString, ByVal _connectionString AsString) As PISDK.Server

        Dim srv As Server
        Dim sdk As PISDK.PISDK
        Dim col As IPICollective
        Dim colList As CollectiveList
        Dim colMember As CollectiveMember

        'Get a handle on the SDK
        sdk = New PISDK.PISDK()

        'set the server to point to our desired server
        srv = sdk.Servers(_serverName)

        'Check to see if it is a collective
        col = srv
        If col.IsCollectiveMember() Then'If so, locate the correct Collective Member
            colList = col.ListMembers()
            colMember = colList(_serverName)

            'Open the member (not the collective)
            srv = col.MemberOpen(colMember, _connectionString)
        Else'It is a normal server, open it as you normally would.
        EndIfReturn srv

    End Function

The IsCollectiveMember property of IPICollective will return true if the underlying server object is a collective member (or a collective in its own rights). You should always check this property before trying to use the Collective-specific functionality of the IPICollective interface, as any unsupported request (such as determining the Collective name) will throw an error.

Once we have determined that the PI Server is a member of a collective, all we need to do is pass the appropriate CollectiveMember object (which we obtained through the ListMembers() function) to the MemberOpen() method. This behaves like the standard Server.Open() method you most likely have called in the past, meaning you can still supply a connection string. The PISDK.Server object that was returned can be used exactly as you would before.

You may be tempted to use the IPICollective.SwitchMember() method to connect to another PI Server. Whilst this method will allow you to connect to another a member, you have no real control over which member you connect to. The SwitchMember() method uses the CollectiveMember's priority when failing over the connection; it will attempt to connect to the highest priority server other than itself. Calling this method multiple times would result in the connection failing between the Primary and the first secondary, starving any additional secondaries. The only workaround to this is to programmatically update the priority for each member of the collective before switching, which is not ideal.

The final thing you will need to do before you can use this connection to send data to your Collective members is to ensure that the Replication_EnableSDKWriteValues PI Tuning parameter is set to 1. This is disabled by default (it doesn't even appear in the list) and will cause any PI-SDK writes to fail. The parameter does not appear in the SMT Tuning Parameters plug-in by default; you will need to right-click on an existing entry and chose "new".

There are, however, some drawbacks to connecting and disconnecting to the various members using MemberOpen. Steve Pilon eloquently outlines some of these drawbacks in his post on the discussion forums: Instead of duplicating Steve's comment I suggest you have a quick read and possibly join in the discussion if you have further questions in this regard. Nevertheless, these drawbacks may be outweighed by the benefits obtained through replication of data and there are also some things you can do to mitigate their effect.
Next Steps

Unfortunately, getting a connection to an individual collective member is only one part of the puzzle. Your application will need to be modified to write to all the SDK members. Furthermore, you will need to account for buffering data to SDK servers that are unavailable. There is a lot to consider when implementing replication of Data, even more so if you wish to pass the ACID test ( There are many options when choosing how to implement a local cache, such as Database, Flat-Files, far too many to list here. I will address these concerns and the various options in another post (blog or discussion forum).


Another viable alternative when implementing manual entry data for a HA environment is to use ACE. ACE uses the API to send data to PI which means data updates pass through the buffer. This will allow you to replicate data to multiple PI Servers, yet retrieve data using the PI-SDK (giving you data-access failover). It's important to remember that only updates using the PIACEPoint are sent using the API; any direct PI-SDK calls still behave as they would in your own custom app.

Unfortunately, using the IPICollective methods discussed earlier will not quite work in PI-ACE. The PI-SDK only allows one open connection per application. When you call IPICollective.MemberOpen(), you will most likely receive an error message "The server is already open under a different connection string", as the one PIACEClassLibraryHost process may be shared by multiple contexts (threads) . You should not attempt to close the existing connection, as this is used by PI-ACE to retrieve Data and configuration information and any premature interruption may cause crashes and unexpected behaviour. The bottom line is, when using PI-ACE to write data to PI, use the inbuilt PIACEPoint functionality.



Final Thoughts

Thanks for sticking through such a long post. I hope it has been useful to somebody! This is not the final word on this subject, there are plenty of slight details I have glossed over (which I hope to cover in a later post) and there are some great products/features in the engineering plan that will greatly improve this problem.

As always, if you have any questions or comments, please feel free to post them here or respond to me personally or the rest of the vCampus team if you would prefer to remain private.  If anybody has any alternate solutions, please, post them up; I'm sure they will be well received.

P.S. All this talk about Collectives has made me think of the Borg - looking forward to the new StarTrek movie (Geek and proud!)