Skip to main content

     
  TPF : Library : TPF Newsletters
Products > Software > Host Transaction Processing > TPF > Library > Newsletters >

Logical Record Caching

Sue Pavlakis, IBM TPF Development, George Leier, IBM TPF Test Core Team, and Fay Casatuta, IBM TPF ID Core Team

Overview

Logical record cache support (APAR PJ27083) allows applications to define and use memory caches, and provides fast access to frequently used information through logical record caches.

Logical record caching is a set of system functions that allow an application to define and use memory caches. A cache is a hashed structure for holding information in a temporary storage area (system heap) where a copy of the data is saved to avoid refetching that data on every access. The data is retrieved from temporary storage instead of its permanent residence. The cache gives the application fast access to frequently used information without always needing to retrieve the information from an external storage device.

Logical record caches are named caches that are subsystem shared with entries that are subsystem unique and either processor unique or processor shared. Processor unique caches hold data that is only used and updated by one processor. The data pertains only to the processor where it resides and does not need to be kept synchronous with the image of any other processor. A processor unique cache does not require a coupling facility (CF). Processor shared logical record caches are discussed later in this article.

The information held in the logical record cache must also be resident on an external storage device. A cache is lost over a processor IPL and must be reestablished by the application after an IPL occurs. There is no mechanism for preserving the contents of a cache over an IPL.

Two areas of the TPF 4.1 system use logical record caching:

  • File system support: To improve file system performance, processor unique logical record caches were created for the directory information and the i-node information. This support was provided with APAR PJ26713 on program update tape (PUT) 11. With PUT 13, these caches were converted to processor shared logical record caches to keep the updates synchronized between all processors in the complex. This support was provided with APAR PJ27083 and is discussed later in this article.

  • Domain name system (DNS) support: DNS support uses two DNS client caches, saved gethostbyaddr() responses and saved gethostbyname() responses. With logical record caching, there is no longer a need to retrieve data from an external DNS server on every reference. Both types of caches are processor unique caches with entries that are timed out. This support was provided with APAR PJ27268 on PUT 13.

Today, with logical record cache support provided on PUT 13, you can use the application programming interfaces (APIs) that are provided to do the following:

  • Create a logical record cache
  • Add a logical record cache entry
  • Update a logical record cache entry
  • Read a logical record cache entry
  • Delete a logical record cache entry
  • Flush a logical record cache
  • Delete a logical record cache.

An explanation of each API and information about how to use it in your application program is provided later in this article. Coding examples are also provided.

Processor Shared Logical Record Caches

Processor shared logical record caches hold data that can be used and updated by all processors in a complex so the data must be kept synchronous between all the processors. CF support is used to keep this data synchronous for all processors in the complex. Therefore, to make use of processor shared logical record caches, at least one CF must be available to the complex. A discussion of how the operating system uses CF support to synchronize the data follows.

When an application creates a processor shared logical record cache, operating system logical record cache support creates a local cache for the processor using system heap and also creates a cache structure on a CF. When the application creates the same processor shared logical record cache on another processor in the complex, operating system support again creates a local cache for this other processor and connects this other processor to the existing cache structure on the CF; that is, there is a local cache for each processor, but only one cache structure on the CF for a given processor shared logical record cache.

When an application adds an entry to the processor shared logical record cache, operating system logical record cache support adds the entry to the processor's local cache and registers interest in the cache entry on the CF. An indicator in the processor's local cache vector is assigned to the added logical record cache entry.

When an application updates an entry in the processor shared logical record cache, operating system logical record cache support updates the entry in the processor's local cache and uses the CF's cross-invalidate mechanism to inform other processors in the complex of the change to the data. Cross-invalidate processing involves setting the indicator in each processor's local cache vector for the logical record cache entry to indicate that the locally cached copy of the data is no longer valid.

When an application reads an entry in the processor shared logical record cache, operating system logical record cache support checks the indicator in the local cache vector for the logical record cache entry to determine whether the locally cached copy of the data is still valid. If the locally cached copy is still valid, the data is returned to the application from the local cache. If the locally cached copy is no longer valid, a CACHE_NOT_FOUND indication is returned to the application and the application must retrieve the data from permanent storage and add the entry to the logical record cache again.

It is important to note that the cache structure on the CF is a directory-only cache. No data is stored in a directory-only cache. The directory-only cache is used to maintain consistency of data in the local caches of processors.

File System Usage of Processor Shared Caches

As discussed previously in this article, file system performance was improved by using processor unique logical record caches for the directory information and the i-node information. However, the data in these caches can be updated by any processor in the complex. To keep the updates synchronized between all the processors in the complex, these caches were converted to processor shared logical record caches. This support was provided with APAR PJ27083 on PUT 13.

Logical Record Cache Attributes

