gtpd1m28Database Reference

TPFCS Recoup

Records that are used by TPFCS data stores are recouped as an extension of phase 1 of TPF recoup.

Because TPFCS has no knowledge of the contents of the data stored in a collection, this knowledge must be provided to TPFCS through another means so that collections that contain references to standard TPF files or to other collections can be recouped correctly. TPFCS can obtain information about the contents of the data by requiring the applications to describe the layout of data in a collection. Applications do this by identifying the displacements of any embedded 4- or 8-byte file addresses or PIDs.

General Approach

During phase 1 of TPF recoup, TPFCS recoup will recoup its own internal collections. However, any collections created by user applications will not be recouped unless they are explicitly made known to TPFCS by establishing one or more recoup indexes. A recoup index describes the location of PIDs and 4- or 8-byte file addresses embedded in all collections associated with that recoup index. An anchor collection, usually the data store application dictionary (named DS_USER_DICT) of the data store, refers to user-created collections, which refer to other collections, and so on. Every user-created collection must be referred to by an anchor collection or it will not be recouped. A recoup index must be created and associated with the anchor collection and any other collections that contain embedded references.

Recoup Indexes

Recoup indexes can be managed by an application or by using the ZBROW RECOUP command.

A separate index should be created for each of the different collection formats in your TPFCS database. A recoup index is unique to the data store. If necessary, a recoup index can be deleted.

After a recoup index is created, you must add one or more entries to it. (Previously added entries can be deleted from a recoup index if they are no longer needed.) Recoup index entries identify the location of file addresses or PIDs in the collection data. 4- or 8-byte file addresses embedded in TPFCS collections must be part of a traditionally chained TPF structure and must have a corresponding TPF recoup descriptor. File addresses of TPFDF records cannot be embedded in TPFCS collections.

There are two basic types of recoup indexes. The first type, known as an homogeneous index, is used when each of the elements in the collections associated with this index has the same format and can be recouped the same way. A homogeneous recoup index can be associated with any type of collection with the exception of BLOBs. The second type, known as a heterogeneous index, is used when the elements in the collections associated with this index cannot be recouped the same way because they have different formats. When adding entries to a heterogeneous index, you must specify which elements have embedded 4- or 8-byte file address or PID information (as well as the displacements in those elements where the file address or PID information is stored). The following restrictions exist:

Because BLOBs have a single element, special processing is required and the recoup index type indicator is ignored. Therefore, the recoup index associated with a BLOB is not considered to be either homogeneous or heterogeneous.

After the recoup index has been created, it can be associated with one or more collections if they have the same format for embedded 4- or 8-byte file addresses or PIDs. However, a single collection can only be associated with one recoup index at a time. You can also associate a recoup index with a collection when the collection is created by using an option list. You can also remove an association whenever you have determined that you no longer want TPFCS recoup to use a given recoup index to process the collection.

TPFCS will use the TPFCS recoup indexes to chain chase any embedded 4- or 8-byte file addresses or PIDs while processing a ZRECP RECALL command. You can also recoup individual collections by identifying a specific data store (DS). In test mode, use the ZRECP RECALL command with the SEL and DS parameters specified to recoup a specific collection. In production mode, use the ZRECP SELECT command with the PID parameter specified to recoup a specific collection when the collection has errors. To display the status of TPFCS recoup, use the ZRECP STATUS command. TPFCS recoup status messages are displayed approximately every minute, when recoup processing for a data store ends or when the ZRECP STATUS command is entered. See TPF Operations for more information about the ZRECP commands.

The following table lists the operations you can perform on a recoup index and identifies the API or parameter of the ZBROW RECOUP command you can use for each operation.


Table 17. Managing TPFCS Recoup Indexes

Operation API ZBROW RECOUP Command Parameter
Create a recoup index TO2_createRecoupIndex DEFINE
Add an entry to a recoup index TO2_addRecoupIndexEntry ADD
Associate a collection with a recoup index TO2_associateRecoupIndexWithPID LINK
Display recoup indexes None DISPLAY
Delete a recoup index to collection association TO2_removeRecoupIndexFromPID UNLINK
Delete an entry from a recoup index TO2_deleteRecoupIndexEntry REMOVE
Delete a recoup index TO2_deleteRecoupIndex DELETE

See the TPF C/C++ Language Support User's Guide for more information about TPFCS APIs and TPF Operations for more information about the ZBROW RECOUP command.

