Warning: Stale Persistent Objects created by $THIS
tl;dr I have discovered that using $THIS in a very specific way will make persistent objects go stale.
I found that it only happens when using $get on an array that contains the OID reference of $THIS. I assume that this is an unwanted feature and have raised a WRC. The problem can be recreated following the steps below, I have also posted the workaround that I am currently testing and looks to be working fine.
1. Create a persistent class...
{
Property SomeValue As %String;
Method SomeMethod()
{
//this will cause $THIS to go stale in this process
if $get(seen($THIS)) quit
}
ClassMethod Initialise() As %Status
{
set store=..%New()
set store.SomeValue=$zh
quit store.%Save()
}
ClassMethod Update() As %Status
{
set store=..%OpenId(1)
set store.SomeValue=$zh
quit store.%Save()
}
}
2. Open up a terminal and...
3. Open a second terminal and...
zw obj
do obj.SomeMethod()
kill obj
Note, it's when calling SomeMethod() that this object will become stale.
4. In the first terminal...
set obj=##class(Test.Store).%OpenId(1)
zw obj
5. In the second terminal...
zw obj
You will see that the second terminal still has a stale version of the persistent object.
These stale objects are also apparent in CSP sessions.
Workaround
Thanks to Timothy for a simpler workaround...
if $get(seen(""_$THIS))
Appending an empty string prevents the side effect.
Instead of using the OID value of $THIS directly, create a separate variable and create a stringy value of the OID...
set oid=$lg($THIS."%%OID",1)_"@"_$lg($THIS."%%OID",2)
Using the oid variable instead of $THIS makes the problem go away.
Sean.
What Caché version are you seeing this on Sean?
2017.1 and 2014.1
A simpler workaround seems to be:
And here's another way to demonstrate that something weird is going on under the hood:
Interestingly, $data doesn't seem to have the same issue.
yes, much simpler!
and passes all my unit tests
$THIS is object reference (OREF) -- unique identifier of object in memory. Different objects might have the same OREF during process lifetime
And subscript of local/global can be only numeric or a string -- not an object reference.
So, while indeed $GET(a($THIS)) triggers something wrong, the construction itself is not correct.
Timothy's suggestion converts OREF to string:
making command correct.
Notice, that in workaround you proposed -- you are using OID, that is unique identifier of object on disk. Different objects cannot have the same OID.
Out of context of the original code, I agree.
The actual implementation is there to stop an infinite loop on objects that reference each other as part of a JSON serialiser, see line 9...
https://github.com/SeanConnelly/Cogs/blob/master/src/Cogs/Lib/Json/Cogs....
I'm not sure the construction of seen($THIS) is so much incorrect, just problematic. Both seen($THIS) and seen(""_$THIS) will produce an array item with a stringy representation, and works perfectly fine with exception of the unwanted side effect.
My assumption was that $THIS used inside the $get was to be avoided for persistent classes, whilst I could continue to use the OREF for non persistent classes, hence finding that the persistent objects OID was a perfectly good workaround.
However, as it turns out seen(""_$THIS) prevents the unwanted behaviour and makes the code much simpler to read, so thanks to Timothy for testing a different idea out.
Out of interest, I have since discovered that the pattern of seen(+$THIS) is used extensively in Caché / Ensemble library code, where the + symbol will coerce the string to the ordinal integer value from the OREF. I was tempted to use this approach, but one thing I am not sure of is if ordinal values are unique across a mixed collection of objects...
Tim's comment demonstrates that $get leaks an OREF when $this is used as a subscript of an array that doesn't exist. That's a bug.
An OREF as a number is unique within a process, so +$this is more compact, and potentially faster than ""_$this. You should never see, e.g., 1@foo and 1@bar at the same time.
Social networks
InterSystems resources
Log in or sign up
Log in or create a new account to continue
Log in or sign up
Log in or create a new account to continue
Log in or sign up
Log in or create a new account to continue