A logical record cache is given a name when it is created. An entry in a logical record cache is uniquely identified by the database ID (DBI) in the entry control block (ECB), a primary key, and optionally, a secondary key. When a logical record cache is created, it is assigned a cache token. This cache token is used on subsequent function calls to identify the logical record cache.

Creating a Logical Record Cache

To create a logical record cache, an application uses the newCache function, passing the following as parameters:

  • The name of the logical record cache being created. If the logical record cache is processor shared, all processors in the complex must use the same name.

  • A pointer to a field where the cache token for the created logical record cache will be stored.

  • The maximum lengths of the primary and secondary keys.

  • The maximum length of the data area for an entry in the logical record cache.

  • The minimum number of unique cache entries the logical record cache will hold before it begins to reuse the least-referenced cache entries.

  • The number of seconds that a cache entry can reside in the local cache before it is cast out.

  • The type of cache (processor shared or processor unique).

Adding an Entry to a Logical Record Cache

To add an entry to a logical record cache, an application uses the updateCacheEntry function, passing the following as parameters:

  • The cache token for the logical record cache
  • The primary key and its length
  • The secondary key and its length
  • The pointer to the area that contains the entry data to be saved in the logical record cache
  • The length of the passed entry data
  • The number of seconds the entry can reside in the cache before it is flushed
  • An indicator to change the local cache only; that is, don't invalidate other processors.

Applications should use a serialization mechanism when adding an entry to a logical record cache.

Updating an Entry in a Logical Record Cache

To update an entry in a logical record cache, an application uses the updateCacheEntry function, passing the following as parameters:

  • The cache token for the logical record cache
  • The primary key and its length
  • The secondary key and its length
  • The pointer to the area that contains the entry data to be saved in the logical record cache
  • The length of the passed entry data
  • The number of seconds the entry can reside in the cache before it is flushed
  • An indicator to invalidate other processors.

Applications should use a serialization mechanism when updating an entry in a logical record cache.

Reading an Entry from a Logical Record Cache

To read an entry from a logical record cache, an application uses the readCacheEntry function, passing the following as parameters:

  • The cache token for the logical record cache
  • The primary key and its length
  • The secondary key and its length
  • The pointer to the area that is to be overlayed with the contents of the specified cache entry
  • The length of the area to hold the contents of the specified cache entry.

Deleting an Entry from a Logical Record Cache

To delete an entry from a logical record cache, an application uses the deleteCacheEntry function, passing the following as parameters:

  • The cache token for the logical record cache
  • The primary key and its length
  • The secondary key and its length.

Deleting an entry from a processor shared logical record cache causes the entry to be invalidated on all other processors in the complex.

Deleting a Logical Record Cache

To delete a logical record cache, an application uses the deleteCache function, passing the following parameter:

  • The cache token for the logical record cache.

Flushing a Logical Record Cache

To flush a logical record cache, an application uses the flushCache function, passing the following parameter:

  • The cache token for the logical record cache.

Coding Examples

The following code excerpt shows how to use the newCache function to create a processor shared logical record cache that uses a secondary key for its entries in addition to a primary key.

char      cache_name[CACHE_MAX_NAME_SIZE];
long      primeKeyLgh=NAME_MAX;      /* max lgh of path name */
long      secondaryKeyLgh=sizeof(ino_t);    /* INODE nbr lgh */
long      cacheSize = * (long *) &ecbptr()->ebw004;
long      dataLgh=sizeof(struct TPF_directory_entry);
long      castOutTime = TPF_FS_CACHE_TIMEOUT ;
char      typeOfCache=Cache_ProcS;     /* proc shared cache  */

strcpy(cache_name,TPF_FS_DIR_CACHE_NAME);
if (newCache(&cache_name,
          &contrl_ptr->icontrol_dcacheToken,
          primeKeyLgh,
          secondaryKeyLgh,
          dataLgh,
          cacheSize,
          castOutTime,
          &typeOfCache,
          NULL) != CACHE_SUCCESS)
   {
   ....error processing
   }

The following code excerpt shows how to use the readCacheEntry function to attempt to read an entry from a cache. If the entry is not found in the cache, the data is then read from the database and the entry is added to the cache using the updateCacheEntry function. The NULL used as the next to last parameter on the updateCacheEntry function call indicates that the entry will not be flushed from the cache. The NULL used as the last parameter on the updateCacheEntry function call indicates that the entry is not invalidated on the other processors in the complex.

long   primaryKeyLgh = strlen( tran->itran_response.itres_name );
long   secondaryKeyLgh = sizeof(ino_t);
struct TPF_directory_entry tde;
long   bufferSize= sizeof(struct TPF_directory_entry);
if  (readCacheEntry(&contrl_ptr->icontrol_dcacheToken,
            &tran->itran_response.itres_name,
            &primaryKeyLgh,
            &tran->itran_response.
                 itres_parent_inode.inode_ino,
            &secondaryKeyLgh,
            &bufferSize,
            &tde) != CACHE_SUCCESS)
{
....read directory from the database, it was not found in cache
    
/* Add the directory to the directory cache.                   */

updateCacheEntry(&contrl_ptr->icontrol_dcacheToken,
            &tran->itran_response.itres_name,
            &primaryKeyLgh,
            &tran->itran_response.
             itres_parent_inode.inode_ino,
            &secondaryKeyLgh,
            &bufferSize,
            &tde,                        
            NULL,                        
            NULL );                      
}

