Preventing Globals From Getting Journaled (Continued from How do I Minimize My Journals)
Coming back to the topic of how to minimize journals.
(It took me longer than I hoped since my last post on this topic...)
As I concluded in my last post -
To avoid a global from being journaled there are several options:
- Turning off journaling system wide
- Mapping globals to CACHETEMP
- Mapping globals to non-journaled databases
- Turning off journaling for a process
- Turning off transactions for object filing
In this post I will cover these options:
For obvious reasons (detailed in my previous post), this is not recommended and is quite an "aggressive" move to solve a specific problem.
Then if I try the same example shown in the previous post of saving a Person object, in SAMPLES:
This does not get into the Journal file…
Note I am using the same SSN value that already exists in the database, though I know there is a Unique index defined on that field, so this Save should fail, and a rollback should be performed…
But journaling is off so we get a ROLLFAIL error:
(In theory if one would want to take this approach of totally disabling journaling, you'd also need to take care of system startup, since the system always comes up with journaling on, so you need to make sure journaling is to be stopped for every system startup (you'd put this into the SYSTEM label of the %ZSTART routine you'd define. See here for more details)
b. Map the relevant globals to CACHETEMP
CACHETEMP is a special database for temporary data, and data in it is not journalled even in transactions.
Assuming you know what globals are the problematic ones (see a previous post re finding them) you can map the specific ones to CACHETEMP
A few considerations before you go ahead with this:
- You'd need to take special care if you'd consider mapping the same global from different namespaces to CACHETEMP, unintended "clashes" can occur and this should be prevented (for example by using a different identifier subscript).
- Another consideration is security. You might not want some Roles/Users having access to different data coming from various namespaces.
- The third one is quite obvious but still worth pointing out - CACHETEMP is for temporary data. As such it's contents gets deleted upon restart. In some cases you might have opted not to journal the data as in case of disaster you can recover the data by some other means (rebuilding from some external source, or by some logic) but you might not want to have to rebuild this data every system startup.
Here's an example how this plays out - say I map the global ^myMapped from the ENSEMBLE namespace to CACHETEMP database:
[By the way if you prefix your global name by CacheTemp (e.g. ^CacheTempMyGlobal) it will be automagically mapped to CACHETEMP, without explicitly defining the mapping]
I then set it (together with another global for comparison - ^notMapped):
In the journal we just see the ^notMapped global:
And since this global is mapped to CACHETEMP this is true even in a transaction:
Again, the ^myMapped global is not journaled:
Note rolling back such a transaction will not generate an error, but the CACHTEMP-mapped global will not get rolled-back.
Say I start off with both (mapped and not mapped) globals like this:
Then in the transaction I change their values, but eventually roll it back:
So the not-mapped will roll back its value:
But the mapped will not…
You can see here more about mapping globals (as well as the link from the Tutorial provided above). Note you can also use wildcards to define a global prefix.
Regarding defining this programmatically you can use the Config.MapGlobals related class, or use the related %Installer manifest tag <GlobalMapping>. For example from the Sample.Installer class in the SAMPLES namespace:
c. Map the relevant globals to a non-journaled database
This is similar to the CACHETEMP mapping approach - only one needs to keep in mind, as previously mentioned, that if the global gets set within a transaction the global will still be journaled even if the database it's in is marked as not journaled. Therefore this approach is appropriate only if you are sure the data is being manipulated not within transactions. Note that by default, any object saving, is done within transactions (see below a note about that)
d. Turn off journaling for the specific process
Turning off journaling all-together for a specific process (and for a specific time-frame) would prevent journaling for any globals within the process (even in transactions).
You can do this by calling the DISABLE^%NOJRN routine (at some stage also referred to as %SYS.NOJRN).
For example I did the following (in two different Terminals to illustrate that while one process has journals disabled, the other still journals):
In the right-hand side (Process #8852) you can see I set a global before disabling, one during, and again one after, and on the left side (process #11516) I set one global while the journaling was disabled on the right side.
This is what we can see in the Journal:
You can see the ^beforeDisable from 8852 (you can ignore the Audit entry as it audits the journal state change), but not the SET while journal was disabled for process 8852, while you still see the SET that was performed in 11516 while it was disabled in 8852, and then finally once it was enabled again you can see the 8852 got the SET journaled again.
(The reverse by the way, as seen in the example above, is ENABLE^%NOJRN)
Per above even if a database is marked to be not journaled, within a transaction, and an object Save is by default in a transaction, globals are still journaled. So you can turn off transactions for object saving by calling the %SYSTEM.OBJ.SetTransactionMode() method.
For example, the same from above, while saving a Person object in SAMPLES which is not journaled, though in %Save(), this will not journal due to turning off the transaction mode:
Again this would help only for a database that is anyway not journaled.