<<< Date Index >>>     <<< Thread Index >>>

Extremly slow browsing of folders



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