diff options
author | Miles Bader <miles@gnu.org> | 1996-04-10 00:19:34 +0000 |
---|---|---|
committer | Miles Bader <miles@gnu.org> | 1996-04-10 00:19:34 +0000 |
commit | 45a873a8d2c464f5dd97229665d361fb88e4eff4 (patch) | |
tree | 79e30419438a769844d5434774e3c52ce263f3ba /libdiskfs | |
parent | 85eac8cdae0864ed204c4a01f429bbac6068f1df (diff) |
(diskfs_check_lookup_cache):
Correctly handle the case where the lookup returns DIR itself.
(diskfs_enter_lookup_cache, diskfs_purge_lookup_cache,
diskfs_check_lookup_cache):
Renamed from versions without `lookup_'.
(diskfs_check_cache): Declare I.
(struct lookup_cache, diskfs_enter_cache): Change NAMELEN field to LEN.
(_diskfs_purge_cache_deletion): Delete function.
Diffstat (limited to 'libdiskfs')
-rw-r--r-- | libdiskfs/name-cache.c | 186 |
1 files changed, 77 insertions, 109 deletions
diff --git a/libdiskfs/name-cache.c b/libdiskfs/name-cache.c index 38688777..ecb67e6d 100644 --- a/libdiskfs/name-cache.c +++ b/libdiskfs/name-cache.c @@ -25,26 +25,33 @@ /* Maximum number of names to cache at once */ #define MAXCACHE 256 -/* Current number of names cached */ -static int cache_cur; +/* Maximum length of file name we bother caching */ +#define CACHE_NAME_LEN 100 /* Cache entry */ struct lookup_cache { - struct lookup_cache *next, *prev; - - /* These do not hold references; special code exists to call - purge routines when the nodes lose refs. */ - struct node *dp; /* directory */ - struct node *np; /* node */ - - /* strlen of name member */ - size_t namelen; - char name[0]; + int dir_cache_id, node_cache_id; + + size_t len; /* strlen of name */ + + char name[CACHE_NAME_LEN]; }; -/* Cache itself */ -static struct lookup_cache *lookup_cache_head, *lookup_cache_tail; +/* The contents of the cache in no particular order */ +static struct lookup_cache lookup_cache[MAXCACHE]; + +/* A rotating buffer of cache entries, maintaining an LRU + ordering of lookup_cache. */ +static int cache_indexes[MAXCACHE]; + +/* The current live entries start at first_cache and run through to + last_cache. When the cache is full, first_cache == last_cache, + and these point at the lru element; lower indexes in cache_indexes + are successively less recently used. */ +static int first_cache, last_cache; + +static spin_lock_t cache_lock = SPIN_LOCK_INITIALIZER; /* Buffer to hold statistics */ static struct @@ -52,98 +59,51 @@ static struct long pos_hits; long neg_hits; long miss; + long fetch_errors; } statistics; /* Node NP has just been found in DIR with NAME. If NP is null, that means that this name has been confirmed as absent in the directory. */ void -diskfs_enter_cache (struct node *dir, struct node *np, char *name) +diskfs_enter_lookup_cache (struct node *dir, struct node *np, char *name) { - struct lookup_cache *lc, *tmp = 0; - size_t len = strlen (name) + 1; - - - lc = malloc (sizeof (struct lookup_cache) + len); - lc->dp = dir; - lc->np = np; - lc->namelen = len - 1; - bcopy (name, lc->name, len); - - spin_lock (&diskfs_node_refcnt_lock); - if (cache_cur == MAXCACHE) - { - /* Free the entry at the tail */ - tmp = lookup_cache_tail; - lookup_cache_tail = lookup_cache_tail->prev; - if (lookup_cache_tail) - lookup_cache_tail->next = 0; - else - lookup_cache_head = 0; - } - else - cache_cur++; + size_t len = strlen (name); + struct lookup_cache *lc; - /* Add the new entry at the front */ - lc->next = lookup_cache_head; - lc->prev = 0; - if (lc->next) - lc->next->prev = lc; - lookup_cache_head = lc; - if (!lc->next) - lookup_cache_tail = lc; + if (len > CACHE_NAME_LEN - 1) + return; + + spin_lock (&cache_lock); + + /* Take first_cache + 1 and fill it with the new entry */ + lc = &lookup_cache[cache_indexes[first_cache + 1]]; + lc->dir_cache_id = dir->cache_id; + lc->node_cache_id = np->cache_id; + lc->len = len; + strcpy (lc->name, name); - spin_unlock (&diskfs_node_refcnt_lock); + /* Increment first_cache, and possibly last_cache too. */ + if (last_cache == first_cache) + last_cache++; + first_cache++; - if (tmp) - free (tmp); + spin_unlock (&cache_lock); } /* Purge all references in the cache to NP as a node inside directory DP. */ void -diskfs_purge_cache (struct node *dp, struct node *np) -{ - struct lookup_cache *lc, *nxt; - - spin_lock (&diskfs_node_refcnt_lock); - for (lc = lookup_cache_head; lc; lc = nxt) - if (lc->np == np && lc->dp == dp) - { - if (lc->prev) - lc->prev->next = lc->next; - if (lc->next) - lc->next->prev = lc->prev; - nxt = lc->next; - if (lookup_cache_tail == lc) - lookup_cache_tail = lc->prev; - free (lc); - } - else - nxt = lc->next; - spin_unlock (&diskfs_node_refcnt_lock); -} - -/* Purge all references in the cache to NP, either as a node or as a - directory. diskfs_node_refcnt_lock must be held around this call. */ -void -_diskfs_purge_cache_deletion (struct node *np) +diskfs_purge_lookup_cache (struct node *dp, struct node *np) { - struct lookup_cache *lc, *nxt; + int i; - for (lc = lookup_cache_head; lc; lc = nxt) - if (lc->np == np || lc->dp == np) - { - if (lc->prev) - lc->prev->next = lc->next; - if (lc->next) - lc->next->prev = lc->prev; - nxt = lc->next; - if (lookup_cache_tail == lc) - lookup_cache_tail = lc->prev; - free (lc); - } - else - nxt = lc->next; + spin_lock (&cache_lock); + for (i = 0; i < MAXCACHE; i++) + if (lookup_cache[i].len + && lookup_cache[i].dir_cache_id == dp->cache_id + && lookup_cache[i].node_cache_id == np->cache_id) + lookup_cache[i].len = 0; + spin_unlock (&cache_lock); } /* Scan the cache looking for NAME inside DIR. If we don't know @@ -151,34 +111,42 @@ _diskfs_purge_cache_deletion (struct node *np) not exist, then return -1. Otherwise, return NP for the entry, with a newly allocated reference. */ struct node * -diskfs_check_cache (struct node *dir, char *name) +diskfs_check_lookup_cache (struct node *dir, char *name) { - struct lookup_cache *lc; + int i; size_t len = strlen (name); - - spin_lock (&diskfs_node_refcnt_lock); - for (lc = lookup_cache_head; lc; lc = lc->next) - if (lc->dp == dir - && lc->namelen == len - && lc->name[0] == name[0] - && !strcmp (lc->name, name)) + + spin_lock (&cache_lock); + + /* Maybe we really ought to look up in lru order...who knows. */ + + for (i = 0; i < MAXCACHE; i++) + if (lookup_cache[i].len == len + && lookup_cache[i].dir_cache_id == dir->cache_id + && lookup_cache[i].name[0] == name[0] + && !strcmp (lookup_cache[i].name, name)) { - if (lc->np) + int id = lookup_cache[i].node_cache_id; + + statistics.pos_hits++; + spin_unlock (&cache_lock); + + if (id == dir->cache_id) + /* The cached node is the same as DIR. */ { - lc->np->references++; - statistics.pos_hits++; - spin_unlock (&diskfs_node_refcnt_lock); - return lc->np; + diskfs_nref (dir); + return dir; } else { - statistics.neg_hits++; - spin_unlock (&diskfs_node_refcnt_lock); - return (struct node *) -1; + struct node *np; + error_t err = diskfs_cached_lookup (id, &np); + return err ? 0 : np; } } + statistics.miss++; - spin_unlock (&diskfs_node_refcnt_lock); + spin_unlock (&cache_lock); + return 0; } - |