HP LoadRunner Protocol SDK
Virtual User Data

It is often necessary to store data for the life time of a Vuser. For example, a Vuser may use the same connection or session ID through several actions. Store such information in the Virtual User Data. LoadRunner keeps the Virtual User Data in Thread Local Storage. The virtual user data cannot be accessed until initialized, usually in the ThreadInitEventHandler. An attempt to access thread-local data after the PerProcessInit handler has run but before ThreadInitEventHandler is run, will fail.

Virtual User Data is distinct from data whose life time is a single step. This is stored in the data of the class that implements the function. Data whose life time is an entire run of an instance of the run-time execution component (global data) is initialized in the PerProcessInit handler.

To Use Virtual User Data

Define a type to store the data required by a Vuser in this protocol. The following example shows a type to store a host-to-socket map.

Copy Code
#include <map>
#include <string>
struct CMyVirtualUserData
{
    std::map<std::string, int> hostToSocketMap;
};

When a Vuser is initiated, create an instance of the Vuser Data and set the reference to it, as in the following example:

Copy Code
int ThreadInitEventHandler(void *)
{
    // Create an object of the virtual user data struct/class
    CMyVirtualUserData* myData = new CMyVirtualUserData();
    // Set the reference to the Vuser data
    CProtocolExtension::Instance()->SetVirtualUserData(myData);
    return EVENT_HANDLER_PASSED;
}

To use the data, first get the reference, as in the following example:

Copy Code
void
SendBooleanEcho::Init()
{
    // Check if there is already an open socket
    CMyVirtualUserData* myData =
       (CMyVirtualUserData*)CProtocolExtension::Instance()->
          GetVirtualUserData();
    std::map<std::string, int>::iterator
       mapIterator = myData->hostToSocketMap.find(hostAndPortString);
    if (mapIterator != myData->hostToSocketMap.end())
        socketDescriptor = (*mapIter).second;
    else
    {    // Call an internal function to create a socket
        socketDescriptor = CreateSocket(hostAndPortString);
        myData->hostToSocketMap[hostAndPortString] = socketDescriptor;
    }
}

When the Vuser exits, whether by normal termination or fatal error (abort), release the Virtual User Data along with any other persistent resources, as in the following example:

Copy Code
int ThreadTerminatetEventHandler(void *)
{
    //Get the Vuser Data reference
    CMyVirtualUserData* myData =
        (CMyVirtualUserData*)CProtocolExtension::Instance()->
            GetVirtualUserData();
    if (myData == NULL)
        return EVENT_HANDLER_PASSED;
    // Close open sockets
    std::map<std::string, int>::iterator mapIter =
        myData->hostToSocketMap.begin();
    for(; mapIter != myData->hostToSocketMap.end(); mapIter++)
        CloseSocket((*mapIter).second);
    // Release the storage for the Virtual User Data
    delete myData;
    return EVENT_HANDLER_PASSED;
}