Question
· Mar 10, 2017

Process private global versus percent variable

What are the differences between a process private global and a percent variable?  Basically I have some code running in an Ensemble operation that processes requests, and it needs access to pieces of data that are scattered throughout XData blocks in various classes.  Rather than opening the XData object and deserializing the XML on each request, I opted to cache this data in a percent variable, something like:

set %MyVar(sub1,sub2) = myValue

Which works out nicely: it's accessible from any code invoked by the operation, it persists for as long as the operation is running, and I can clear it out by restarting the operation, if I need to change the XData, for example.  However that got me thinking: I could get all that same behavior from a process private global.  So how are PPGs and %-vars different?  Why choose one over the other?

Discussion (10)0
Log in or sign up to continue

%-variables, stored in local memory of the current process.

Process-private globals, implicitly stored in database CACHETEMP. 

It means, that when you use %-variables, you limited by the memory of your process, (which can be increased programmatically by the way). While Process-private global works exactly as simple global and limited only by free size on the disk. 

And also you should remember that you can not store objects in global variables, even if it is Process-private one.

Access to process-private variables also could be a bit slower than %-variables.

Lets say I have a *.INT routine called %ZLOG. This routine can be called from any namespace and when it is called,  some variables are already defined. I want to check for the existence of a specific PPG before overwriting a collection of variables set by something further up the call stack. If the PPG I created exists then I can safely assume that it was my process that set it.

eg. Before calling %ZLOG, set a PPG in your process then at the start of %ZLOG check for the existence of the PPG.

// Assume variables are set by something else if PPG not present in %ZLOG
Set var1=$GET(var1)
Set var2=$GET(var2)
Set: $DATA(^||ExtractProcess("var1")) var1=^||ExtractProcess("var1") 
Set: $DATA(^||ExtractProcess("var2")) var2=^||ExtractProcess("var2")

PPGs are cleared when the process is terminated so you don't have to kill them off. So if you plan to run something as a background job or have some kind of unique transaction taking place for an individual user's process, PPGs are good to use. In this example, I have opted to use a PPG rather than using the NEW keyword. NEW is only useful if you know what variables to NEW and what not to NEW. At least with a unique PPG I know for a fact that it was my ExtractProcess that created the PPG. %VAR variables are accessible for any namespace but are not specific to a particular process.

Thanks Wolf Koelling.  I should have made it more explicit that %vars are shared across NAMESPACES not processes. When a user logs into our system their process remains active as long as they are logged in. During their login session they can call any number of COS routines to perform a wide range of different functions. Variables not explicitly killed off still reside in memory and this was the problem I had to solve. 

I had to be sure that

a) The %ZLOG COS routine would not crash out because of missing variables the routine expects.

b) All the calls or entry points into %ZLOG would still work as normal otherwise a system-wide crash would occur across all our databases.

c) Be able to identify that if my background process had called %ZLOG then use the PPG created before the call to %ZLOG. No other code in our system uses PPGs whereas there is a plethora of globals, %variables and non-percent variables. 

I could have used a scratch or temporary global such as ^CacheTempUser.DataExtract($JOB). This type of global is killed off when the instance is brought down for our daily backup job. A PPG was very easy to implement.

I have placed a strikethrough on the erroneous statement in my answer.

There have been some conflicting info in the answers to this question so I am going to try and put all the correct info into one place.

Pluses for Process Private Globals:

  1) no size limit

  2) cleaned up by the system when the process exits

  3) explicit KILL will clean up PPG

  4) can be used in a class with Cache SQL Storage

Pluses for % Array:

  1) faster than PPG

  2)  cleaned up by the system when the process exits

  3) explicit KILL will clean up % array

  4) argumentless KILL will clean up % array

  5) Can be used in the NEW command

  6) can be used in a class with Cache SQL Storage

Negatives for Process Private Globals

  1) slower than % Arrays

Negatives for % Arrays:

  1) limited in size by the process memory

I hope this list is close to complete and accurate.

Brendan

This is excellent! Probably the best answer on this question. I would add that sometimes the process is the login session of an individual user and what the user does within that session needs to be carefully managed!

You can also use set $ZS=1234567 to set the max-limit memory for your process. Useful if the default memory is inadequate for a particular process but is fine for everything else.

Another clarification, ppg's are not limited only by disk space, just like all other databases the maximum size of cachetemp can be set to stop infinite growth, this means the ppg's have the same limit.

Also remember, the more you use them the more cachetemp fills.

One last point is that other parts of cache such as odbc queries also use cachetemp for storage and so the whole of cachetemp is not always available.

As ever you have to plan usage appropriately based on the application and the database configuration.