Make the man(1) and apropos(1) options -s and -S much less expensive:
authorschwarze <schwarze@openbsd.org>
Tue, 20 Jan 2015 18:19:39 +0000 (18:19 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 20 Jan 2015 18:19:39 +0000 (18:19 +0000)
Do not append an SQL clause looking into the large "keys" table.
Instead, filter the result of the SQL query in buildnames() where
equivalent data from the much smaller "mlinks" table is already
available for free.

This is relevant because man(1) uses the equivalent of "-S ${MACHINE}"
by default since main.c rev. 1.122, to make sure that manuals for
the current architecture are shown.  With many ports installed, this
patch can speed up man(1) by a factor of more than a hundred.

Slowness reported by Theo Buehler <theo at math dot ethz dot ch>, thanks!

usr.bin/mandoc/mansearch.c

index bc052b3..2e7c7bd 100644 (file)
@@ -1,7 +1,7 @@
-/*     $OpenBSD: mansearch.c,v 1.39 2014/12/06 01:22:28 schwarze Exp $ */
+/*     $OpenBSD: mansearch.c,v 1.40 2015/01/20 18:19:39 schwarze Exp $ */
 /*
  * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -77,7 +77,8 @@ struct        match {
        int              form; /* bit field: formatted, zipped? */
 };
 
-static void             buildnames(struct manpage *, sqlite3 *,
+static void             buildnames(const struct mansearch *,
+                               struct manpage *, sqlite3 *,
                                sqlite3_stmt *, uint64_t,
                                const char *, int form);
 static char            *buildoutput(sqlite3 *, sqlite3_stmt *,
@@ -88,8 +89,6 @@ static        void            *hash_calloc(size_t, size_t, void *);
 static struct expr     *exprcomp(const struct mansearch *,
                                int, char *[]);
 static void             exprfree(struct expr *);
-static struct expr     *exprspec(struct expr *, uint64_t,
-                                const char *, const char *);
 static struct expr     *exprterm(const struct mansearch *, char *, int);
 static int              manpage_compare(const void *, const void *);
 static void             sql_append(char **sql, size_t *sz,
@@ -335,14 +334,16 @@ mansearch(const struct mansearch *search,
                        mpage->bits = mp->bits;
                        mpage->sec = 10;
                        mpage->form = mp->form;
-                       buildnames(mpage, db, s, mp->pageid,
+                       buildnames(search, mpage, db, s, mp->pageid,
                            paths->paths[i], mp->form);
-                       mpage->output = TYPE_Nd & outbit ?
-                           mp->desc : outbit ?
-                           buildoutput(db, s2, mp->pageid, outbit) : NULL;
-
+                       if (mpage->names != NULL) {
+                               mpage->output = TYPE_Nd & outbit ?
+                                   mp->desc : outbit ?
+                                   buildoutput(db, s2, mp->pageid, outbit) :
+                                   NULL;
+                               cur++;
+                       }
                        free(mp);
-                       cur++;
                }
 
                sqlite3_finalize(s);
@@ -399,7 +400,8 @@ manpage_compare(const void *vp1, const void *vp2)
 }
 
 static void
-buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
+buildnames(const struct mansearch *search, struct manpage *mpage,
+               sqlite3 *db, sqlite3_stmt *s,
                uint64_t pageid, const char *path, int form)
 {
        char            *newnames, *prevsec, *prevarch;
@@ -424,10 +426,15 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
                        sep1 = ", ";
                }
 
-               /* Fetch the next name. */
+               /* Fetch the next name, rejecting sec/arch mismatches. */
 
                sec = (const char *)sqlite3_column_text(s, 0);
+               if (search->sec != NULL && strcasecmp(sec, search->sec))
+                       continue;
                arch = (const char *)sqlite3_column_text(s, 1);
+               if (search->arch != NULL && *arch != '\0' &&
+                   strcasecmp(arch, search->arch))
+                       continue;
                name = (const char *)sqlite3_column_text(s, 2);
 
                /* Remember the first section found. */
@@ -637,8 +644,7 @@ exprcomp(const struct mansearch *search, int argc, char *argv[])
        struct expr     *first, *prev, *cur, *next;
 
        first = cur = NULL;
-       logic = igncase = toclose = 0;
-       toopen = NULL != search->sec || NULL != search->arch;
+       logic = igncase = toopen = toclose = 0;
 
        for (i = 0; i < argc; i++) {
                if (0 == strcmp("(", argv[i])) {
@@ -704,17 +710,8 @@ exprcomp(const struct mansearch *search, int argc, char *argv[])
 
                toopen = logic = igncase = 0;
        }
-       if (toopen || logic || igncase || toclose)
-               goto fail;
-
-       if (NULL != search->sec || NULL != search->arch)
-               cur->close++;
-       if (NULL != search->arch)
-               cur = exprspec(cur, TYPE_arch, search->arch, "^(%s|any)$");
-       if (NULL != search->sec)
-               exprspec(cur, TYPE_sec, search->sec, "^%s$");
-
-       return(first);
+       if ( ! (toopen || logic || igncase || toclose))
+               return(first);
 
 fail:
        if (NULL != first)
@@ -722,29 +719,6 @@ fail:
        return(NULL);
 }
 
-static struct expr *
-exprspec(struct expr *cur, uint64_t key, const char *value,
-               const char *format)
-{
-       char     errbuf[BUFSIZ];
-       char    *cp;
-       int      irc;
-
-       mandoc_asprintf(&cp, format, value);
-       cur->next = mandoc_calloc(1, sizeof(struct expr));
-       cur = cur->next;
-       cur->and = 1;
-       cur->bits = key;
-       if (0 != (irc = regcomp(&cur->regexp, cp,
-           REG_EXTENDED | REG_NOSUB | REG_ICASE))) {
-               regerror(irc, &cur->regexp, errbuf, sizeof(errbuf));
-               fprintf(stderr, "regcomp: %s\n", errbuf);
-               cur->substr = value;
-       }
-       free(cp);
-       return(cur);
-}
-
 static struct expr *
 exprterm(const struct mansearch *search, char *buf, int cs)
 {