Recently I have switched my workplace over to an ldap directory service from YP(NIS). When this was done browsing folders in mutt became *very* slow, felt like using it over a 1200baud modem :-( After a lot of debugging with strace etc. it turns out mutt does several getgrgid and getpwuid calls while browsing folders (several calls for each entry, consisting of over 20 system calls and numerous calls to retrieve the group and password db to process). Obviously these calls were assumed to be inexpensive (in terms of wall clock time) but when being used on a system where the directory service is not local e.g. over an ssl link to a loaded ldap server getgrgid and getpwuid become *extremely* expensive. I examined the source in browser.c and have added caching for the group and password structures the first time they are obtained, this reduced the number of getgrgid/getpwuid calls massively at the expense of using a few hundred bytes per folder more memory. As a result mutt became responsive browsing folders again. Attached are the two patches to add this functionality, they should be applied pwcache.patch first then grcache.patch second. These are against the Debian 1.5.6 sources as thats what I had to hand - they should still apply elsewhere I hope. An alternate, more invasive, fix would be to build a distinct more persistent cache of looked up uids and access through that, this would reduce the lookups even further if all the folders belong to the same user/group (a very common occurrence) -- Regards Vincent http://www.kyllikki.org/
diff -u mutt-1.5.3.orig/browser.c mutt-1.5.3/browser.c --- mutt-1.5.3.orig/browser.c 2004-09-28 12:41:24.000000000 +0100 +++ mutt-1.5.3/browser.c 2004-09-28 14:07:26.000000000 +0100 @@ -64,6 +64,12 @@ FREE (&((state->entry)[c].name)); FREE (&((state->entry)[c].desc)); FREE (&((state->entry)[c].st)); + if((state->entry)[c].pw != NULL) + { + FREE (&((state->entry)[c].pw)); + FREE (&((state->entry)[c].pwbuf)); + } + } #ifdef USE_IMAP FREE (&state->folder); @@ -276,8 +282,35 @@ case 'u': if (folder->ff->st != NULL) { - if ((pw = getpwuid (folder->ff->st->st_uid))) + if(folder->ff->pw == NULL) + { + /* no cached copy - try to create one */ + folder->ff->pw = safe_malloc (sizeof(struct passwd)); + folder->ff->pwbuf = safe_malloc (sysconf(_SC_GETPW_R_SIZE_MAX)); + + getpwuid_r(folder->ff->st->st_uid, + folder->ff->pw, + folder->ff->pwbuf, + sysconf(_SC_GETPW_R_SIZE_MAX),&pw); + + if(pw == NULL) + { + fprintf(stderr,"%s:getpwuid_r failed\n",__FUNCTION__); + FREE (folder->ff->pwbuf); + folder->ff->pwbuf = NULL; + FREE (folder->ff->pw); + folder->ff->pw = NULL; + /* unable to get it in cached area so try system fallback */ + pw = getpwuid (folder->ff->st->st_uid); + } + } + else + { + pw = folder->ff->pw; + } + + if (pw) mutt_format_s (dest, destlen, fmt, pw->pw_name); else { snprintf (tmp, sizeof (tmp), "%%%sld", fmt); diff -u mutt-1.5.3.orig/browser.h mutt-1.5.3/browser.h --- mutt-1.5.3.orig/browser.h 2004-09-28 12:41:29.000000000 +0100 +++ mutt-1.5.3/browser.h 2004-09-28 14:08:30.000000000 +0100 @@ -26,6 +26,8 @@ off_t size; time_t mtime; struct stat *st; + struct passwd *pw; + unsigned char *pwbuf; char *name; char *desc;
diff -ur mutt-1.5.6.orig/browser.c mutt-1.5.6/browser.c --- mutt-1.5.6.orig/browser.c 2004-09-28 15:46:50.000000000 +0100 +++ mutt-1.5.6/browser.c 2004-09-28 15:53:18.000000000 +0100 @@ -64,11 +64,17 @@ FREE (&((state->entry)[c].name)); FREE (&((state->entry)[c].desc)); FREE (&((state->entry)[c].st)); + /* free cache entries if present */ if((state->entry)[c].pw != NULL) { FREE (&((state->entry)[c].pw)); FREE (&((state->entry)[c].pwbuf)); } + if((state->entry)[c].gr != NULL) + { + FREE (&((state->entry)[c].gr)); + FREE (&((state->entry)[c].grbuf)); + } } #ifdef USE_IMAP @@ -224,7 +230,35 @@ case 'g': if (folder->ff->st != NULL) { - if ((gr = getgrgid (folder->ff->st->st_gid))) + if(folder->ff->gr == NULL) + { + /* no cached group copy - try to create one */ + folder->ff->gr = safe_malloc (sizeof(struct group)); + folder->ff->grbuf = safe_malloc (sysconf(_SC_GETGR_R_SIZE_MAX)); + + getgrgid_r(folder->ff->st->st_gid, + folder->ff->gr, + folder->ff->grbuf, + sysconf(_SC_GETGR_R_SIZE_MAX),&gr); + + if(pw == NULL) + { + fprintf(stderr,"%s:getgrgid_r failed\n",__FUNCTION__); + FREE (folder->ff->grbuf); + folder->ff->grbuf = NULL; + FREE (folder->ff->gr); + folder->ff->gr = NULL; + /* unable to get it in cached area so try system fallback */ + gr = getgrgid (folder->ff->st->st_gid); + } + } + else + { + gr = folder->ff->gr; + } + + + if (gr) mutt_format_s (dest, destlen, fmt, gr->gr_name); else { diff -ur mutt-1.5.6.orig/browser.c.orig mutt-1.5.6/browser.c.orig --- mutt-1.5.6.orig/browser.c.orig 2004-09-28 15:46:49.000000000 +0100 +++ mutt-1.5.6/browser.c.orig 2004-09-28 15:46:50.000000000 +0100 @@ -64,6 +64,12 @@ FREE (&((state->entry)[c].name)); FREE (&((state->entry)[c].desc)); FREE (&((state->entry)[c].st)); + if((state->entry)[c].pw != NULL) + { + FREE (&((state->entry)[c].pw)); + FREE (&((state->entry)[c].pwbuf)); + } + } #ifdef USE_IMAP FREE (&state->folder); @@ -276,7 +282,34 @@ case 'u': if (folder->ff->st != NULL) { - if ((pw = getpwuid (folder->ff->st->st_uid))) + if(folder->ff->pw == NULL) + { + /* no cached copy - try to create one */ + folder->ff->pw = safe_malloc (sizeof(struct passwd)); + folder->ff->pwbuf = safe_malloc (sysconf(_SC_GETPW_R_SIZE_MAX)); + + getpwuid_r(folder->ff->st->st_uid, + folder->ff->pw, + folder->ff->pwbuf, + sysconf(_SC_GETPW_R_SIZE_MAX),&pw); + + if(pw == NULL) + { + fprintf(stderr,"%s:getpwuid_r failed\n",__FUNCTION__); + FREE (folder->ff->pwbuf); + folder->ff->pwbuf = NULL; + FREE (folder->ff->pw); + folder->ff->pw = NULL; + /* unable to get it in cached area so try system fallback */ + pw = getpwuid (folder->ff->st->st_uid); + } + } + else + { + pw = folder->ff->pw; + } + + if (pw) mutt_format_s (dest, destlen, fmt, pw->pw_name); else { diff -ur mutt-1.5.6.orig/browser.h mutt-1.5.6/browser.h --- mutt-1.5.6.orig/browser.h 2004-09-28 15:46:50.000000000 +0100 +++ mutt-1.5.6/browser.h 2004-09-28 15:51:48.000000000 +0100 @@ -29,6 +29,9 @@ struct passwd *pw; unsigned char *pwbuf; + struct group *gr; /* cached group info */ + unsigned char *grbuf; /* cached group info buffer */ + char *name; char *desc;
Attachment:
signature.asc
Description: Digital signature