s3: Cache results of finding printer names
authorVolker Lendecke <vl@samba.org>
Fri, 27 Aug 2010 12:44:16 +0000 (14:44 +0200)
committerKarolin Seeger <kseeger@samba.org>
Mon, 27 Sep 2010 19:29:02 +0000 (21:29 +0200)
With hundreds of printers or on a slow machine, this can become expensive.

Problem reported and patch sponsored by DESY, Hamburg (www.desy.de)

Fix bug #7656 (Scalability problem with hundreds of printers).
(cherry picked from commit de445e29ce944985651cbd62c8203cc9ace51a25)

source3/rpc_server/srv_spoolss_nt.c

index 4b5385be26e974762e30b44cf91026b1e1238d30..2a113e41259111a3f5cdb80b5f08777b2c8d6a65 100644 (file)
@@ -432,6 +432,14 @@ static bool set_printer_hnd_name(Printer_entry *Printer, const char *handlename)
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        WERROR result;
 
+       /*
+        * Hopefully nobody names his printers like this. Maybe \ or ,
+        * are illegal in printer names even?
+        */
+       const char printer_not_found[] = "Printer \\, !@#$%^&*( not found";
+       char *cache_key;
+       char *tmp;
+
        DEBUG(4,("Setting printer name=%s (len=%lu)\n", handlename,
                (unsigned long)strlen(handlename)));
 
@@ -474,6 +482,27 @@ static bool set_printer_hnd_name(Printer_entry *Printer, const char *handlename)
                found = true;
        }
 
+       /*
+        * With hundreds of printers, the "for" loop iterating all
+        * shares can be quite expensive, as it is done on every
+        * OpenPrinter. The loop maps "aprinter" to "sname", the
+        * result of which we cache in gencache.
+        */
+
+       cache_key = talloc_asprintf(talloc_tos(), "PRINTERNAME/%s",
+                                   aprinter);
+       if ((cache_key != NULL) && gencache_get(cache_key, &tmp, NULL)) {
+
+               found = (strcmp(tmp, printer_not_found) != 0);
+               if (!found) {
+                       DEBUG(4, ("Printer %s not found\n", aprinter));
+                       SAFE_FREE(tmp);
+                       return false;
+               }
+               fstrcpy(sname, tmp);
+               SAFE_FREE(tmp);
+       }
+
        /* Search all sharenames first as this is easier than pulling
           the printer_info_2 off of disk. Don't use find_service() since
           that calls out to map_username() */
@@ -539,10 +568,20 @@ static bool set_printer_hnd_name(Printer_entry *Printer, const char *handlename)
        free_a_printer( &printer, 2);
 
        if ( !found ) {
+               if (cache_key != NULL) {
+                       gencache_set(cache_key, printer_not_found,
+                                    time(NULL)+300);
+                       TALLOC_FREE(cache_key);
+               }
                DEBUGADD(4,("Printer not found\n"));
                return false;
        }
 
+       if (cache_key != NULL) {
+               gencache_set(cache_key, sname, time(NULL)+300);
+               TALLOC_FREE(cache_key);
+       }
+
        DEBUGADD(4,("set_printer_hnd_name: Printer found: %s -> %s\n", aprinter, sname));
 
        fstrcpy(Printer->sharename, sname);