Embedded 4-Byte File Address Information

If 4-byte file addresses are embedded in a collection, they must be stored as a 16-byte entry of type TO2_RECOUP_FA, which has the following format:

unsigned char format
Indicates the type of file address that is contained.

TO2_RECOUP_FRMT_FARF
Indicates that fileAddr is a 4-byte file address.

unsigned char reserved1
Reserved for future IBM use; must be set to zero.

unsigned char flag
Indicates whether this reference contains overflow records or other referenced records.

TO2_RECOUP_DSCR_NO
Indicates that this reference does not contain any overflow records or other referenced records.

TO2_RECOUP_DSCR_YES
Indicates that this reference contains overflow records or other referenced records. Create a unique group or index record set by entering the GROUP macro with the USE parameter specified with a value of TPFCS, and the IND parameter specified with a value of C and loaded as a recoup descriptor. See TPF System Macros for more information about the GROUP macro.

unsigned char recID[2]
Hexadecimal record ID.

unsigned char rcc
Hexadecimal record code check (RCC), or set to zero.

unsigned char ctl
Must be set to 0.

TO2_FARF_FA fileAddr
File address.

unsigned long reserved
Reserved for future IBM use; must be set to zero.

Embedded 8-Byte File Address Information

If 8-byte file addresses are embedded in a collection, they must be stored as a 16-byte entry of type TO2_RECOUP_XFA, which has the following format:

unsigned char format
Indicates the type of file address that is contained.

TO2_RECOUP_FRMT_FARF6
Indicates that fileAddr is an 8-byte file address.

unsigned char reserved1
Reserved for future IBM use; must be set to zero.

unsigned char flag
Indicates whether this reference contains overflow records or other referenced records.

TO2_RECOUP_DSCR_NO
Indicates that this reference does not contain any overflow records or other referenced records.

TO2_RECOUP_DSCR_YES
Indicates that this reference contains overflow records or other referenced records. Create a unique group or index record set by entering the GROUP macro with the USE parameter specified with a value of TPFCS, and the IND parameter specified with a value of C and loaded as a recoup descriptor. See TPF System Macros for more information about the GROUP macro.

unsigned char recID[2]
Hexadecimal record ID.

unsigned char rcc
Hexadecimal record code check (RCC), or set to zero.

unsigned char ctl
Must be set to zero.

TO2_FARF6_FA fileAddr
File address.

Embedded Persistent Identifier (PID) Information

If PIDs are embedded within a collection, they must be stored in the following format:

TO2_PID
The PID of the referenced collection.
Note:
Recoup will ignore an embedded PID that is all zeros.

Sample TPFCS Recoup Applications

The following examples are intended as suggested uses for TPFCS recoup applications.

The following example creates recoup indexes:

/*********************************************************************/
/* Sample application to create recoup indexes                       */
/*********************************************************************/
 
