Product Documentation

FairCom ISAM for C

Previous Topic

Next Topic

ctRecordUpdateCallbackControl

Declaration

ctRecordUpdateCallbackControl() is used to add and delete callback function definitions. Its prototype is as follows:

NINT ctDECL ctRecordUpdateCallbackControl(pRUCBCTL prucbctl);

Description

A file can have one or more callback function definitions. Each callback function definition is identified by its name, which is a case-sensitive ASCII string. The callback functions are called in the order in which they were added.

These callbacks execute within the server process space. Programming errors will affect the entire database server process.

The synchronous callback types ( RUCBonrecupd, RUCBontrancmt ) occur in the context of the calling user. Most c-tree APIs cannot be safely called from these callbacks, as they may alter existing internal user state information. For advanced usage, information could be sent to another thread to make c-tree file calls if desired. ctThrd* APIs are useful in this regard to pass information to another thread.

The asynchronous callback types ( RUCBqueuethrd, RUCBqueueapp ) are more flexible, since they don't share the same state as the original operation. It should be safe to directly call c-tree file APIs, however, ensure you don't operate on the same file that is generating the callback.

More generally, within the server each thread has an implicit top level "connection" context that is single threaded, which we call OWNER. If you want to do something like have a pool of worker threads, you'll need to manage this using ctSetOWNER (faircom.com) or ctdbGetCtreeOWNER()/ctdbSetCtreeOWNER(). Only a single thread should be within a c-tree API call with a particular OWNER at the same time.

The RUCBCTL structure has the following definition:

typedef struct rucbctl {

COUNT version; /* version of this structure */

COUNT opcode; /* operation code */

LONG bufsiz; /* buffer size */

pVOID bufptr; /* input/output buffer */

#ifndef ct8P

LONG pad;

#endif

} RUCBCTL, *pRUCBCTL;

The RUCBACB structure, used when adding a callback definition, has the following definition:

/* Input buffer format for RUCBCTLaddcallback opcode. */

typedef struct rucbacb {

COUNT version; /* Version of this structure */

FILNO datno; /* Data file number */

LONG calltm; /* Time of function call */

LONG nfncnames; /* Number of function names */

LONG pad; /* Padding to ensure 8-byte alignment of next field */

pTEXT datnam; /* Data file name */

pTEXT cbname; /* Unique name to identify this callback */

pTEXT dllname; /* Name of callback DLL */

pTEXT params; /* Optional parameters */

ppTEXT fncnames; /* Callback function names */

#ifndef ct8P

LONG pad2[5];

#endif

} RUCBACB, *pRUCBACB;

The calltm member defines "when" a callback is executed. There are currently four possible values:

  • RUCBonrecupd - Synchronous call during record update.
  • RUCBontrancmt - Synchronous call during transaction commit.
  • RUCBqueuethrd - Asynchronous queue update to a background thread that will call the callback after the transaction commits.
  • RUCBqueueapp - Asynchronous queue update to the transaction log or memory queue. The application is responsible for reading the log/queue.

The RUCBDCB structure, used when deleting a callback definition, has the following definition:

/* Input buffer format for RUCBCTLdelcallback opcode. */

typedef struct rucbdcb {

COUNT version; /* Version of this structure */

FILNO datno; /* Data file number */

LONG pad; /* Padding for 8-byte pointer alignment */

pTEXT datnam; /* Data file name */

pTEXT cbname; /* Unique name to identify this callback */

#ifndef ct8P

LONG pad2[2];

#endif

} RUCBDCB, *pRUCBDCB;

Option to Update All Existing Records

The default when adding a callback is to not call it for existing records. An option can be specified to choose a new behavior of calling the callback for all existing records. This option, RUCBcallexist, is specified by OR'ing it into the calltm field of the RUCBACB structure when calling ctRecordUpdateCallbackControl().

Return Values

Value

Symbolic Constant

Explanation

0

NO_ERROR

Successful operation.

See c-tree Plus Error Codes for a complete listing of valid c-tree Plus error values.

Example

Follow these steps to use ctRecordUpdateCallbackControl() to add a callback function:

  1. Declare RUCBCTL and RUCBACB structures and a list of callback names:

    RUCBCTL rucbctl;

    RUCBACB rucbacb;

    pTEXT myCallbackFunctionNames[NbrRUCBFnc] = {

    "rucbOpenFileCallback",

    "rucbCloseFileCallback",

    "rucbRecordUpdateCallback"

    };

    NINT rc;

  2. Initialize the RUCBCTL structure to indicate that this is an add callback operation:

    memset(&rucbctl,0,sizeof(rucbctl));

    rucbctl.verson = RUCBCTL_VERS_V01;

    rucbctl.opcode = RUCBCTLaddcallback;

    rucbctl.bufsiz = sizeof(rucbacb);

    rucbctl.bufptr = &rucbacb;

  3. Initialize the RUCBACB structure with your callback settings:

    memset(&rucbacb,0,sizeof(rucbacb));

    rucbacb.verson = RUCBACB_VERS_V01;

    rucbacb.opcode = RUCBCTLaddcallback;

    /* datno of -1 instructs ctRecordUpdateCallbackControl() to open the file;

    ** otherwise it is the file number of an already-open data file. */

    rucbacb.datno = -1;

    rucbacb.datnam = "mydatafile.dat";

    rucbacb.dllname = "ctuser.dll";

    rucbacb.params = "my parameters";

    rucbacb.fncnames = myCallbackFunctionNames;

    rucbacb.nfncnames = NbrRUCBFnc;

    rucbacb.cbname = "My First Callback";

    /* This record update callback will be called on record update. */

    rucbacb.calltm = RUCBonrecupd;

  4. Call ctRecordUpdateCallbackControl() and check the result:

    if ((rc = ctRecordUpdateCallbackControl(&rucbctl)) != NO_ERROR)

    printf("Error: Failed to add record update callback function '%s': %d (%d)\n",

    rucbacb.cbname,rc,sysiocod);

    else

    printf("Successfully added record update callback function '%s'.\n",

    rucbacb.cbname);

To use ctRecordUpdateCallbackControl() to delete a callback function:

  1. Declare RUCBCTL and istructures:

    RUCBCTL rucbctl;

    RUCBDCB rucbdcb;

    NINT rc;

  2. Initialize the RUCBCTL structure to indicate that this is a delete callback operation:

    memset(&rucbctl,0,sizeof(rucbctl));

    rucbctl.verson = RUCBCTL_VERS_V01;

    rucbctl.opcode = RUCBCTLdelcallback;

    rucbctl.bufsiz = sizeof(rucbdcb);

    rucbctl.bufptr = &rucbdcb;

  3. Initialize the RUCBDCB structure with your callback settings:

    memset(&rucbdcb,0,sizeof(rucbdcb));

    rucbdcb.verson = RUCBDCB_VERS_V01;

    /* datno of -1 instructs ctRecordUpdateCallbackControl() to open the file;

    ** otherwise it is the file number of an already-open data file. */

    rucbdcb.datno = -1;

    rucbdcb.datnam = "mydatafile.dat";

    rucbdcb.cbname = "My First Callback";

  4. Call ctRecordUpdateCallbackControl() and check the result:

    if ((rc = ctRecordUpdateCallbackControl(&rucbctl)) != NO_ERROR)

    printf("Error: Failed to delete record update callback function '%s': %d (%d)\n",

    rucbdcb.cbname,rc,sysiocod);

    else

    printf("Successfully deleted record update callback function '%s'.\n",

    rucbdcb.cbname);

TOCIndex