From f427d4ce65659419c8989d87acd97d00b4db41e6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 18 Dec 2007 09:41:03 +0100 Subject: Add a in-memory cache This is a more general API that caches data with a LRU scheme. See include/cache.h. No comments yet, I'm still working on it. But Jeremy has given me a hint in one of his checkins that he would like to make use of this now. The idea is that we get rid of all our silly little caches and merge them all into one cache that we can then very easily trim, for example even with a smbcontrol message if someone decides memory is tight. The main user is the stat cache, this patch also converts the getwd cache. More caches to come. (This used to be commit 7a911b35713538d82001a3c9f34152e293fe1943) --- source3/smbd/vfs.c | 168 ++++++++++++++++++----------------------------------- 1 file changed, 57 insertions(+), 111 deletions(-) (limited to 'source3/smbd/vfs.c') diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 628d2eec4b..45d0788117 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -731,152 +731,98 @@ int vfs_ChDir(connection_struct *conn, const char *path) return(res); } -/* number of list structures for a caching GetWd function. */ -#define MAX_GETWDCACHE (50) - -static struct { - SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ - SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ - char *path; /* The pathname. */ - bool valid; -} ino_list[MAX_GETWDCACHE]; - -extern bool use_getwd_cache; - -/**************************************************************************** - Prompte a ptr (to make it recently used) -****************************************************************************/ - -static void array_promote(char *array,int elsize,int element) -{ - char *p; - if (element == 0) - return; - - p = (char *)SMB_MALLOC(elsize); - - if (!p) { - DEBUG(5,("array_promote: malloc fail\n")); - return; - } - - memcpy(p,array + element * elsize, elsize); - memmove(array + elsize,array,elsize*element); - memcpy(array,p,elsize); - SAFE_FREE(p); -} - /******************************************************************* Return the absolute current directory path - given a UNIX pathname. Note that this path is returned in DOS format, not UNIX format. Note this can be called with conn == NULL. ********************************************************************/ +struct getwd_cache_key { + SMB_DEV_T dev; + SMB_INO_T ino; +}; + char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) { char s[PATH_MAX+1]; - static bool getwd_cache_init = False; SMB_STRUCT_STAT st, st2; - int i; - char *ret = NULL; + char *result; + DATA_BLOB cache_value; + struct getwd_cache_key key; *s = 0; - if (!use_getwd_cache) { - nocache: - ret = SMB_VFS_GETWD(conn,s); - if (!ret) { - DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, " - "errno %s\n",strerror(errno))); - return NULL; - } - return talloc_strdup(ctx, ret); - } - - /* init the cache */ - if (!getwd_cache_init) { - getwd_cache_init = True; - for (i=0;i 0) + && (cache_value.data[cache_value.length-1] == '\0')); - /* promote it for future use */ - array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); - if (ret == NULL) { - errno = ENOMEM; - } - return ret; - } else { - /* If the inode is different then something's changed, - scrub the entry and start from scratch. */ - ino_list[i].valid = False; - } - } - } + if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0) + && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino) + && (S_ISDIR(st.st_mode))) { + /* + * Ok, we're done + */ + result = talloc_strdup(ctx, (char *)cache_value.data); + if (result == NULL) { + errno = ENOMEM; } + return result; } - /* We don't have the information to hand so rely on traditional - * methods. The very slow getcwd, which spawns a process on some - * systems, or the not quite so bad getwd. */ + nocache: + + /* + * We don't have the information to hand so rely on traditional + * methods. The very slow getcwd, which spawns a process on some + * systems, or the not quite so bad getwd. + */ if (!SMB_VFS_GETWD(conn,s)) { - DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n", - strerror(errno))); - return (NULL); + DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n", + strerror(errno))); + return NULL; } - ret = talloc_strdup(ctx,s); - - DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n", - s,(double)st.st_ino,(double)st.st_dev)); - - /* add it to the cache */ - i = MAX_GETWDCACHE - 1; - string_set(&ino_list[i].path,s); - ino_list[i].dev = st.st_dev; - ino_list[i].inode = st.st_ino; - ino_list[i].valid = True; + if (lp_getwd_cache() && VALID_STAT(st)) { + ZERO_STRUCT(key); /* unlikely, but possible padding */ + key.dev = st.st_dev; + key.ino = st.st_ino; - /* put it at the top of the list */ - array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); + memcache_add(smbd_memcache(), GETWD_CACHE, + data_blob_const(&key, sizeof(key)), + data_blob_const(s, strlen(s)+1)); + } - if (ret == NULL) { + result = talloc_strdup(ctx, s); + if (result == NULL) { errno = ENOMEM; } - return ret; + return result; } /******************************************************************* -- cgit