You have to distinguish between "journals" and "mirror-journals" files. the 1st are to ensure any instance DB integrity (DB corruption) in case of a failure. The 2nd are you ensure proper mirror "failover" and any A-Sync members.

When LIVETC01 (as a Backup) is "catch up" its a good source to copy .DAT files to the LIVEDR.
It is also safe to delete its mirror-journals.
The steps you did to catch up the LIVEDR are correct. (I assume you did "activate" & "catch up" after that in LIVEDR)

After the IRIS.DAT copy (of all DBs in mirror) from LIVETC01 to LIVEDR and both are "catch up" - It is safe to delete mirror-journals up to the point of the copy from your primary LIVETC02

Hello,

The IRIS management portal is a web application.
It connects to the IRIS database with a component called: "CSP Gateway" (can be installed on various web servers: IIS, Apache, Nginx). This "CSP gateway" is enabling you to develop web applications that will interact with the DB directly though this component. You may run "ajax like" code on the server-side, and have all your web pages fully dynamic (generated on the server in run-time).
TO work with the management portal from remote, you may take advantage of it's security mechanism (define users, roles, services) the ability to authenticate with external to IRIS entities (e.g. doing LDAP to ADDS) and also have a two-factor authentication, for better security.

Any external data database or other tool that can do ODBC & JDBC can communicate with IRIS and get data out of it. Those are also.   

Hello, as the documentation is saying, the call to %OnSaveFinally() is done at the last step of the %Save() = after data was written to the database, and the transaction is already committed.

I did a test with a class:

Class USER.TestClass Extends %Persistent
{
   Property Name As %String;
   ClassMethod %OnSaveFinally(oref As %ObjectHandle, status As %Status)
   {
      S ^TestGlobal="This is a test "_$ZDT($H)
   }
}

Then, I've saved some new data into the class:

USER>s obj=##class(USER.TestClass).%New(), obj.Name="Name", sc=obj.%Save() w !,sc
1
USER>zw ^USER.TestClassD
^USER.TestClassD=1
^USER.TestClassD(1)=$lb("","Name")

and then checked the journal entries to see the behavior.
It shows that the %OnSaveFinally() was called just after a successful save after the CT (close of transaction):

1675920  2312 BT  1675936 2312 S  +\iris\mgr\user\ USER.TestClassD = 1
1675992  2312 ST +\iris\mgr\user\ USER.TestClassD(1) = $lb("","Name")       
1676052  2312 CT
1676068  2312 S  +\iris\mgr\user\ TestGlobal = "This is a test 07/15/202+

Adding a soft delete is a good idea, but then indices will have to be changed as well to support that.

If all your 5 places of code are not called, and record are keeping "disappear" then it might be a SQL that is run by a user or developer. I would recommend to :

- have an detailed audit on that table/class to see it's deletions
- check all ODBC/JDBC users - to see if permissions for delete can be removed
- Possibly to have a code to scan journal files, to find that class, global, pid, date time stamp - and store this on a sperate table or global that can be later examined

Hello,


The best way it to do it is to use the dictionary to loop on properties of the original class and create a new class  which is identical, but with a different storage. The cloning is done by using %ConstructClone
Usually, the new class for backup, does not need to have methods, indices or triggers, so those can be "cleaned" before saving it.

Have the original and the destination class objects:

S OrigClsComp=##class(%Dictionary.CompiledClass).%OpenId(Class)
S DestCls=OrigCls.%ConstructClone(1)

You should give the destination class a name and type:

S DestCls.Name="BCK."_Class , DestCls.Super="%Persistent"

Usually the destination class does not need to have anything than the properties, so in case there are methods, triggers or indices that need to be removed from the destination class, you may do: 

F i=1:1:DestCls.Methods.Count() D DestCls.Methods.RemoveAt(i)      ; clear methods/classmethods
F i=1:1:DestCls.Triggers.Count() D DestCls.Triggers.RemoveAt(i)     ; clear triggers
F i=1:1:DestCls.Indices.Count() D DestCls.Indices.RemoveAt(i)       ; clear indices

Setting the new class storage:

S StoreGlo=$E(OrigCls.Storages.GetAt(1).DataLocation,2,*)
S StoreBCK="^BCK."_$S($L(StoreGlo)>27:$P(StoreGlo,".",2,*),1:StoreGlo)

S DestCls.Storages.GetAt(1).DataLocation=StoreBCK
S DestCls.Storages.GetAt(1).IdLocation=StoreBCK
S DestCls.Storages.GetAt(1).IndexLocation=$E(StoreBCK,1,*-1)_"I"
S DestCls.Storages.GetAt(1).StreamLocation=$E(StoreBCK,1,*-1)_"S"
S DestCls.Storages.GetAt(1).DefaultData=$P(Class,".",*)_"DefaultData"

Then just save the DestCls

S sc=DestCls.%Save()

Actually I was always using $Zorder ($ZO) which was "invented" 30 years ago, before $Query (popular MSM, DSM etc.)
Another thing is that $Order is a "vertical" way of looping through an array/global/PVC and $Query (or $ZO) are meant to loop in a "horizontal" way (same as you ZWRITE it)

it has the same functionality, and very easy to use:
Set node = "^TestGlobal(""Not Configured"")" W !,node
^TestGlobal("Not Configured")
F  S node=$ZO(@node) Q:node=""  w !,node,"=",@node
^TestGlobal("Not Configured","Value 1")=value 1
^TestGlobal("Not Configured","Value 2")=value 2

Usually the GREF is the total number of global references (per second). A given process can do a limited number of I/O operations/sec (this is due to the CPU clock speed).
When there are bottlencecks, there are some tools that can tell you which part of your system (or code) can be improved. Monitoring with SAM or other tools can give you some numbers to work with. there is also a %SYS.MONLBL that can help you improve your code.
Storage is also a consideration, sometimes a DB can be optimized to store data in a more compact way and save I/O (especially when you are on the cloud when disks are somehow slower than you have on premisse). 
One easy improvment is to do some "heavy" parts on your system (e.g. reports, massive data manipulatipons etc.) in parallel. This can be done with using the "queue manager" or with the %PARALLEL keyword fr SQL queries.
A more complex way to go is to do a vertical or horizental scale of the system, of even sharding.

Hello,

We are using this on an a-sync mirror member, that we want to be "behind" for any X minutes (parameter)

Here is a sample code:
 

s sc=1

    try {

        I ##class(%SYSTEM.Mirror).GetMemberType()'="Failover" {

            S diff=..GetDiff(debug)

            I diff < minutes {

                I $zcvt(##class(SYS.Mirror).AsyncDejournalStatus(),"U")="RUNNING" {

                    D ##class(SYS.Mirror).AsyncDejournalStop()

                }

            } else {

                I $zcvt(##class(SYS.Mirror).AsyncDejournalStatus(),"U")'="RUNNING" {

                    D ##class(SYS.Mirror).AsyncDejournalStart()

                }

            }

        }

    } catch e {

        ; any error trp you want

    }

    Quit sc

Hello Peter,

Welcome back to the community.

I also have almost ~30 years (since 1991) experience on Intersystems technology starting with some PDP11, VAX & Alpha machines (anyone else misses the VMS OS like I do?) with DSM, the first PCs with MSM and then (1999) came Cache that become IRIS.. very long, interesting and challenging way !

I do remember at 1992 customers with 50-100 users running MSM on a 286 machines. and it was fast (!) At that times, where disks were slow, small & expensive, developers used to define the globals in a very compacted & normalized way, so applications flew on that platform.

Today, when disks (as Rebert said) are without limits, fast & relatively cheap, some "new" developers tend to disparage with a correct design of a DB, which on a big databases of few TBs it is noticeable.
You can get a significant improvement when the are been optimized (this is part of my job in the past few years). and this is not just the data structure, but also in correct way of optimized coding.

In my opinion, the multi-level tree of blocks that hold a global, is limited by the DB itself, which is limited by the OS file system. With global mapping, and sharding (new technology) - even a DB in a size of PETA bytes coukld easily hold them, and be a very efficient, like this technology was forever.