GT.M handles "trigger definitions" and "triggered updates" differently.
Trigger definition changes appear in both journal files and replication streams so the definitions propagate to recovered and replicated databases.
Triggered updates appear in the journal file, since MUPIP JOURNAL RECOVER/ROLLBACK to not invoke triggers. However, they do not appear in the replication stream since the Update Process on a replicating instance apply triggers and process their logic.
When journaling is ON, GT.M generates journal records for database updates performed by trigger logic. For an explicit database update, a journal record specifies whether any triggers were invoked as part of that update. GT.M triggers have no effect on the generation and use of before image journal records, and the backward phase of rollback / recovery.
A trigger associated with a global in a region that is journaled can perform updates in a region that is not journaled. However, if triggers in multiple regions update the same node in an unjournaled region concurrently, the replay order for recovery or rollback might differ from that of the original update and therefore produce a different result; therefore this practice requires careful analysis and implementation. Except when using triggers for debugging, FIS recommends journaling any region that uses triggers.
The following sample journal extract shows how GT.M journals records updates to trigger definitions and information on $ZTWORMHOLE:
GDSJEX04 01\61731,15123\1\16422\gtm.node1\gtmuser1\21\0\\\ 02\61731,15123\1\16422\0 01\61731,15126\1\16423\gtm.node1\gtmuser1\21\0\\\ 08\61731,15126\1\16423\0\4294967297 05\61731,15126\1\16423\0\4294967297\1\4\^#t("trigvn","#LABEL")="1" 05\61731,15126\1\16423\0\4294967297\2\4\^#t("trigvn","#CYCLE")="1" 05\61731,15126\1\16423\0\4294967297\3\4\^#t("trigvn","#COUNT")="1" 05\61731,15126\1\16423\0\4294967297\4\4\^#t("trigvn",1,"TRIGNAME")="trigvn#1# "05\61731,15126\1\16423\0\4294967297\5\4\^#t("trigvn",1,"CMD")="S" 05\61731,15126\1\16423\0\4294967297\6\4\^#t("trigvn",1,"XECUTE")="W $ZTWORMHOLE s ^trigvn(1)=""Triggered Update"" if $ZTVALUE=1 s $ZTWORMHOLE=$ZTWORMHOLE_"" Code:CR""" 05\61731,15126\1\16423\0\4294967297\7\4\^#t("trigvn",1,"CHSET")="M" 05\61731,15126\1\16423\0\4294967297\8\4\^#t("#TRHASH",175233586,1)="trigvn"_$C(0,0,0,0,0)_ "W $ZTWORMHOLE s ^trigvn(1)=""Triggered Update"" if $ZTVALUE=1 s $ZTWORMHOLE=$ZTWORMHOLE _"" Code:CR""1" 05\61731,15126\1\16423\0\4294967297\9\4\^#t("#TRHASH",107385314,1)="trigvn"_$C(0,0)_" W $ZTWORMHOLE s ^trigvn(1)=""Triggered Update"" if $ZTVALUE=1 s $ZTWORMHOLE=$ZTWORMHOLE_"" Code:CR""1" 09\61731,15126\1\16423\0\4294967297\1\1\ 02\61731,15127\2\16423\0 01\61731,15224\2\16429\gtm.node1\gtmuser1\21\0\\\ 08\61731,15224\2\16429\0\8589934593 11\61731,15224\2\16429\0\8589934593\1\"A process context like--> Discount:10%;Country:IN" 05\61731,15224\2\16429\0\8589934593\1\1\^trigvn="Initial Update" 09\61731,15224\2\16429\0\8589934593\1\1\BA 08\61731,15232\3\16429\0\12884901889 11\61731,15232\3\16429\0\12884901889\1\"A process context like--> Discount:10%;Country:IN Code:CR" 05\61731,15232\3\16429\0\12884901889\1\1\^trigvn="1" 09\61731,15232\3\16429\0\12884901889\1\1\BA 08\61731,15260\4\16429\0\17179869185 11\61731,15260\4\16429\0\17179869185\1\"A process context like--> Discount:10%;Country:IN Code:CR" 05\61731,15260\4\16429\0\17179869185\1\1\^trigvn="Another Update" 09\61731,15260\4\16429\0\17179869185\1\1\BA 02\61731,15263\5\16429\0 01\61731,15865\5\26697\gtm.node1\gtmuser1\21\0\\\ 08\61731,15865\5\26697\0\21474836481 05\61731,15865\5\26697\0\21474836481\1\2\^trigvn(1)="Updated outside the trigger." 09\61731,15865\5\26697\0\21474836481\1\1\BA 02\61731,15870\6\26697\0 01\61731,15886\6\26769\gtm.node1\gtmuser1\21\0\\\ 08\61731,15886\6\26769\0\25769803777 11\61731,15886\6\26769\0\25769803777\1\" Code:CR" 05\61731,15886\6\26769\0\25769803777\1\1\^trigvn="1" 09\61731,15886\6\26769\0\25769803777\1\1\BA 02\61731,15895\7\26769\0 01\61731,15944\7\26940\gtm.node1\gtmuser1\21\0\\\ 08\61731,15944\7\26940\0\30064771073 05\61731,15944\7\26940\0\30064771073\1\3\^trigvn="Another Update" 09\61731,15944\7\26940\0\30064771073\1\1\BA 08\61731,16141\8\26940\0\34359738369 11\61731,16141\8\26940\0\34359738369\1\"A process context like--> Discount:10%;Country:IN Code:CR" 05\61731,16141\8\26940\0\34359738369\1\1\^trigvn="1" 09\61731,16141\8\26940\0\34359738369\1\1\BA 08\61731,16178\9\26940\0\38654705665 11\61731,16178\9\26940\0\38654705665\1\"A process context like--> Discount:10%;Country:IN Code:CR" 05\61731,16178\9\26940\0\38654705665\1\1\^trigvn="Another update" 09\61731,16178\9\26940\0\38654705665\1\1\BA 02\61731,16210\10\26940\0 01\61731,16517\10\5337\gtm.node1\gtmuser1\21\0\\\ 08\61731,16517\10\5337\0\42949672961 05\61731,16517\10\5337\0\42949672961\1\2\^trigvn(1)="4567" 09\61731,16517\10\5337\0\42949672961\1\1\BA 08\61731,16522\11\5337\0\47244640257 11\61731,16522\11\5337\0\47244640257\1\" Code:CR" 05\61731,16522\11\5337\0\47244640257\1\1\^trigvn="1" 09\61731,16522\11\5337\0\47244640257\1\1\BA 08\61731,16544\12\5337\0\51539607553 11\61731,16544\12\5337\0\51539607553\1\"No context Code:CR" 05\61731,16544\12\5337\0\51539607553\1\1\^trigvn="1" 09\61731,16544\12\5337\0\51539607553\1\1\BA 02\61731,16555\13\5337\0 03\61731,16555\13\5337\0\0
This journal extract output shows $ZTWORMHOLE information for each triggered update to ^trigvn
. Notice how GT.M stored trigger definitions as a node of a global-like structure ^#t
and how GT.M journals the trigger definition for ^trigvn
and the triggered update for ^trgvn.
Note: GT.M implicitly wraps a trigger as an M transaction. Therefore, a journal extract file for a database that uses triggers has Type 8 and 9 (TSTART/TCOMMIT) records even if the triggers perform no updates (that is, are effectively No-ops).
During replication, GT.M replicates trigger definitions to ensure that when MUPIP TRIGGER updates triggers on an initiating instance, all replicating instances remain logically identical.
The replication stream has no records for updates generated by implicit GT.M trigger logic. If your trigger action invokes a routine, specify the value of the environment variable gtmroutines before invoking replication with MUPIP so the update process can locate any routines invoked as part of trigger actions.
To support upward compatibility, V5.4-000 allows your originating primary to replicate to:
An instance with a different a trigger configuration.
An instance running a prior GT.M version (having no trigger capability), in which case it replicates any triggered updates.
When a replicating instance needs to serve as a possible future originating instance, you must carefully design your replication filters to handle missing triggers or trigger mismatch situations to maintain logical consistency with the originating primary.
During an event such as rolling upgrade, the replicating instance may have a new database schema (due to application upgrades) and in turn a new set of triggers. Therefore, GT.M replication allows you to have different-trigger configuration for originating (primary) and replicating (secondary) instances. When replication starts between the two instances, any update to triggers on the originating instance automatically flow (through the filters) to the replicating instance. For the duration of the rolling upgrade, your application must use replication filters to ensure trigger updates on the originating instance produce an appropriate action on the replicating instance. However, whenever you follow the practice of creating replicating instances from backups of other appropriate originating instances, you do not have to use additional replication filters, because the backups include GT.M trigger definitions, under normal conditions instances automatically have the same triggers.
Because the replication stream carries the native key format, having different collation for a replicated global on the replicating node from that on the initiating node is effectively a schema change and requires an appropriate filter to appropriately transform the subscripts from initiating form to replicating form. This is true even without triggers. However, with triggers a mismatch also potentially impacts appropriate trigger invocation.
Because GT.M stores triggers in the database files as pseudo global variables, an application upgrade requiring a change to triggers is, in the worst case, no different than an application upgrade that changes the database schema, and can be handled under current rolling upgrade methods. Some changes to GT.M triggers may well be much simpler than a database schema change, and may not need a rolling upgrade.
At replication connection, if an originating primary detects a replicating instance that does not support triggers, the Source Server issues a warning to the operator log and the Source Server log. The Source Server also sends a warning message to the operator log and the Source Server log the first time it has to replicate an update associated with a trigger. In this configuration, internal filters in GT.M strip the replication stream of trigger-related information such as $ZTWORMHOLE data and trigger definition updates from MUPIP TRIGGER or $ZTRIGGER(). The Source Server does send updates done within trigger logic. Unless the application has replication filters that appropriately compensate for the trigger mismatch, this is a situation for concern, as the replicating instance may not maintain logical consistency with the originating primary. Note that filters that deal with $ZTWORMHOLE issues must reside on the originating instance.