#include <tpfapi.h>        /* Needed for TPF_regs structure          */
#include <c$to2.h>         /* Needed for TO2 API functions           */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
void main( void )
{
  TO2_ENV_PTR        env_ptr = NULL;     /* pointer to environment   */
  TO2_USER_TOKEN     userToken = 0;      /* user token               */
  char               applid[] = "RECOUP_INDEX_CREATOR            ";
  char               dsname[] = "TESTX.DS";
 
  TO2_PID            dsDictPID;          /* DS dictionary PID        */
  TO2_PID_PTR        dsDictPtr = &dsDictPID; /* ptr to DS dict PID   */
  char               IndexName[8];       /* Recoup index name        */
  TO2_RECOUP_TYPE    rc_type;            /* recoup index type        */
  TO2_RECOUP_CONTROL rc_ctrl;            /* recoup index control     */
  TO2_RECOUP_ENTRY_TYPE    rce_type;     /* PID or FA indicator      */
  TO2_RECOUP_ENTRY_ACCESS  rce_access;   /* index or key indicator   */
  char                     rce_token[8]; /* recoup index entry token */
  long                     rce_displ;    /* displ. to embedded ref.  */
  long                     rce_valLen;   /* length of collect. index */
  long                     rce_value;    /* collection index         */
 
/*********************************************************************/
/* Create TO2_environment                                            */
/*********************************************************************/
  if (TO2_createEnv(&env_ptr,&userToken,applid,dsname) == TO2_ERROR)
  {
     printf("ERROR: createEnv failed ! \n");
     exit(1);
  }
 
/*********************************************************************/
/* Set up the recoup index for the application dictionary collection.*/
/* If this index already existed, delete it first and recreate it.   */
/* Each entry in the dictionary collection will have a PID embedded  */
/* at a displacement of 0, so the collection is homogeneous.         */
/*********************************************************************/
  if (TO2_getDSdictPID(dsDictPtr, env_ptr) == TO2_ERROR)
  {
     printf("ERROR: getDSdictPID failed\n");
     TO2_deleteEnv(env_ptr);
     exit(1);
  }
 
  memcpy(IndexName, "APPLDICT", 8);
  TO2_deleteRecoupIndex(env_ptr, IndexName);
 
  rc_type = TO2_RECOUP_HOMOGENEOUS;
  rc_ctrl = TO2_RECOUP_CONTROL_NONE;
  if (TO2_createRecoupIndex(env_ptr, IndexName, rc_type, rc_ctrl,
       NULL, NULL, "Used with data store appl dictionary") == TO2_ERROR)
  {
     printf("ERROR: createRecoupIndex %s failed\n", IndexName);
     TO2_deleteEnv(env_ptr);
     exit(1);
  }
 
  memcpy(rce_token, "ENTRY001", 8);
  rce_type = TO2_RECOUP_ENTRY_PID;
  rce_displ = 0;
  rce_access = TO2_RECOUP_ACCESS_NOTUSED;
  if (TO2_addRecoupIndexEntry(env_ptr, IndexName, &rce_token,
                              rce_type, &rce_displ,
                              rce_access, NULL, NULL) == TO2_ERROR)
  {
     printf("ERROR: addRecoupIndexEntry for DS failed !\n");
  }
 
  if (TO2_associateRecoupIndexWithPID(dsDictPtr, env_ptr, IndexName)
                                                      == TO2_ERROR)
  {
     printf("ERROR: associateRecoupIndexWithPID for DS failed !\n");
  }
 
/*********************************************************************/
/* Create a recoup index for a heterogeneous collection.             */
/* Every collection that is associated with this recoup index must   */
/* have the following format:                                        */
/*   The second element has two embedded references; a file address  */
/*       at displacement 16, and a file address at displacement 40.  */
/*   The third element has an embedded file address at displacement  */
/*       14.                                                         */
/* (Note: Minimal error checking is shown.)                          */
/*********************************************************************/
  memcpy(IndexName,"HETERO01",8);
  rc_type = TO2_RECOUP_HETEROGENEOUS;
  rc_ctrl = TO2_RECOUP_CONTROL_NONE;
  if (TO2_createRecoupIndex(env_ptr, IndexName, rc_type, rc_ctrl,
                            NULL, NULL, NULL) == TO2_ERROR)
  {
     if (TO2_getErrorCode(env_ptr) == TO2_ERROR_INDEX_EXISTS)
        printf("Index %8s already exists\n", IndexName);
     else
     {
        printf("ERROR: createRecoupIndex %s failed\n", IndexName);
        TO2_deleteEnv(env_ptr);
        exit(1);
     }
  }
 
  memcpy(rce_token, "ENTRY01A", 8);
  rce_type = TO2_RECOUP_ENTRY_FA;
  rce_displ = 16;
  rce_access = TO2_RECOUP_ACCESS_INDEX;
  rce_valLen = 4;
  rce_value = 2;
  TO2_addRecoupIndexEntry(env_ptr, IndexName, &rce_token,
                          rce_type, &rce_displ, rce_access,
                          &rce_valLen, &rce_value);
 
  memcpy(rce_token, "ENTRY01B", 8);
  rce_displ = 40;
  TO2_addRecoupIndexEntry(env_ptr, IndexName, &rce_token,
                          rce_type, &rce_displ, rce_access,
                          &rce_valLen, &rce_value);
 
  memcpy(rce_token, "ENTRY02A", 8);
  rce_displ = 14;
  rce_value = 3;
  TO2_addRecoupIndexEntry(env_ptr, IndexName, &rce_token,
                          rce_type, &rce_displ, rce_access,
                          &rce_valLen, &rce_value);
 
/*********************************************************************/
/* Delete TO2_environment                                            */
/*********************************************************************/
  TO2_deleteEnv(env_ptr);
  exit(0);
}

