diff options
Diffstat (limited to 'source/ubiqx/ubi_Cache.c')
-rw-r--r-- | source/ubiqx/ubi_Cache.c | 505 |
1 files changed, 0 insertions, 505 deletions
diff --git a/source/ubiqx/ubi_Cache.c b/source/ubiqx/ubi_Cache.c deleted file mode 100644 index f428dcefe97..00000000000 --- a/source/ubiqx/ubi_Cache.c +++ /dev/null @@ -1,505 +0,0 @@ -/* ========================================================================== ** - * ubi_Cache.c - * - * Copyright (C) 1997 by Christopher R. Hertel - * - * Email: crh@ubiqx.mn.org - * -------------------------------------------------------------------------- ** - * - * This module implements a generic cache. - * - * -------------------------------------------------------------------------- ** - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * -------------------------------------------------------------------------- ** - * - * This module uses a splay tree to implement a simple cache. The cache - * module adds a thin layer of functionality to the splay tree. In - * particular: - * - * - The tree (cache) may be limited in size by the number of - * entries permitted or the amount of memory used. When either - * limit is exceeded cache entries are removed until the cache - * conforms. - * - Some statistical information is kept so that an approximate - * "hit ratio" can be calculated. - * - There are several functions available that provide access to - * and management of cache size limits, hit ratio, and tree - * trimming. - * - * The splay tree is used because recently accessed items tend toward the - * top of the tree and less recently accessed items tend toward the bottom. - * This makes it easy to purge less recently used items should the cache - * exceed its limits. - * - * To use this module, you will need to supply a comparison function of - * type ubi_trCompFunc and a node-freeing function of type - * ubi_trKillNodeRtn. See ubi_BinTree.h for more information on - * these. (This is all basic ubiqx tree management stuff.) - * - * Notes: - * - * - Cache performance will start to suffer dramatically if the - * cache becomes large enough to force the OS to start swapping - * memory to disk. This is because the nodes of the underlying tree - * will be scattered across memory in an order that is completely - * unrelated to their traversal order. As more and more of the - * cache is placed into swap space, more and more swaps will be - * required for a simple traversal (...and then there's the splay - * operation). - * - * In one simple test under Linux, the load and dump of a cache of - * 400,000 entries took only 1min, 40sec of real time. The same - * test with 450,000 records took 2 *hours* and eight minutes. - * - * - In an effort to save memory, I considered using an unsigned - * short to save the per-entry entry size. I would have tucked this - * value into some unused space in the tree node structure. On - * 32-bit word aligned systems this would have saved an additional - * four bytes per entry. I may revisit this issue, but for now I've - * decided against it. - * - * Using an unsigned short would limit the size of an entry to 64K - * bytes. That's probably more than enough for most applications. - * The key word in that last sentence, however, is "probably". I - * really dislike imposing such limits on things. - * - * - Each entry keeps track of the amount of memory it used and the - * cache header keeps the total. This information is provided via - * the EntrySize parameter in ubi_cachePut(), so it is up to you to - * make sure that the numbers are accurate. (The numbers don't even - * have to represent bytes used.) - * - * As you consider this, note that the strdup() function--as an - * example--will call malloc(). The latter generally allocates a - * multiple of the system word size, which may be more than the - * number of bytes needed to store the string. - * - * -------------------------------------------------------------------------- ** - * - * Log: ubi_Cache.c,v - * Revision 0.4 1999/09/22 03:42:24 crh - * Fixed a minor typo. - * - * Revision 0.3 1998/06/03 18:00:15 crh - * Further fiddling with sys_include.h, which is no longer explicitly - * included by this module since it is inherited from ubi_BinTree.h. - * - * Revision 0.2 1998/06/02 01:36:18 crh - * Changed include name from ubi_null.h to sys_include.h to make it - * more generic. - * - * Revision 0.1 1998/05/20 04:36:02 crh - * The C file now includes ubi_null.h. See ubi_null.h for more info. - * - * Revision 0.0 1997/12/18 06:24:33 crh - * Initial Revision. - * - * ========================================================================== ** - */ - -#include "ubi_Cache.h" /* Header for *this* module. */ - -/* -------------------------------------------------------------------------- ** - * Static data... - */ - -/* commented out until I make use of it... -static char ModuleID[] = -"ubi_Cache\n\ -\tRevision: 0.4 \n\ -\tDate: 1999/09/22 03:42:24 \n\ -\tAuthor: crh \n"; -*/ - -/* -------------------------------------------------------------------------- ** - * Internal functions... - */ - -static void free_entry( ubi_cacheRootPtr CachePtr, ubi_cacheEntryPtr EntryPtr ) - /* ------------------------------------------------------------------------ ** - * Free a ubi_cacheEntry, and adjust the mem_used counter accordingly. - * - * Input: CachePtr - A pointer to the cache from which the entry has - * been removed. - * EntryPtr - A pointer to the already removed entry. - * - * Output: none. - * - * Notes: The entry must be removed from the cache *before* this function - * is called!!!! - * ------------------------------------------------------------------------ ** - */ - { - CachePtr->mem_used -= EntryPtr->entry_size; - (*CachePtr->free_func)( (void *)EntryPtr ); - } /* free_entry */ - -static void cachetrim( ubi_cacheRootPtr crptr ) - /* ------------------------------------------------------------------------ ** - * Remove entries from the cache until the number of entries and the amount - * of memory used are *both* below or at the maximum. - * - * Input: crptr - pointer to the cache to be trimmed. - * - * Output: None. - * - * ------------------------------------------------------------------------ ** - */ - { - while( ( crptr->max_entries && (crptr->max_entries < crptr->root.count) ) - || ( crptr->max_memory && (crptr->max_memory < crptr->mem_used) ) ) - { - if( !ubi_cacheReduce( crptr, 1 ) ) - return; - } - } /* cachetrim */ - - -/* -------------------------------------------------------------------------- ** - * Exported functions... - */ - -ubi_cacheRootPtr ubi_cacheInit( ubi_cacheRootPtr CachePtr, - ubi_trCompFunc CompFunc, - ubi_trKillNodeRtn FreeFunc, - unsigned long MaxEntries, - unsigned long MaxMemory ) - /* ------------------------------------------------------------------------ ** - * Initialize a cache header structure. - * - * Input: CachePtr - A pointer to a ubi_cacheRoot structure that is - * to be initialized. - * CompFunc - A pointer to the function that will be called - * to compare two cache values. See the module - * comments, above, for more information. - * FreeFunc - A pointer to a function that will be called - * to free a cache entry. If you allocated - * the cache entry using malloc(), then this - * will likely be free(). If you are allocating - * cache entries from a free list, then this will - * likely be a function that returns memory to the - * free list, etc. - * MaxEntries - The maximum number of entries that will be - * allowed to exist in the cache. If this limit - * is exceeded, then existing entries will be - * removed from the cache. A value of zero - * indicates that there is no limit on the number - * of cache entries. See ubi_cachePut(). - * MaxMemory - The maximum amount of memory, in bytes, to be - * allocated to the cache (excluding the cache - * header). If this is exceeded, existing entries - * in the cache will be removed until enough memory - * has been freed to meet the condition. See - * ubi_cachePut(). - * - * Output: A pointer to the initialized cache (i.e., the same as CachePtr). - * - * Notes: Both MaxEntries and MaxMemory may be changed after the cache - * has been created. See - * ubi_cacheSetMaxEntries() - * ubi_cacheSetMaxMemory() - * ubi_cacheGetMaxEntries() - * ubi_cacheGetMaxMemory() (the latter two are macros). - * - * - Memory is allocated in multiples of the word size. The - * return value of the strlen() function does not reflect - * this; it will allways be less than or equal to the amount - * of memory actually allocated. Keep this in mind when - * choosing a value for MaxMemory. - * - * ------------------------------------------------------------------------ ** - */ - { - if( CachePtr ) - { - (void)ubi_trInitTree( CachePtr, CompFunc, ubi_trOVERWRITE ); - CachePtr->free_func = FreeFunc; - CachePtr->max_entries = MaxEntries; - CachePtr->max_memory = MaxMemory; - CachePtr->mem_used = 0; - CachePtr->cache_hits = 0; - CachePtr->cache_trys = 0; - } - return( CachePtr ); - } /* ubi_cacheInit */ - -ubi_cacheRootPtr ubi_cacheClear( ubi_cacheRootPtr CachePtr ) - /* ------------------------------------------------------------------------ ** - * Remove and free all entries in an existing cache. - * - * Input: CachePtr - A pointer to the cache that is to be cleared. - * - * Output: A pointer to the cache header (i.e., the same as CachePtr). - * This function re-initializes the cache header. - * - * ------------------------------------------------------------------------ ** - */ - { - if( CachePtr ) - { - (void)ubi_trKillTree( CachePtr, CachePtr->free_func ); - CachePtr->mem_used = 0; - CachePtr->cache_hits = 0; - CachePtr->cache_trys = 0; - } - return( CachePtr ); - } /* ubi_cacheClear */ - -void ubi_cachePut( ubi_cacheRootPtr CachePtr, - unsigned long EntrySize, - ubi_cacheEntryPtr EntryPtr, - ubi_trItemPtr Key ) - /* ------------------------------------------------------------------------ ** - * Add an entry to the cache. - * - * Input: CachePtr - A pointer to the cache into which the entry - * will be added. - * EntrySize - The size, in bytes, of the memory block indicated - * by EntryPtr. This will be copied into the - * EntryPtr->entry_size field. - * EntryPtr - A pointer to a memory block that begins with a - * ubi_cacheEntry structure. The entry structure - * should be followed immediately by the data to be - * cached (even if that is a pointer to yet more data). - * Key - Pointer used to identify the lookup key within the - * Entry. - * - * Output: None. - * - * Notes: After adding the new node, the cache is "trimmed". This - * removes extra nodes if the tree has exceeded it's memory or - * entry count limits. It is unlikely that the newly added node - * will be purged from the cache (assuming a reasonably large - * cache), since new nodes in a splay tree (which is what this - * module was designed to use) are moved to the top of the tree - * and the cache purge process removes nodes from the bottom of - * the tree. - * - The underlying splay tree is opened in OVERWRITE mode. If - * the input key matches an existing key, the existing entry will - * be politely removed from the tree and freed. - * - Memory is allocated in multiples of the word size. The - * return value of the strlen() function does not reflect - * this; it will allways be less than or equal to the amount - * of memory actually allocated. - * - * ------------------------------------------------------------------------ ** - */ - { - ubi_trNodePtr OldNode; - - EntryPtr->entry_size = EntrySize; - CachePtr->mem_used += EntrySize; - (void)ubi_trInsert( CachePtr, EntryPtr, Key, &OldNode ); - if( OldNode ) - free_entry( CachePtr, (ubi_cacheEntryPtr)OldNode ); - - cachetrim( CachePtr ); - } /* ubi_cachePut */ - -ubi_cacheEntryPtr ubi_cacheGet( ubi_cacheRootPtr CachePtr, - ubi_trItemPtr FindMe ) - /* ------------------------------------------------------------------------ ** - * Attempt to retrieve an entry from the cache. - * - * Input: CachePtr - A ponter to the cache that is to be searched. - * FindMe - A ubi_trItemPtr that indicates the key for which - * to search. - * - * Output: A pointer to the cache entry that was found, or NULL if no - * matching entry was found. - * - * Notes: This function also updates the hit ratio counters. - * The counters are unsigned short. If the number of cache tries - * reaches 32768, then both the number of tries and the number of - * hits are divided by two. This prevents the counters from - * overflowing. See the comments in ubi_cacheHitRatio() for - * additional notes. - * - * ------------------------------------------------------------------------ ** - */ - { - ubi_trNodePtr FoundPtr; - - FoundPtr = ubi_trFind( CachePtr, FindMe ); - - if( FoundPtr ) - CachePtr->cache_hits++; - CachePtr->cache_trys++; - - if( CachePtr->cache_trys & 0x8000 ) - { - CachePtr->cache_hits = CachePtr->cache_hits / 2; - CachePtr->cache_trys = CachePtr->cache_trys / 2; - } - - return( (ubi_cacheEntryPtr)FoundPtr ); - } /* ubi_cacheGet */ - -ubi_trBool ubi_cacheDelete( ubi_cacheRootPtr CachePtr, ubi_trItemPtr DeleteMe ) - /* ------------------------------------------------------------------------ ** - * Find and delete the specified cache entry. - * - * Input: CachePtr - A pointer to the cache. - * DeleteMe - The key of the entry to be deleted. - * - * Output: TRUE if the entry was found & freed, else FALSE. - * - * ------------------------------------------------------------------------ ** - */ - { - ubi_trNodePtr FoundPtr; - - FoundPtr = ubi_trFind( CachePtr, DeleteMe ); - if( FoundPtr ) - { - (void)ubi_trRemove( CachePtr, FoundPtr ); - free_entry( CachePtr, (ubi_cacheEntryPtr)FoundPtr ); - return( ubi_trTRUE ); - } - return( ubi_trFALSE ); - } /* ubi_cacheDelete */ - -ubi_trBool ubi_cacheReduce( ubi_cacheRootPtr CachePtr, unsigned long count ) - /* ------------------------------------------------------------------------ ** - * Remove <count> entries from the bottom of the cache. - * - * Input: CachePtr - A pointer to the cache which is to be reduced in - * size. - * count - The number of entries to remove. - * - * Output: The function will return TRUE if <count> entries were removed, - * else FALSE. A return value of FALSE should indicate that - * there were less than <count> entries in the cache, and that the - * cache is now empty. - * - * Notes: This function forces a reduction in the number of cache entries - * without requiring that the MaxMemory or MaxEntries values be - * changed. - * - * ------------------------------------------------------------------------ ** - */ - { - ubi_trNodePtr NodePtr; - - while( count ) - { - NodePtr = ubi_trLeafNode( CachePtr->root.root ); - if( NULL == NodePtr ) - return( ubi_trFALSE ); - else - { - (void)ubi_trRemove( CachePtr, NodePtr ); - free_entry( CachePtr, (ubi_cacheEntryPtr)NodePtr ); - } - count--; - } - return( ubi_trTRUE ); - } /* ubi_cacheReduce */ - -unsigned long ubi_cacheSetMaxEntries( ubi_cacheRootPtr CachePtr, - unsigned long NewSize ) - /* ------------------------------------------------------------------------ ** - * Change the maximum number of entries allowed to exist in the cache. - * - * Input: CachePtr - A pointer to the cache to be modified. - * NewSize - The new maximum number of cache entries. - * - * Output: The maximum number of entries previously allowed to exist in - * the cache. - * - * Notes: If the new size is less than the old size, this function will - * trim the cache (remove excess entries). - * - A value of zero indicates an unlimited number of entries. - * - * ------------------------------------------------------------------------ ** - */ - { - unsigned long oldsize = CachePtr->max_entries; /* Save the old value. */ - - CachePtr->max_entries = NewSize; /* Apply the new value. */ - if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */ - cachetrim( CachePtr ); /* remove excess. */ - return( oldsize ); - } /* ubi_cacheSetMaxEntries */ - -unsigned long ubi_cacheSetMaxMemory( ubi_cacheRootPtr CachePtr, - unsigned long NewSize ) - /* ------------------------------------------------------------------------ ** - * Change the maximum amount of memory to be used for storing cache - * entries. - * - * Input: CachePtr - A pointer to the cache to be modified. - * NewSize - The new cache memory size. - * - * Output: The previous maximum memory size. - * - * Notes: If the new size is less than the old size, this function will - * trim the cache (remove excess entries). - * - A value of zero indicates that the cache has no memory limit. - * - * ------------------------------------------------------------------------ ** - */ - { - unsigned long oldsize = CachePtr->max_memory; /* Save the old value. */ - - CachePtr->max_memory = NewSize; /* Apply the new value. */ - if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */ - cachetrim( CachePtr ); /* remove excess. */ - return( oldsize ); - } /* ubi_cacheSetMaxMemory */ - -int ubi_cacheHitRatio( ubi_cacheRootPtr CachePtr ) - /* ------------------------------------------------------------------------ ** - * Returns a value that is 10,000 times the slightly weighted average hit - * ratio for the cache. - * - * Input: CachePtr - Pointer to the cache to be queried. - * - * Output: An integer that is 10,000 times the number of successful - * cache hits divided by the number of cache lookups, or: - * (10000 * hits) / trys - * You can easily convert this to a float, or do something - * like this (where i is the return value of this function): - * - * printf( "Hit rate : %d.%02d%%\n", (i/100), (i%100) ); - * - * Notes: I say "slightly-weighted", because the numerator and - * denominator are both accumulated in locations of type - * 'unsigned short'. If the number of cache trys becomes - * large enough, both are divided by two. (See function - * ubi_cacheGet().) - * Dividing both numerator and denominator by two does not - * change the ratio (much...it is an integer divide), but it - * does mean that subsequent increments to either counter will - * have twice as much significance as previous ones. - * - * - The value returned by this function will be in the range - * [0..10000] because ( 0 <= cache_hits <= cache_trys ) will - * always be true. - * - * ------------------------------------------------------------------------ ** - */ - { - int tmp = 0; - - if( CachePtr->cache_trys ) - tmp = (int)( (10000 * (long)(CachePtr->cache_hits) ) - / (long)(CachePtr->cache_trys) ); - return( tmp ); - } /* ubi_cacheHitRatio */ - -/* -------------------------------------------------------------------------- */ |