summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2007-12-18 09:41:03 +0100
committerVolker Lendecke <vl@samba.org>2007-12-18 09:56:04 +0100
commitf427d4ce65659419c8989d87acd97d00b4db41e6 (patch)
tree382dce7bf0150c284b84d822e3d1c8c037fb0281 /source3/smbd
parent68e65b29815f1f9bbe7384e07fc341f6c8f2f605 (diff)
downloadsamba-f427d4ce65659419c8989d87acd97d00b4db41e6.tar.gz
samba-f427d4ce65659419c8989d87acd97d00b4db41e6.tar.bz2
samba-f427d4ce65659419c8989d87acd97d00b4db41e6.zip
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)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/mangle_hash2.c67
-rw-r--r--source3/smbd/server.c13
-rw-r--r--source3/smbd/statcache.c64
-rw-r--r--source3/smbd/vfs.c168
4 files changed, 112 insertions, 200 deletions
diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c
index 7066c2a4e5..9643506aea 100644
--- a/source3/smbd/mangle_hash2.c
+++ b/source3/smbd/mangle_hash2.c
@@ -93,15 +93,6 @@ static unsigned char char_flags[256];
*/
static unsigned mangle_prefix;
-/* we will use a very simple direct mapped prefix cache. The big
- advantage of this cache structure is speed and low memory usage
-
- The cache is indexed by the low-order bits of the hash, and confirmed by
- hashing the resulting cache entry to match the known hash
-*/
-static char **prefix_cache;
-static unsigned int *prefix_cache_hashes;
-
/* these are the characters we use in the 8.3 hash. Must be 36 chars long */
static const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static unsigned char base_reverse[256];
@@ -147,57 +138,39 @@ static unsigned int mangle_hash(const char *key, unsigned int length)
return value & ~0x80000000;
}
-/*
- initialise (ie. allocate) the prefix cache
- */
-static bool cache_init(void)
-{
- if (prefix_cache) {
- return True;
- }
-
- prefix_cache = SMB_CALLOC_ARRAY(char *,MANGLE_CACHE_SIZE);
- if (!prefix_cache) {
- return False;
- }
-
- prefix_cache_hashes = SMB_CALLOC_ARRAY(unsigned int, MANGLE_CACHE_SIZE);
- if (!prefix_cache_hashes) {
- SAFE_FREE(prefix_cache);
- return False;
- }
-
- return True;
-}
-
/*
insert an entry into the prefix cache. The string might not be null
terminated */
static void cache_insert(const char *prefix, int length, unsigned int hash)
{
- int i = hash % MANGLE_CACHE_SIZE;
+ char *str = SMB_STRNDUP(prefix, length);
- if (prefix_cache[i]) {
- free(prefix_cache[i]);
+ if (str == NULL) {
+ return;
}
- prefix_cache[i] = SMB_STRNDUP(prefix, length);
- prefix_cache_hashes[i] = hash;
+ memcache_add(smbd_memcache(), MANGLE_HASH2_CACHE,
+ data_blob_const(&hash, sizeof(hash)),
+ data_blob_const(str, length+1));
+ SAFE_FREE(str);
}
/*
lookup an entry in the prefix cache. Return NULL if not found.
*/
-static const char *cache_lookup(unsigned int hash)
+static char *cache_lookup(TALLOC_CTX *mem_ctx, unsigned int hash)
{
- int i = hash % MANGLE_CACHE_SIZE;
+ DATA_BLOB value;
- if (!prefix_cache[i] || hash != prefix_cache_hashes[i]) {
+ if (!memcache_lookup(smbd_memcache(), MANGLE_HASH2_CACHE,
+ data_blob_const(&hash, sizeof(hash)), &value)) {
return NULL;
}
- /* yep, it matched */
- return prefix_cache[i];
+ SMB_ASSERT((value.length > 0)
+ && (value.data[value.length-1] == '\0'));
+
+ return talloc_strdup(mem_ctx, (char *)value.data);
}
@@ -377,7 +350,7 @@ static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
{
unsigned int hash, multiplier;
unsigned int i;
- const char *prefix;
+ char *prefix;
char extension[4];
*pp_out = NULL;
@@ -397,7 +370,7 @@ static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
}
/* now look in the prefix cache for that hash */
- prefix = cache_lookup(hash);
+ prefix = cache_lookup(ctx, hash);
if (!prefix) {
M_DEBUG(10,("lookup_name_from_8_3: %s -> %08X -> not found\n",
name, hash));
@@ -421,6 +394,8 @@ static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
*pp_out = talloc_strdup(ctx, prefix);
}
+ TALLOC_FREE(prefix);
+
if (!pp_out) {
M_DEBUG(0,("talloc_fail"));
return False;
@@ -728,10 +703,6 @@ struct mangle_fns *mangle_hash2_init(void)
init_tables();
mangle_reset();
- if (!cache_init()) {
- return NULL;
- }
-
return &mangle_fns;
}
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 41d036a8b9..574197d711 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -86,6 +86,19 @@ struct messaging_context *smbd_messaging_context(void)
return ctx;
}
+struct memcache *smbd_memcache(void)
+{
+ static struct memcache *cache;
+
+ if (!cache
+ && !(cache = memcache_init(NULL,
+ lp_max_stat_cache_size()*1024))) {
+
+ smb_panic("Could not init smbd memcache");
+ }
+ return cache;
+}
+
/*******************************************************************
What to do when smb.conf is updated.
********************************************************************/
diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c
index 8f1e008985..72fed008a2 100644
--- a/source3/smbd/statcache.c
+++ b/source3/smbd/statcache.c
@@ -26,8 +26,6 @@
Stat cache code used in unix_convert.
*****************************************************************************/
-static TDB_CONTEXT *tdb_stat_cache;
-
/**
* Add an entry into the stat cache.
*
@@ -45,10 +43,8 @@ void stat_cache_add( const char *full_orig_name,
bool case_sensitive)
{
size_t translated_path_length;
- TDB_DATA data_val;
char *original_path;
size_t original_path_length;
- size_t sc_size = lp_max_stat_cache_size();
char saved_char;
TALLOC_CTX *ctx = talloc_tos();
@@ -56,12 +52,6 @@ void stat_cache_add( const char *full_orig_name,
return;
}
- if (sc_size && (tdb_map_size(tdb_stat_cache) > sc_size*1024)) {
- reset_stat_cache();
- }
-
- ZERO_STRUCT(data_val);
-
/*
* Don't cache trivial valid directory entries such as . and ..
*/
@@ -132,24 +122,20 @@ void stat_cache_add( const char *full_orig_name,
saved_char = translated_path[translated_path_length];
translated_path[translated_path_length] = '\0';
- data_val.dsize = translated_path_length + 1;
- data_val.dptr = (uint8 *)translated_path;
-
/*
* New entry or replace old entry.
*/
- if (tdb_store_bystring(tdb_stat_cache, original_path, data_val,
- TDB_REPLACE) != 0) {
- DEBUG(0,("stat_cache_add: Error storing entry %s -> %s\n",
- original_path, translated_path));
- } else {
- DEBUG(5,("stat_cache_add: Added entry (%lx:size%x) %s -> %s\n",
- (unsigned long)data_val.dptr,
- (unsigned int)data_val.dsize,
- original_path,
- translated_path));
- }
+ memcache_add(
+ smbd_memcache(), STAT_CACHE,
+ data_blob_const(original_path, original_path_length),
+ data_blob_const(translated_path, translated_path_length + 1));
+
+ DEBUG(5,("stat_cache_add: Added entry (%lx:size %x) %s -> %s\n",
+ (unsigned long)translated_path,
+ (unsigned int)translated_path_length,
+ original_path,
+ translated_path));
translated_path[translated_path_length] = saved_char;
TALLOC_FREE(original_path);
@@ -186,7 +172,7 @@ bool stat_cache_lookup(connection_struct *conn,
unsigned int num_components = 0;
char *translated_path;
size_t translated_path_length;
- TDB_DATA data_val;
+ DATA_BLOB data_val;
char *name;
TALLOC_CTX *ctx = talloc_tos();
@@ -236,9 +222,12 @@ bool stat_cache_lookup(connection_struct *conn,
while (1) {
char *sp;
- data_val = tdb_fetch_bystring(tdb_stat_cache, chk_name);
+ data_val = data_blob_null;
- if (data_val.dptr != NULL && data_val.dsize != 0) {
+ if (memcache_lookup(
+ smbd_memcache(), STAT_CACHE,
+ data_blob_const(chk_name, strlen(chk_name)),
+ &data_val)) {
break;
}
@@ -275,12 +264,11 @@ bool stat_cache_lookup(connection_struct *conn,
}
}
- translated_path = talloc_strdup(ctx,(char *)data_val.dptr);
+ translated_path = talloc_strdup(ctx,(char *)data_val.data);
if (!translated_path) {
smb_panic("talloc failed");
}
- translated_path_length = data_val.dsize - 1;
- SAFE_FREE(data_val.dptr);
+ translated_path_length = data_val.length - 1;
DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] "
"-> [%s]\n", chk_name, translated_path ));
@@ -288,7 +276,8 @@ bool stat_cache_lookup(connection_struct *conn,
if (SMB_VFS_STAT(conn, translated_path, pst) != 0) {
/* Discard this entry - it doesn't exist in the filesystem. */
- tdb_delete_bystring(tdb_stat_cache, chk_name);
+ memcache_delete(smbd_memcache(), STAT_CACHE,
+ data_blob_const(chk_name, strlen(chk_name)));
TALLOC_FREE(chk_name);
TALLOC_FREE(translated_path);
return False;
@@ -366,7 +355,8 @@ void stat_cache_delete(const char *name)
DEBUG(10,("stat_cache_delete: deleting name [%s] -> %s\n",
lname, name ));
- tdb_delete_bystring(tdb_stat_cache, lname);
+ memcache_delete(smbd_memcache(), STAT_CACHE,
+ data_blob_const(lname, talloc_get_size(lname)-1));
TALLOC_FREE(lname);
}
@@ -395,15 +385,7 @@ bool reset_stat_cache( void )
if (!lp_stat_cache())
return True;
- if (tdb_stat_cache) {
- tdb_close(tdb_stat_cache);
- }
+ memcache_flush(smbd_memcache(), STAT_CACHE);
- /* Create the in-memory tdb using our custom hash function. */
- tdb_stat_cache = tdb_open_ex("statcache", 1031, TDB_INTERNAL,
- (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash);
-
- if (!tdb_stat_cache)
- return False;
return True;
}
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<MAX_GETWDCACHE;i++) {
- string_set(&ino_list[i].path,"");
- ino_list[i].valid = False;
- }
+ if (!lp_getwd_cache()) {
+ goto nocache;
}
- /* Get the inode of the current directory, if this doesn't work we're
- in trouble :-) */
+ SET_STAT_INVALID(st);
if (SMB_VFS_STAT(conn, ".",&st) == -1) {
- /* Known to fail for root: the directory may be
- * NFS-mounted and exported with root_squash (so has no root access). */
+ /*
+ * Known to fail for root: the directory may be NFS-mounted
+ * and exported with root_squash (so has no root access).
+ */
DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
- "(NFS problem ?)\n",
- strerror(errno) ));
+ "(NFS problem ?)\n", strerror(errno) ));
goto nocache;
}
+ ZERO_STRUCT(key); /* unlikely, but possible padding */
+ key.dev = st.st_dev;
+ key.ino = st.st_ino;
- for (i=0; i<MAX_GETWDCACHE; i++) {
- if (ino_list[i].valid) {
-
- /* If we have found an entry with a matching inode and dev number
- then find the inode number for the directory in the cached string.
- If this agrees with that returned by the stat for the current
- directory then all is o.k. (but make sure it is a directory all
- the same...) */
-
- if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
- if (SMB_VFS_STAT(conn,ino_list[i].path,&st2) == 0) {
- if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
- (st2.st_mode & S_IFMT) == S_IFDIR) {
+ if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
+ data_blob_const(&key, sizeof(key)),
+ &cache_value)) {
+ goto nocache;
+ }
- ret = talloc_strdup(ctx,
- ino_list[i].path);
+ SMB_ASSERT((cache_value.length > 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;
}
/*******************************************************************