#include <mplib1/dl_lru.h>The cache routines consist of six functions which provide the following functions
The normal program use would be to call the initialisation routine, then to call the setup routine to tell it what the name of the list will be, what fields it contains, and how many entries to have.
Then there would be multiple calls to the search routine, and probably a number of calls to the add routine when the search fails and the data was found by another method, and optionally a call to the notify routine if the data was not found externally.
After the program has performed its main job, the report routine can be called to give statistics on adds, hits & misses.
This can be best illustrated by the following pseudo-code.
inititalise the cache routines create the list required while user gives input search for required item in cache if not found in cache find item in database if found in database add to cache print details otherwise notify cache inform user otherwise print details (as returned by cache) end while print cache statistics
In fact slightly more variations are possible, but we shall examine these after looking at the actual functions in some detail.
int Cache_Init( int default_flags );This function should be called once at startup. The value supplied will be used to provide the defaults flags for Create_Cache_List where not included.
If any value other than CACHE_USE_DEFAULT is supplied it should have only one bit set per mask group. For example, in the cache mode group either CACHE_CACHE_ON or CACHE_STAT_ONLY should be supplied.
The groups and their members are:
Mode Group Cache or statistics CACHE_CACHE_ON Cache items CACHE_STAT_ONLY Statistics only Case Group Should key values distinguish between upper and lower case. CACHE_IGNORE_CASE Ignore case in key values CACHE_CHECK_CASE Check case in key values Allocate Group Should the list be pre-allocated. CACHE_PRE_ALLOCATE Preallocate space for items CACHE_DEMAND_ALLOC Allocate space for items on demand Miss Group Should complete miss value be stored. CACHE_MISS_IGNORE Ignore complete miss finds CACHE_MISS_CACHE Cache and return complete misses on a findReturn: 0 on failure, 1 on success.
int Create_Cache_List( const char *list_name, int max_items, int list_flags, int key_size, const char *format_string, const char *field_names );The list_name is a unique string to identify which chain to put the data on.
The cache_max size specifies the maximum number of items that will be created on the list before re-use occurs. If this is 0 then the list will expand until it either feels like it, or is unable to.
The list_flags specify how the cache should operate. If the supplied value does not have a bit set in a particular mask, the value will default to that provided to Cache_Init.
The key_size parameter if non-zero specifies the maximum length of the key. This is used when pre-allocating list items, and also allows for faster re-use when the cache is full.
The format_string list is a string, similar to that used as a format string in printf, which specifies the field types. The current formats supported are string, character, integer, double and varchar.
%d decimal integer %x hexadecimal integer %c character %f double %s string %S varcharThe string and varchar types may be preceded by a width specifier which if not present will default to 40.
The field_names parameter is a comma seperated list of fields, which will be used to identify the fields in the field type list.
e.g. "stn_id,stn_name,gwy_live_stn"This function should be called once for each type of data set that requires caching.
Return: 0 on failure, 1 on success.
int Add_Cache_Item( char *list_name, char *list_key, ... );This function should be called to add a single set of data items to a given cache list.
The list_name is the same string as specified in the Create_Cache_List call.
The list_key value is a unique string to identify this item in the list. It can usually be produced by performing an sprintf of the actual key fields.
The list key value is then followed by a list of pointers to the actual data fields. These data pointers should be in exactly the same order as the fields specified in the Create_Cache_List call, and should have the same number of fields.
Return: 0 on failure, 1 on success.
int Find_Cache_Item( const char *list_name, const char *list_key, const char *field_list, ... );This function should be called to search (and return data if found) a list for a given key value.
The list_name is the same string as specified in the Create_Cache_List call.
The list_key value is the unique string to identify a given item, generated in the same manner as would be done by the Add_Cache_Item call.
The field_list, is a comma separated list of fields to be returned. This list may contain any subset of the fields specified in field_names in the Create_Cache_List call.
The field list is followed by a list of pointers to the fields to filled in.
Return:
CACHE_COMPLETE_MISS if not in cache and not in external data source CACHE_MISSED if not in the cache CACHE_FOUND_ITEM if the item was found :-) CACHE_FOUND_MANY if more than one item with this key value was found.These values are in ascending sequence so that the return check can be coded as simply or a complex as desired.
int Cache_Complete_Miss( const char *list_name, const char *list_key );This function should be called when a given value being searched for, is not found either in the cache list (Find_Cache_Item) or in the external data source.
The list_name is the same string as specified in the Create_Cache_List call.
The list key value is the unique string to identify a given item, generated in the same manner as would be done by the Add_Cache_Item call.
Return: 0 on failure, 1 on success.
int Cache_Flush( const char *list_name );This function causes all stored values, together with all complete miss values to be freed.
The list_name is the same string as specified in the Create_Cache_List call.
Return: 0 on failure, 1 on success.
int Cache_Stats( FILE *file_handle, const char *list_name, int contents );This function provides details of the data sizes, and cache hit statistics.
The file_handle is that of the stream where the report output is are desired.
The list_name is that for which statistics are desired, or NULL if statistics are required for all lists.
Return: 0 on failure, 1 on success.
The return codes from Find_Cache_Item are so arranged in ascending order because it makes it possible to code the subsequent checking in a variety of ways, but allowing simple code to work as well. For example, the relevant section of the pseudo-code at the start of the document would normally be coded as follows;
rv=Find_Cache_Item( list_name, key_value, field_list, &rf1, &rf2 ); if ( rv <= CACHE_MISSED ) { rv = Database_Check( key_value, &rf1, &rf2 ); if ( rv == FOUND ) { Add_Cache_Item( list_name, key_value, &rf1, &rf2 ); /* display details .... */ }else { Cache_Complete_Miss( list_name, key_value ); /* inform user of error ... */ } } else { /* display details ... */ }But consider the case where the key value is one that will not be found either in the cache or the database, and that this value has been checked before. We would end up checking the cache and the database to gain the same result, whereas if the cache knows something about complete failures we can recode the above as follows;
rv=Find_Cache_Item( list_name, key_value, field_list, &rf1, &rf2 ); if ( rv <= CACHE_COMPLETE_MISS ) { Cache_Complete_Miss( list_name, key_value ); /* inform user of error ... */ } else if ( rv <= CACHE_MISSED ) { rv = Database_Check( key_value, &rf1, &rf2 ); if ( rv == FOUND ) { Add_Cache_Item( list_name, key_value, &rf1, &rf2 ); /* display details .... */ }else { Cache_Complete_Miss( list_name, key_value ); /* inform user of error ... */ } } else { /* display details ... */ }The only item that should seem strange is the call to Cache_Complete_Miss when Find_Cache_Item has just returned CACHE_COMPLETE_MISS. This is because there may be some other action required, or this code may be like the first example, in which case a complete miss would be recorded. Let's just call it consistency.
Because of the nature of caching, and the design of the code it should not be assumed that, just because an item has just been added that it will be found on an immediately following search. The following example contains this bad assumption.
Add_Cache_Item( list_name, key_value, &rf1, &rf2 ); /* fiddle with values of rf1 & rf2 for some reason */ Find_Cache_Item( list_name, key_value, field_list, &rf1, &rf2 ); /* use rf1, rf2, WRONG !!! */The Add_Cache_Item call may have failed, the list may not exist, or it may be running in statistics only mode.
Your code should include dl_lru.h, this file contains the function definitions for the cache routines, along with all the flag definitions.