summaryrefslogtreecommitdiff
path: root/source3/smbd/filename.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2000-01-26 21:25:35 +0000
committerJeremy Allison <jra@samba.org>2000-01-26 21:25:35 +0000
commitace4006c9f7ac16b3c09b1b2222f607bccfa040e (patch)
tree772287462f6eafa8864cc9e4373b759fd5bfcf0d /source3/smbd/filename.c
parentd867b86721e988dee56d5e9382b32c870ccb2790 (diff)
downloadsamba-ace4006c9f7ac16b3c09b1b2222f607bccfa040e.tar.gz
samba-ace4006c9f7ac16b3c09b1b2222f607bccfa040e.tar.bz2
samba-ace4006c9f7ac16b3c09b1b2222f607bccfa040e.zip
Added hash-based stat cache code from Ying Chen.
Jeremy. (This used to be commit b62a1bd6328f5894ae1a2fef3ef6fc66304ade52)
Diffstat (limited to 'source3/smbd/filename.c')
-rw-r--r--source3/smbd/filename.c173
1 files changed, 92 insertions, 81 deletions
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 64f63805f3..2f8e92d98e 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -3,6 +3,8 @@
Version 1.9.
filename handling routines
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1999-200
+ Copyright (C) Ying Chen 2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,6 +21,10 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * New hash table stat cache code added by Ying Chen.
+ */
+
#include "includes.h"
extern int DEBUGLEVEL;
@@ -109,15 +115,12 @@ stat cache was %f%% effective.\n", global_stat_cache_lookups,
}
typedef struct {
- ubi_dlNode link;
int name_len;
- pstring orig_name;
- pstring translated_name;
+ char names[2]; /* This is extended via malloc... */
} stat_cache_entry;
-#define MAX_STAT_CACHE_SIZE 50
-
-static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0};
+#define INIT_STAT_CACHE_SIZE 512
+static hash_table stat_cache;
/****************************************************************************
Compare a pathname to a name in the stat cache - of a given length.
@@ -144,9 +147,11 @@ static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
{
stat_cache_entry *scp;
+ stat_cache_entry *found_scp;
pstring orig_name;
pstring translated_path;
int namelen;
+ hash_element *hash_elem;
if (!lp_stat_cache()) return;
@@ -194,39 +199,39 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
* add it.
*/
- for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
- scp = (stat_cache_entry *)ubi_dlNext( scp )) {
- if((strcmp( scp->orig_name, orig_name) == 0) &&
- (strcmp( scp->translated_name, translated_path) == 0)) {
- /*
- * Name does exist - promote it.
- */
- if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != scp ) {
- ubi_dlRemThis( &stat_cache, scp);
- ubi_dlAddHead( &stat_cache, scp);
- }
+ if (hash_elem = hash_lookup(&stat_cache, orig_name)) {
+ found_scp = (stat_cache_entry *)(hash_elem->value);
+ if (strcmp((found_scp->names+found_scp->name_len+1), translated_path) == 0) {
return;
+ } else {
+ hash_remove(&stat_cache, hash_elem);
+ if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
+ DEBUG(0,("stat_cache_add: Out of memory !\n"));
+ return;
+ }
+ pstrcpy(scp->names, orig_name);
+ pstrcpy((scp->names+namelen+1), translated_path);
+ scp->name_len = namelen;
+ hash_insert(&stat_cache, (char *)scp, orig_name);
}
- }
-
- if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry))) == NULL) {
- DEBUG(0,("stat_cache_add: Out of memory !\n"));
return;
- }
-
- pstrcpy(scp->orig_name, orig_name);
- pstrcpy(scp->translated_name, translated_path);
- scp->name_len = namelen;
-
- ubi_dlAddHead( &stat_cache, scp);
+ } else {
- DEBUG(10,("stat_cache_add: Added entry %s -> %s\n", scp->orig_name, scp->translated_name ));
+ /*
+ * New entry.
+ */
- if(ubi_dlCount(&stat_cache) > lp_stat_cache_size()) {
- scp = (stat_cache_entry *)ubi_dlRemTail( &stat_cache );
- free((char *)scp);
- return;
+ if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
+ DEBUG(0,("stat_cache_add: Out of memory !\n"));
+ return;
+ }
+ pstrcpy(scp->names, orig_name);
+ pstrcpy(scp->names+namelen+1, translated_path);
+ scp->name_len = namelen;
+ hash_insert(&stat_cache, (char *)scp, orig_name);
}
+
+ DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->names, (scp->names+scp->name_len+1)));
}
/****************************************************************************
@@ -238,10 +243,14 @@ static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRU
{
stat_cache_entry *scp;
stat_cache_entry *longest_hit = NULL;
+ char *trans_name;
pstring chk_name;
int namelen;
+ hash_element *hash_elem;
+ char *sp;
- if (!lp_stat_cache()) return False;
+ if (!lp_stat_cache())
+ return False;
namelen = strlen(name);
@@ -260,55 +269,44 @@ static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRU
if(!case_sensitive)
strupper( chk_name );
- for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
- scp = (stat_cache_entry *)ubi_dlNext( scp )) {
- if(scp->name_len <= namelen) {
- if(stat_name_equal_len(scp->orig_name, chk_name, scp->name_len)) {
- if((longest_hit == NULL) || (longest_hit->name_len <= scp->name_len))
- longest_hit = scp;
+ while (1) {
+ hash_elem = hash_lookup(&stat_cache, chk_name);
+ if(hash_elem == NULL) {
+ /*
+ * Didn't find it - remove last component for next try.
+ */
+ sp = strrchr(chk_name, '/');
+ if (sp) {
+ *sp = '\0';
+ } else {
+ /*
+ * We reached the end of the name - no match.
+ */
+ global_stat_cache_misses++;
+ return False;
}
+ if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0)
+ || (strcmp(chk_name, "..") == 0)) {
+ global_stat_cache_misses++;
+ return False;
+ }
+ } else {
+ scp = (stat_cache_entry *)(hash_elem->value);
+ global_stat_cache_hits++;
+ trans_name = scp->names+scp->name_len+1;
+ if(dos_stat( trans_name, pst) != 0) {
+ /* Discard this entry - it doesn't exist in the filesystem. */
+ hash_remove(&stat_cache, hash_elem);
+ return False;
+ }
+ memcpy(name, trans_name, scp->name_len);
+ *start = &name[scp->name_len];
+ if(**start == '/')
+ ++*start;
+ StrnCpy( dirpath, trans_name, name - (*start));
+ return (namelen == scp->name_len);
}
}
-
- if(longest_hit == NULL) {
- DEBUG(10,("stat_cache_lookup: cache miss on %s\n", name));
- global_stat_cache_misses++;
- return False;
- }
-
- global_stat_cache_hits++;
-
- DEBUG(10,("stat_cache_lookup: cache hit for name %s. %s -> %s\n",
- name, longest_hit->orig_name, longest_hit->translated_name ));
-
- /*
- * longest_hit is the longest match we got in the list.
- * Check it exists - if so, overwrite the original name
- * and then promote it to the top.
- */
-
- if(dos_stat( longest_hit->translated_name, pst) != 0) {
- /*
- * Discard this entry.
- */
- ubi_dlRemThis( &stat_cache, longest_hit);
- free((char *)longest_hit);
- return False;
- }
-
- memcpy(name, longest_hit->translated_name, longest_hit->name_len);
- if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != longest_hit ) {
- ubi_dlRemThis( &stat_cache, longest_hit);
- ubi_dlAddHead( &stat_cache, longest_hit);
- }
-
- *start = &name[longest_hit->name_len];
- if(**start == '/')
- ++*start;
-
- StrnCpy( dirpath, longest_hit->translated_name, name - (*start));
-
- return (namelen == longest_hit->name_len);
}
/****************************************************************************
@@ -352,7 +350,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
*dirpath = 0;
*bad_path = False;
if(pst) {
- ZERO_STRUCTP(pst);
+ ZERO_STRUCTP(pst);
}
if(saved_last_component)
@@ -744,3 +742,16 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d
CloseDir(cur_dir);
return(False);
}
+
+/*************************************************************************** **
+ * Initializes or clears the stat cache.
+ *
+ * Input: none.
+ * Output: none.
+ *
+ * ************************************************************************** **
+ */
+BOOL reset_stat_cache( void )
+{
+ return hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE, (compare_function)(strcmp));
+} /* reset_stat_cache */