Hello @David Hockenbroch

I tested this simple method using CodeMode = Objectgenerator :

Method test() [ CodeMode = objectgenerator ]
{
    Write
    Quit 1
}

Do $SYSTEM.OBJ.Compile("User.NewClass1","ck")
We can see a lot of variable values at compile time :

....
%qstruct="ck"
....

%qstruct contains compile flags and qualifiers

Hi,

Two years ago, I analyzed the behaviours using stream and %Persistent class.  

Class Test.Stream1 Extends %Persistent
{

Property st As %GlobalBinaryStream;

ClassMethod add1() As %Status
{
	; write stream in ^Test.Stream1S
	Set o = ..%New()
	Do o.st.Write("azeruiop")
	Quit o.%Save()
}

ClassMethod add2() As %Status
{
	; write stream in ^CacheStream
	Set o = ..%New()
	Set st = ##class(%GlobalBinaryStream).%New()
	Do st.Write("azeruiop")
	Set o.st = st
	Quit o.%Save()
}

Storage Default
{
<Data name="Stream1DefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>st</Value>
</Value>
</Data>
<DataLocation>^Test.Stream1D</DataLocation>
<DefaultData>Stream1DefaultData</DefaultData>
<IdLocation>^Test.Stream1D</IdLocation>
<IndexLocation>^Test.Stream1I</IndexLocation>
<StreamLocation>^Test.Stream1S</StreamLocation>
<Type>%Storage.Persistent</Type>
}

}

The method add2 use ^CacheStream due to the default storage usage (as described by @Robert Cemper ).  

However, We can force the storage in ^Test.Stream1S with :
Do st.%LocationSet("^Test.Stream1S")

Hi @Robert Cemper, @Vitaliy.Serdtsev 

Thank you for your replies!
I found a solution to do this without any change to an existing code, not simple but It works and could be useful in a critical situation.

I read the code of ^%ETN and see these lines :

UserError() s $zt="UserErrorE"
 i $d(^rOBJ("%ZERROR")) d 
 . n %00000 d ^%ZERROR

So, If we create a "%ZERROR" routine, we have an entry point :

ROUTINE %ZERROR

%ZERROR
    If $Data(^zForceCommit($Job)) { ; to avoid do this for all processes...
        While $TLEVEL {
            TCOMMIT
        }
    }

    Quit

And then, we must terminate the process like that:

Set pid = "1234" ; pid to terminate
Set ^zForceCommit(pid)=""
Zn "%SYS"
Set process = ##class(SYS.Process).%OpenId(pid)
Set sc = process.Terminate(1)

It's important to use the SYS.Process class and the Terminate method with argument 1 to use ^%ETN.

Code snipet to expose the problem.

Class ZUser.NewClass1 Extends %Persistent [ Not ProcedureBlock ]
{

ClassMethod Demo()
{

    Do ..TestLock()
    ; This class is Not ProcedureBlock the record still locked

    ; If the class is ProcedureBlock the record is released.
    ; try by yourself :-)
}

ClassMethod TestLock() As %Status
{
    Set id = $Order(^ZUser.NewClass1D(""))
    If id = "" {
        Set obj = ##class(ZUser.NewClass1).%New()
        Do obj.%Save()
        Kill obj
    }

    Set id = $Order(^ZUser.NewClass1D(""))

    Set obj = ##class(ZUser.NewClass1).%OpenId(id, 4)

    ; in case of usage Not ProcedureBlock you should 
    ; kill obj or set obj="" (and all others variables with this object reference) to release the lock


    Return $$$OK


}
}

Solved.
Finally, It was simple.
The routine has been installed after the switch, but before my investigation.
So, I thought the routine was there and not performed.

It's useless on your local dev, but depending your goal :
You can try to dump

zzDumpDoc(pkg, targetDir="c:\dev\testdumpdoc\")
    new (pkg, targetDir)

    Do:'##class(%File).DirectoryExists(targetDir) ##class(%File).CreateDirectoryChain(targetDir)

    Set pkgDot = pkg _ ".", class = pkgDot, restore = 0

    If $Isobject($Get(%request)) {
        Set oldRequest = %request
        Set oldResponse = %response
        Set oldSession = %session
        Set restore = 1

    }

    Set %request = ##class(%CSP.Request).%New()
    Set %response = ##class(%CSP.Response).%New()
    Set %session = ##class(%CSP.Session).%New("0123456789")
    Do %session.Unlock()

    Set %request.Data("PAGE",1) = "CLASS"

    For  {
        Set class = $Order(^oddDEF(class))
        Quit:$e(class,1,$l(pkgDot))'=pkgDot
        Set %request.Data("LIBRARY",1) = $namespace
        Set %request.Data("CLASSNAME",1) = class

        Set initialIO = $IO
        Set file = targetDir_class_".html"
        OPEN file:("NRW"):2
        USE file
        Do ##class(%CSP.Documatic.PrintClass).OnPage()
        USE initialIO
        CLOSE file
    }

    If restore {
        Set %request = oldRequest
        Set %response = oldResponse
        Set %session = oldSession
    }
    quit

There exits more elegant way to redirect the output (check the community).

Hello @Evgeny Shvarov ,

I tested the following code in an Iris terminal to add %DB_%DEFAULT role, It seems to work :

Write !,"Current user roles : ",$Roles
Zn "%SYS"
Set tSc = ##class(Security.Applications).Get("/csp/user",.p)
Write !,"Get application : ",$SYSTEM.Status.GetOneErrorText(tSc)
Set p("MatchRoles")=p("MatchRoles")_":%DB_%DEFAULT"
Set tSc = ##class(Security.Applications).Modify("/csp/user",.p)
Write !,"Modify application : ",$SYSTEM.Status.GetOneErrorText(tSc)
Kill p