The Transaction Start SA function is the sub-agent user/system callback that is invoked right before the transaction is started.

The server sends “server request” message to SIL-SA subsystems that registered callbacks right before the transaction is started. Once the SIL-SA  subsystems receive the “server-message” Transaction Start SA they will invoke the callbacks. After the callbacks are invoked and if they are successful then subsystem responds with the “ok” message. If the callbacks are not invoked due to some reason or if the callbacks return error then an “error” message is returned to the server causing the server transaction termination.

The following function template definition is used for Transaction Start SA callback functions:


/* Typedef of the trans_start callback */
typedef status_t
    (*agt_cb_sa_trans_start_t) (const xmlChar *transaction_id,
                                boolean isvalidate,
                                boolean isrollback,
                                boolean isrunning);


Callback Template

    

  • Type: User Callback
  • Max Callbacks: No limit (except available heap memory)
  • File: agt_cb.h
  • Template:   agt_cb_sa_trans_start_t
    • Inputs:
      • transaction_id  == transaction ID of the transaction control block in progress
      • isvalidate == TRUE if this is a <validate> operation, the target data nodes will not be altered at all during the transaction. FALSE if this is some sort of real edit.
      • isrollback == TRUE if this is Transaction for a Rollback Phase or Load
      • isrunning == if transaction is for the running datastore
    • Outputs: none
    • Returns: status_t:
      • Status of the callback function execution. If an error is returned the transaction will be terminated.
  • Register: agt_cb_sa_trans_start_register
  • Unregister: agt_cb_sa_trans_start_unregister


Register Callback


The Transaction Start SA callback function is hooked into the server with the agt_cb_sa_trans_start_register function, described below. 


extern status_t
    agt_cb_sa_trans_start_register (agt_cb_sa_trans_start_t cbfn);


The register function is used to declare a specific callback function for Transaction Start SA callbacks. For SIL-SA the registration is done during the Initialization Phase 1 before the startup configuration is loaded into the running configuration database and before running configurations are loaded. 

Initialization function with the registration of the Transaction Start SA callback type may look as follows:


/******************************************************************** 
* FUNCTION interfaces_init
* 
* initialize the server instrumentation library.
* Initialization Phase 1
* 
*********************************************************************/ 
static status_t 
     interfaces_init (void) 
{ 
   ...

    /* Register a Transaction Start callback. */
    res = agt_cb_sa_trans_start_register(transaction_start);
    if (res != NO_ERR) {
        return res;
    }

   ...
}


Callback Cleanup

The SIL-SA version of the Transaction Start SA callback now have unregister functions (Since the versions 19.10-21 and 20.10-9). The callbacks can be cleaned up automatically whether when the subsystem goes away or when the server shuts down, but there will not be any cleanup during <unload> operation. As a result, the SIL-SA code must provide an unregister function to cleanup the callback during <unload> operation (versions 19.10-21 and 20.10-9) .



The Transaction Start callback function is cleaned up with the agt_cb_trans_start_unregister function, described below.


extern void
    agt_cb_sa_trans_start_unregister (agt_cb_sa_trans_start_t cbfn)




Callback Example



The following sections illustrates how to utilize the Transaction Start SA callback in examples. 

In this example, the Transaction Start SA callback function applies multiple actions after the transaction is actually started. The purpose of this function is to provide more validation options and more flexible and easier development. This callback function may deny the start of the transaction if some specific check is unmet. 



In this example, if the transaction is for the <validate> operation on <running> datastore then the SIL-SA callback will trigger an error and deny the server transaction. In addition, for example, the callback function can write a system or other log entries. 

The following example code illustrates how the Transaction Start SA callback may look like.

 

/********************************************************************
* FUNCTION silsa_transaction_start
*
* Start Transaction SA callback
* The Start Transaction function is the user/system
* callback that is invoked before any changes to the
* database will be committed.
*
* RETURNS:
*   status
********************************************************************/
static status_t
    silsa_transaction_start (const xmlChar *transaction_id_val,
                             boolean isvalidate_val,
                             boolean isrollback_val,
                             boolean isrunning_val)
{
    if (!transaction_id_val) {
        log_error("\ntransaction_id value not set");
        return ERR_INTERNAL_VAL;
    }

    const xmlChar *user = sil_sa_get_username();
    const xmlChar *client_addr = sil_sa_get_client_addr();

    if (LOGDEBUG2) {
        log_debug2("\n\n********************************************"
                   "\nEnter silsa_transaction_start callback for silsa-test "
                   "---- 2"
                   "\ntransaction_id -- %s"
                   "\nuser_id -- %s"
                   "\nclient_addr -- %s"
                   "\nisvalidate -- %s"
                   "\nisrollback -- %s"
                   "\nisrunning -- %s"
                   "\n********************************************\n\n",
                   transaction_id_val,
                   user,
                   client_addr,
                   isvalidate_val ? NCX_EL_TRUE : NCX_EL_FALSE,
                   isrollback_val ? NCX_EL_TRUE : NCX_EL_FALSE,
                   isrunning_val ? NCX_EL_TRUE : NCX_EL_FALSE);
    }

    /* return an error when "validate" operation is in progress */
    if (!isrollback_val && isvalidate_val && isrunning_val) {
        return ERR_NCX_INVALID_NUM;
    } else {
        return NO_ERR;
    }

}  /* silsa_transaction_start */


In the example above, the callback simply logs all the available parameters and denies the transaction if it is for <validate> operation on running datastore and return “Invalid Number” error status, as an example.
In this callback, there could be handling for customer specific pointers, it is a good place to initialize specific pointers that will be cleaned after the transaction complete during the Transaction Complete SA callback invocation.
In the example, we used two additional APIs to retrieve current transaction “user name” and “address”:


  /* Get the user_id value from the message header */ 
  const xmlChar *user = sil_sa_get_username();

  /* Get the client address (client_addr value from the message header) */
  const xmlChar *client_addr = sil_sa_get_client_addr();


These two APIs only available in the SIL-SA version of the SIL code and intended to provide an access to specific fields in the message header since the message header itself is not available in the SIL-SA version of of the SIL.