Protocol Implementation > Implement the main function > 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.
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; } |