The following code excerpt shows how to use the updateCacheEntry function to update an entry in the cache after the data has been updated on the database. The NULL used as the next to last parameter on the updateCacheEntry function call indicates that the entry will not be flushed from the cache. The last parameter on the updateCacheEntry function call indicates that the entry is to be invalidated on the other processors in the complex since this processor updated the entry.

struct TPF_directory_entry new_tde =                             
       { TPF_FS_DIRECTORY_CURRENT_VERSION };                
const long dataLength = sizeof (new_tde);
const long primaryKeyLgh = strlen( link->ilink_file_name );
const long secondaryKeyLgh = sizeof(ino_t);
const char invalidate = Cache_Invalidate;

new_tde.TPF_directory_entry_ino =                        
   link->ilink_file_inode_ordinal;                      
new_tde.TPF_directory_entry_igen =                       
   link->ilink_file_inode->inode_igen;

...update the database

   updateCacheEntry(&contrl_ptr->icontrol_dcacheToken,
             link->ilink_file_name,
             &primaryKeyLgh,
             &link->ilink_parent_inode->inode_ino,
             &secondaryKeyLgh,
             &dataLength,
             &new_tde,                           
             NULL,                              
             &invalidate );

Using Processor Shared Logical Record Caches

Using processor shared logical record caches requires CF resources for TPF record locking to be established. You are not required to use CF record locking (through the ZMCFT MIGRATE functional message), but must set up one or more CFs for record locking before you can enable CFs for the synchronization of processor shared logical record caches. The following functional messages are used to establish the CF resources necessary for synchronization of processor shared logical record caches:

  • ZMCFT ADD cfname — This functional message must be entered on all processors to add the CF to each processor.

  • ZCFLK ADD cfname SIZE xxxx — This functional message is entered from one processor to add the CF to the locking configuration for all processors.

You enable CFs to be used for synchronization of processor shared logical record caches by entering the ZCACH CF ENABLE functional message. This functional message is entered from one processor and takes effect on all other active processors in the complex. If an inactive processor is brought into the complex later, you must enter this functional message again at that time.

Once this is done, applications can create and use processor shared logical record caches that will be synchronized across multiple loosely coupled processors. Additionally, any existing processor shared logical record caches will begin to be synchronized. Processor shared logical record caches behave like processor unique caches if CFs are not enabled for processor shared logical record cache synchronization. Therefore, processor shared logical record caches could be implemented with the understanding that the caches would not be synchronized. CF resources could then be introduced at a later date to enable the caches to be synchronized.

So How Are My Caches Doing ?

Logical record caches are established and used by applications as stated previously. Whether you are talking about processor shared or processor unique caches, they can be monitored for tuning purposes by using TPF Data Collection reports and by entering functional messages. The ZCACH DISPLAY functional message can be used to display attributes and count fields for the processor's local copies of the logical record caches, and the data collection TPF Logical Record Cache Summary report can be used to check on how your logical record caches are doing.

Similarly, the ZCFCH DISPLAY functional message can be used to display attributes and counts of CF-resident directory-only caches. The data collection Coupling Facility Caching Summary report should also be used for tuning CF-resident directory-only caches. Information such as castouts per second can be very helpful in determining if caching attributes need to be altered. As is always the case, tuning is very installation-specific. If you have additional questions about cache tuning, call your IBM TPF support representative.

If you want to modify cache attributes, you can enter the ZCACH MODIFY functional message. This functional message will establish a set of permanent override values that will be used by the TPF system whenever caches of the names specified are created. For the new attributes to take effect for caches that already exist, these caches must be deleted either by the application or by entering the ZCACH DELETE functional message. When these logical record caches are re-created, the new attributes will be used.

Similarly, if you want to modify CF-resident directory-only cache structure attributes, you can enter the ZCFCH MODIFY functional message. This functional message will establish a set of permanent override values that will be used by the TPF system whenever CF-resident directory-only caches of the names specified are created. For new attributes to be used on existing CF-resident directory-only cache structures, the associated processor shared logical record caches must be deleted on all processors by the application or by the ZCACH DELETE functional message. Deleting all the processor shared logical record caches that use the CF-resident directory-only cache structure will force the directory-only cache structure to be created with the new attributes the next time it is created.

Creating override values through the functional messages described previously can be used to try out or phase in new logical record cache or CF directory-only cache attributes. When the new attributes are verified, the associated applications can be updated to use these new attributes and the overrides can be deleted through a functional message.

Fourth Quarter 2000 - Table of Contents