The following example associates recoup indexes with collections:

/*********************************************************************/
/* Sample application to associate recoup indexes with collections   */
/*********************************************************************/
 
#include <tpfapi.h>        /* Needed for TPF_regs structure          */
#include <c$to2.h>         /* Needed for TO2 API functions           */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tpfio.h>         /* Needed for getfc()                     */
 
void main( void )
{
  TO2_ENV_PTR        env_ptr = NULL;       /* pointer to environment */
  TO2_USER_TOKEN     userToken = 0;        /* user token             */
  char               applid[] = "APPLICATION_1                   ";
  char               dsname[] = "TESTX.DS"; /* data store name       */
  char               IndexName[8];         /* Recoup index name      */
  TO2_PID            pid;                  /* area for array PID     */
  TO2_PID_PTR        arpid_ptr=&pid;       /* pointer to array PID   */
  char               element[50];          /* array element          */
  long               element_length;       /* length of array element*/
  TO2_RECOUP_FA      fa_entry;             /* fileAddr entry in elem */
  char               recid[2];             /* fileAddr record ID     */
  unsigned int       file_addr;            /* TPF record file address*/
  struct stdhdr     *file2rec_ptr;         /* pointer to TPF record  */
  long               size;                 /* size of PID            */
  TO2_OPTION_PTR     optionListPtr = NULL; /* pointer to option list */
  char               colName[64];          /* collection name        */
 
/*********************************************************************/
/* Create TO2_environment                                            */
/*********************************************************************/
  if (TO2_createEnv(&env_ptr,&userToken,applid,dsname) == TO2_ERROR)
  {
     printf("ERROR: createEnv failed ! \n");
     exit(1);
  }
 
/*********************************************************************/
/* Create an array that is associated with the heterogeneous recoup  */
/* index created in the previous sample application.  The array will */
/* be an anchor collection in the data store, so add it to the data  */
/* store application dictionary.  Also, assign a browse name to the  */
/* array that is the same as the array's key in the application dict.*/
/*********************************************************************/
  memcpy(IndexName,"HETERO01",8);
  element_length = sizeof(element);
  optionListPtr = TO2_createOptionList(env_ptr,
                                       TO2_OPTION_LIST_CREATE,
                                       TO2_CREATE_RECOUP,
                                       TO2_OPTION_LIST_END,
                                       IndexName);
  if (TO2_createArrayWithOptions(arpid_ptr, env_ptr, optionListPtr,
                                 &element_length) == TO2_ERROR)
  {
     printf("ERROR: createArray failed !\n");
  }
  free(optionListPtr);
 
  memset(colName, 0x00, sizeof(colName));
  memcpy(colName, "ARRAY1", 6);
  size = sizeof(TO2_PID);
  TO2_atDSdictNewKeyPut(env_ptr, colName, arpid_ptr, &size);
 
  TO2_defineBrowseNameForPID(arpid_ptr, env_ptr, colName);
 
/*********************************************************************/
/* Add the 3rd element to the array.  This element has a TPF file    */
/* address embedded at a displacement of 14 bytes.  The TPF file has */
/* a standard TPF header and will contain forward references.        */
/*********************************************************************/
  recid[0] = 0xAB;
  recid[1] = 0x12;
  file_addr = getfc(D2, GETFC_TYPE0, recid, GETFC_BLOCK|GETFC_FILL,
                    GETFC_NOSERRC, 0x00);
  memset(&fa_entry, 0x00, sizeof(fa_entry));
  fa_entry.flag = TO2_RECOUP_DSCR_YES;
  memcpy(&fa_entry.recID, recid, 2);
  memcpy(&fa_entry.fileAddr, &file_addr, 4);
 
  file2rec_ptr = ecbptr()->ce1cr2;
  memcpy(file2rec_ptr,&array_entry.recID,4);
  filec(D2);
 
  memset(&element, 0x00, sizeof(element));
  memcpy(element,"DATA BEFORE FA",14);
  memcpy(&element[14], &fa_entry, sizeof(fa_entry));
  memcpy(element,"DATA AFTER FA",13);
  TO2_add(arpid_ptr, env_ptr, element, &element_length);
 
/*********************************************************************/
/* Delete TO2_environment                                            */
/*********************************************************************/
  TO2_deleteEnv(env_ptr);
  exit(0);
}