Tips & Tricks - Process-private Globals as a class storage

Primary tabs

Process-private Globals  can be used as a data global in storage definition. That way, each process can have its own objects for the class with ppg storage. For example lets define a pool, which can:

  • add elements to a pool (ignoring duplicates)
  • check if an element exists in the pool

Here's the class:

/// Stores unique identifiers
Class Utils.Pool Extends %Persistent
{

Property Value As %String;

Index IDKEY On Value [ IdKey, PrimaryKey, Unique ];

Method %OnNew(Value As %String = "") As %Status [ Private, ServerOnly = 1 ]
{
    Set ..Value = Value
    Quit $$$OK
}

ClassMethod Add(Value As %String = "")
{
    Quit:..%ExistsId(Value)
    Set Obj = ..%New(Value)
    Do Obj.%Save()
}

Storage Default
{
<Data name="PoolDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
</Data>
<DataLocation>^||Utils.PoolD</DataLocation>
<DefaultData>PoolDefaultData</DefaultData>
<IdLocation>^||Utils.PoolD</IdLocation>
<IndexLocation>^||Utils.PoolI</IndexLocation>
<StreamLocation>^||Utils.PoolS</StreamLocation>
<Type>%Library.CacheStorage</Type>
}
}

And the testing code:

/// Do ##class(Utils.Pool).Test()
ClassMethod Test()
{
    Do ..%KillExtent()
    Do ..Add(1)
    Write "Is 1 in pool: ", ..%ExistsId(1),!
    Write "Is 2 in pool: ", ..%ExistsId(2),!
    Do ..Add(2)
    Write "Is 2 in pool: ", ..%ExistsId(2),!
}

Outputs:

Is 1 in pool: 1
Is 2 in pool: 0
Is 2 in pool: 1 

This approach can be used if you  want:

  • Storage space, inaccessible to other processes (without using locks, etc)
  • Store something only while process lives

The code is also available on GitHub.

Comments

Unfortunately in times when web-applications prevail other types of applications this approach is cannot be widely used. This way can't be used directly in CSP, because of by default any session could be joined to any process, but Procces-private globals is not session-provite globals. And If you need to have such functionality with CSP, you should use Preserve sessions or use something like Sessions-private global, something like this

^CacheTemp.SomeTableD($select($isobject($get(%session)):%session.SessionId,1:$job))

Preserve mode should be avoided if at all possible. It has a negative impact on performance, and tempts people into very bad design choices!