summaryrefslogtreecommitdiff
path: root/libdiskfs
diff options
context:
space:
mode:
Diffstat (limited to 'libdiskfs')
-rw-r--r--libdiskfs/ChangeLog57
-rw-r--r--libdiskfs/lookup.c35
-rw-r--r--libdiskfs/name-cache.c112
3 files changed, 184 insertions, 20 deletions
diff --git a/libdiskfs/ChangeLog b/libdiskfs/ChangeLog
index 3ae2e004..a0d446e8 100644
--- a/libdiskfs/ChangeLog
+++ b/libdiskfs/ChangeLog
@@ -1,3 +1,60 @@
+Tue Sep 3 10:48:05 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (diskfs_enter_lookup_cache): Cache `.' and `..'
+ just like other nodes.
+ (diskfs_check_lookup_cache): If we get a cache hit on `..', then
+ do the inverse locking semantic, and only return success if things
+ are stable around the call.
+
+Fri Aug 30 21:57:18 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * lookup.c (cache_misses): New variable, to find out what sort of
+ thing all the cache misses are.
+ (cm_lock): New variable.
+ (diskfs_lookup): Keep track of cache misses in cache_misses.
+
+ * name-cache.c (MAXCACHE): 200 now. After experimentation, this
+ appears to be a pretty good value. Very little benefit after
+ this.
+
+Fri Aug 30 20:41:27 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (struct lookup_cache): Delete member `hits'.
+ New member `stati'.
+ (diskfs_enter_lookup_cache): Don't initialize C->hits.
+ (find_cache): Set C->stati before returning.
+ (build_partial): Delete function.
+ (diskfs_check_lookup_cache): Delete calls to build_partial.
+ Register all statistics through register_neg_hit,
+ register_pos_hit, and register_miss.
+ (MAXCACHE): 2000 now.
+
+Wed Aug 28 12:20:53 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (MAXCACHE): 500 for now.
+
+Mon Aug 26 15:10:55 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (MAXCACHE): Increase to 50000.
+ (struct lookup_cache): New member `hits'.
+ (statistics): Name struct type `struct stats'.
+ (diskfs_enter_lookup_cache): Initialize C->hits.
+ (PARTIAL_THRESH, NPARTIALS): New macros.
+ (partial_stats): New variable.
+ (build_partial): New function.
+ (diskfs_check_lookup_cache): Call build_partial after statistics
+ frobbing.
+
+ * name-cache.c (diskfs_check_lookup_cache): Increment members of
+ statistics while still holding CACHE_LOCK.
+
+Fri Aug 16 18:23:25 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (diskfs_check_lookup_cache): Keep track of negative
+ hits properly.
+ * lookup.c (diskfs_lookup): On LOOKUPs that fail to find the node,
+ enter a negative cache entry.
+
Thu Aug 15 16:07:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
* opts-version.c (diskfs_extra_version): New (weak) reference.
diff --git a/libdiskfs/lookup.c b/libdiskfs/lookup.c
index 40ce8937..282d829f 100644
--- a/libdiskfs/lookup.c
+++ b/libdiskfs/lookup.c
@@ -20,6 +20,17 @@
#include "priv.h"
+static struct
+{
+ int present;
+ int absent;
+ int errors;
+ int dot;
+ int dotdot;
+} cache_misses;
+static spin_lock_t cm_lock = SPIN_LOCK_INITIALIZER;
+
+
/* Lookup in directory DP (which is locked) the name NAME. TYPE will
either be LOOKUP, CREATE, RENAME, or REMOVE. CRED identifies the
user making the call.
@@ -71,7 +82,7 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
struct protid *cred)
{
error_t err;
-
+
if (type == REMOVE || type == RENAME)
assert (np);
@@ -119,6 +130,26 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
}
err = diskfs_lookup_hard (dp, name, type, np, ds, cred);
+
+ spin_lock (&cm_lock);
+ if (type == LOOKUP)
+ {
+ if (err == ENOENT)
+ cache_misses.absent++;
+ else if (err)
+ cache_misses.errors++;
+ else
+ cache_misses.present++;
+ if (name[0] == '.')
+ {
+ if (name[1] == '\0')
+ cache_misses.dot++;
+ else if (name[1] == '.' && name[2] == '\0')
+ cache_misses.dotdot++;
+ }
+ }
+ spin_unlock (&cm_lock);
+
if (err && err != ENOENT)
return err;
@@ -137,6 +168,8 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
if ((type == LOOKUP || type == CREATE) && !err && np)
diskfs_enter_lookup_cache (dp, *np, name);
+ else if (type == LOOKUP && err == ENOENT)
+ diskfs_enter_lookup_cache (dp, 0, name);
return err;
}
diff --git a/libdiskfs/name-cache.c b/libdiskfs/name-cache.c
index 2cf1ed8b..808c16f4 100644
--- a/libdiskfs/name-cache.c
+++ b/libdiskfs/name-cache.c
@@ -24,7 +24,7 @@
#include <cacheq.h>
/* Maximum number of names to cache at once */
-#define MAXCACHE 256
+#define MAXCACHE 200
/* Maximum length of file name we bother caching */
#define CACHE_NAME_LEN 100
@@ -44,7 +44,10 @@ struct lookup_cache
char name[CACHE_NAME_LEN];
/* Strlen of NAME. If this is zero, it's an unused entry. */
- size_t name_len;
+ size_t name_len;
+
+ /* XXX */
+ int stati;
};
/* The contents of the cache in no particular order */
@@ -53,13 +56,18 @@ static struct cacheq lookup_cache = { sizeof (struct lookup_cache) };
static spin_lock_t cache_lock = SPIN_LOCK_INITIALIZER;
/* Buffer to hold statistics */
-static struct
+static struct stats
{
long pos_hits;
long neg_hits;
long miss;
long fetch_errors;
} statistics;
+
+#define PARTIAL_THRESH 100
+#define NPARTIALS MAXCACHE / PARTIAL_THRESH
+struct stats partial_stats [NPARTIALS];
+
/* If there's an entry for NAME, of length NAME_LEN, in directory DIR in the
cache, return it's entry, otherwise 0. CACHE_LOCK must be held. */
@@ -67,15 +75,21 @@ static struct lookup_cache *
find_cache (struct node *dir, const char *name, size_t name_len)
{
struct lookup_cache *c;
+ int i;
/* Search the list. All unused entries are contiguous at the end of the
list, so we can stop searching when we see the first one. */
- for (c = lookup_cache.mru; c && c->name_len; c = c->hdr.next)
+ for (i = 0, c = lookup_cache.mru;
+ c && c->name_len;
+ c = c->hdr.next, i++)
if (c->name_len == name_len
&& c->dir_cache_id == dir->cache_id
&& c->name[0] == name[0] && strcmp (c->name, name) == 0)
- return c;
-
+ {
+ c->stati = i / 100;
+ return c;
+ }
+
return 0;
}
@@ -90,13 +104,6 @@ diskfs_enter_lookup_cache (struct node *dir, struct node *np, char *name)
if (name_len > CACHE_NAME_LEN - 1)
return;
- /* Never cache . or ..; it's too much trouble to get the locking
- order right. */
- if (name[0] == '.'
- && (name[1] == '\0'
- || (name[1] == '.' && name[2] == '\0')))
- return;
-
spin_lock (&cache_lock);
if (lookup_cache.length == 0)
@@ -145,6 +152,47 @@ diskfs_purge_lookup_cache (struct node *dp, struct node *np)
spin_unlock (&cache_lock);
}
+/* Register a negative hit for an entry in the Nth stat class */
+void
+register_neg_hit (int n)
+{
+ int i;
+
+ statistics.neg_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].neg_hits++;
+}
+
+/* Register a positive hit for an entry in the Nth stat class */
+void
+register_pos_hit (int n)
+{
+ int i;
+
+ statistics.pos_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].pos_hits++;
+}
+
+/* Register a miss */
+void
+register_miss ()
+{
+ int i;
+
+ statistics.miss++;
+ for (i = 0; i < NPARTIALS; i++)
+ partial_stats[i].miss++;
+}
+
+
+
/* Scan the cache looking for NAME inside DIR. If we don't know
anything entry at all, then return 0. If the entry is confirmed to
not exist, then return -1. Otherwise, return NP for the entry, with
@@ -163,15 +211,18 @@ diskfs_check_lookup_cache (struct node *dir, char *name)
cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */
- statistics.pos_hits++;
- spin_unlock (&cache_lock);
-
if (id == 0)
/* A negative cache entry. */
- return (struct node *)-1;
+ {
+ register_neg_hit (c->stati);
+ spin_unlock (&cache_lock);
+ return (struct node *)-1;
+ }
else if (id == dir->cache_id)
/* The cached node is the same as DIR. */
{
+ register_pos_hit (c->stati);
+ spin_unlock (&cache_lock);
diskfs_nref (dir);
return dir;
}
@@ -179,12 +230,35 @@ diskfs_check_lookup_cache (struct node *dir, char *name)
/* Just a normal entry in DIR; get the actual node. */
{
struct node *np;
- error_t err = diskfs_cached_lookup (id, &np);
+ error_t err;
+
+ register_pos_hit (c->stati);
+ spin_unlock (&cache_lock);
+
+ if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
+ {
+ mutex_unlock (&dir->lock);
+ err = diskfs_cached_lookup (id, &np);
+ mutex_lock (&dir->lock);
+
+ /* In the window where DP was unlocked, we might
+ have lost. So check the cache again, and see
+ if it's still there; if so, then we win. */
+ c = find_cache (dir, "..", 2);
+ if (!c || c->node_cache_id != id)
+ {
+ /* Lose */
+ mutex_unlock (&np->lock);
+ return 0;
+ }
+ }
+ else
+ err = diskfs_cached_lookup (id, &np);
return err ? 0 : np;
}
}
- statistics.miss++;
+ register_miss ();
spin_unlock (&cache_lock);
return 0;