]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Performance fixes for Get-Jobs (STR #2913)
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 31 Jul 2014 00:02:30 +0000 (00:02 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 31 Jul 2014 00:02:30 +0000 (00:02 +0000)
Cache a few additional job attributes so that we normally do not need to load
the job attributes from the 'c' files.

If we do need to load them, limit the returned jobs to 500 at a time.

Implement first-index operation attribute.

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@12067 a1ca3aef-8c08-0410-bb20-df032aa958be

CHANGES.txt
scheduler/ipp.c
scheduler/job.c
scheduler/job.h

index 529cc4e455ea78cea6e40f8fd282c4ab8a57681e..d3a258b3259044a35355d3988f7f33cd6c5bb45f 100644 (file)
@@ -3,16 +3,17 @@ CHANGES.txt - 2.0b1 - 2014-07-30
 
 CHANGES IN CUPS V2.0b1
 
-       - Dropped OpenSSL support in favor of GNU TLS.
-       - Dropped "dark wake" support on OS X, which was preventing portables
-         from going to sleep when there was a stuck job. We now use a variation
-         of the CUPS 1.4 sleep support to do a cleaner sleep
-         (<rdar://problem/14323704>)
-       - Dropped support for AIX, HP-UX, and OSF/1 (aka Digital UNIX)
-       - Dropped lppasswd and support for Digest authentication in in the
-         scheduler (STR #4321)
-       - CUPS TLS support now supports certificate validation and policy
-         enforcement (STR #1616)
+       - Added a "--list-filters" option to the cupsfilter command (STR #4325)
+        - Added systemd support (STR #3917)
+       - Added support for re-sending a job as a raster file if a higher-level
+         format such as PDF fails (<rdar://problem/15583721>)
+       - Added support for regular expression matching in the MIME type rules
+         (<rdar://problem/11131245>)
+       - Added support for TLS certificate validation and policy enforcement
+         (STR #1616)
+       - Added support for simultaneous XML and test output from ipptool.
+       - Added support for PAUSE directive in ipptool test files.
+       - Added support for auto-typing of TIFF files by ipptool (STR #4418)
        - The scheduler now returns completed jobs in the correct newest-to-
          oldest order (STR #4396)
        - The configure script now supports target-specific tools for pkg-config
@@ -25,16 +26,27 @@ CHANGES IN CUPS V2.0b1
          default (<rdar://problem/14756625>)
        - Adopted Linux man page conventions and updated all man pages
          (STR #4372, STR #4329)
+       - The scheduler now supports the "first-index" operation attribute for
+         the Get-Jobs operation (STR #2913)
        - Changed the default AccessLogLevel and PageLogFormat to disable the
          access_log and page_log files by default (<rdar://problem/16495000>)
-       - Added a "--list-filters" option to the cupsfilter command (STR #4325)
-        - Added systemd support (STR #3917)
-       - Added support for re-sending a job as a raster file if a higher-level
-         format such as PDF fails (<rdar://problem/15583721>)
-       - Added support for regular expression matching in the MIME type rules
-         (<rdar://problem/11131245>)
        - cupsRasterInterpretPPD now supports the Orientation header in order to
          support long-edge feed raster printers (<rdar://problem/15837926>)
+       - The scheduler now allows run-as-root backends to have group read and
+         execute permissions (STR #2935)
+       - The ippFindAttribute and ippFindNextAttribute functions now support
+         hierarchical searches (STR #4395)
+       - Dropped OpenSSL support in favor of GNU TLS.
+       - Dropped "dark wake" support on OS X, which was preventing portables
+         from going to sleep when there was a stuck job. We now use a variation
+         of the CUPS 1.4 sleep support to do a cleaner sleep
+         (<rdar://problem/14323704>)
+       - Dropped support for AIX, HP-UX, and OSF/1 (aka Digital UNIX)
+       - Dropped lppasswd and support for Digest authentication in in the
+         scheduler (STR #4321)
+       - The scheduler now caches more job history data and limits the number
+         of completed jobs returned by Get-Jobs as needed in order to prevent a
+         denial-of-service on busy servers (STR #2913)
        - The filter/backend sandbox on OS X now defaults to a more strict
          whitelist (<rdar://problem/15939788>)
        - Increased the default idle exit timeout to 60 seconds on OS X
@@ -43,12 +55,5 @@ CHANGES IN CUPS V2.0b1
          (<rdar://problem/16385643>)
        - The scheduler now uses </DefaultPrinter> to close the default printer
          definition in printers.conf (STR #4153)
-       - The scheduler now allows run-as-root backends to have group read and
-         execute permissions (STR #2935)
-       - The ippFindAttribute and ippFindNextAttribute functions now support
-         hierarchical searches (STR #4395)
-       - Added support for simultaneous XML and test output from ipptool.
-       - Added support for PAUSE directive in ipptool test files.
-       - Added support for auto-typing of TIFF files by ipptool (STR #4418)
        - Canceling all jobs in the web interface now just cancels the jobs
          (STR #1914)
index 563d296ab3b59223f350b3c838768b6c09be2d9b..1f6fe5a39d0601e17149b431e76b0da056d0abed 100644 (file)
@@ -1511,8 +1511,7 @@ add_job(cupsd_client_t  *con,             /* I - Client connection */
   }
 
   if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) == NULL)
-    ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
-                 "Untitled");
+    ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
   else if ((attr->value_tag != IPP_TAG_NAME &&
             attr->value_tag != IPP_TAG_NAMELANG) ||
            attr->num_values != 1)
@@ -1592,6 +1591,9 @@ add_job(cupsd_client_t  *con,             /* I - Client connection */
       ippDeleteAttribute(job->attrs, auth_info);
   }
 
+  if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL)
+    cupsdSetString(&(job->name), attr->values[0].string.text);
+
   if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name",
                                IPP_TAG_ZERO)) != NULL)
   {
@@ -1686,8 +1688,7 @@ add_job(cupsd_client_t  *con,             /* I - Client connection */
   ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
                printer->uri);
 
-  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-                               IPP_TAG_INTEGER)) != NULL)
+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
     attr->values[0].integer = 0;
   else
     ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", 0);
@@ -4328,8 +4329,9 @@ copy_banner(cupsd_client_t *con,  /* I - Client connection */
 
   kbytes = (cupsFileTell(out) + 1023) / 1024;
 
-  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-                               IPP_TAG_INTEGER)) != NULL)
+  job->koctets += kbytes;
+
+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
     attr->values[0].integer += kbytes;
 
   cupsFileClose(out);
@@ -4751,7 +4753,55 @@ copy_job_attrs(cupsd_client_t *con,      /* I - Client connection */
                 "job-uri", NULL, job_uri);
   }
 
-  copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude);
+  if (job->attrs)
+  {
+    copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude);
+  }
+  else
+  {
+   /*
+    * Generate attributes from the job structure...
+    */
+
+    if (!ra || cupsArrayFind(ra, "job-id"))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+    if (!ra || cupsArrayFind(ra, "job-k-octets"))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", job->koctets);
+
+    if (job->name && (!ra || cupsArrayFind(ra, "job-name")))
+      ippAddString(con->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_NAME), "job-name", NULL, job->name);
+
+    if (job->username && (!ra || cupsArrayFind(ra, "job-originating-user-name")))
+      ippAddString(con->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_NAME), "job-originating-user-name", NULL, job->username);
+
+    if (!ra || cupsArrayFind(ra, "job-state"))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
+
+    if (!ra || cupsArrayFind(ra, "job-state-reasons"))
+    {
+      switch (job->state_value)
+      {
+        default : /* Should never get here for processing, pending, held, or stopped jobs since they don't get unloaded... */
+           break;
+        case IPP_JSTATE_ABORTED :
+           ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-aborted-by-system");
+           break;
+        case IPP_JSTATE_CANCELED :
+           ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-canceled-by-user");
+           break;
+        case IPP_JSTATE_COMPLETED :
+           ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-completed-successfully");
+           break;
+      }
+    }
+
+    if (job->completed_time && (!ra || cupsArrayFind(ra, "time-at-completed")))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-completed", (int)job->completed_time);
+
+    if (job->completed_time && (!ra || cupsArrayFind(ra, "time-at-creation")))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)job->creation_time);
+  }
 }
 
 
@@ -6101,9 +6151,13 @@ get_jobs(cupsd_client_t  *con,           /* I - Client connection */
   int          port;                   /* Port portion of URI */
   int          job_comparison;         /* Job comparison */
   ipp_jstate_t job_state;              /* job-state value */
-  int          first_job_id;           /* First job ID */
-  int          limit;                  /* Maximum number of jobs to return */
+  int          first_job_id = 1,       /* First job ID */
+               first_index = 1,        /* First index */
+               current_index = 0;      /* Current index */
+  int          limit = 0;              /* Maximum number of jobs to return */
   int          count;                  /* Number of jobs that match */
+  int          need_load_job = 0;      /* Do we need to load the job? */
+  const char   *job_attr;              /* Job attribute requested */
   ipp_attribute_t *job_ids;            /* job-ids attribute */
   cupsd_job_t  *job;                   /* Current job pointer */
   cupsd_printer_t *printer;            /* Printer */
@@ -6269,8 +6323,7 @@ get_jobs(cupsd_client_t  *con,            /* I - Client connection */
   * See if they want to limit the number of jobs reported...
   */
 
-  if ((attr = ippFindAttribute(con->request, "limit",
-                               IPP_TAG_INTEGER)) != NULL)
+  if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL)
   {
     if (job_ids)
     {
@@ -6282,11 +6335,20 @@ get_jobs(cupsd_client_t  *con,          /* I - Client connection */
 
     limit = attr->values[0].integer;
   }
-  else
-    limit = 0;
 
-  if ((attr = ippFindAttribute(con->request, "first-job-id",
-                               IPP_TAG_INTEGER)) != NULL)
+  if ((attr = ippFindAttribute(con->request, "first-index", IPP_TAG_INTEGER)) != NULL)
+  {
+    if (job_ids)
+    {
+      send_ipp_status(con, IPP_CONFLICT,
+                     _("The %s attribute cannot be provided with job-ids."),
+                     "first-index");
+      return;
+    }
+
+    first_index = attr->values[0].integer;
+  }
+  else if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL)
   {
     if (job_ids)
     {
@@ -6298,15 +6360,12 @@ get_jobs(cupsd_client_t  *con,          /* I - Client connection */
 
     first_job_id = attr->values[0].integer;
   }
-  else
-    first_job_id = 1;
 
  /*
   * See if we only want to see jobs for a specific user...
   */
 
-  if ((attr = ippFindAttribute(con->request, "my-jobs",
-                               IPP_TAG_BOOLEAN)) != NULL && job_ids)
+  if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && job_ids)
   {
     send_ipp_status(con, IPP_CONFLICT,
                     _("The %s attribute cannot be provided with job-ids."),
@@ -6319,6 +6378,42 @@ get_jobs(cupsd_client_t  *con,           /* I - Client connection */
     username[0] = '\0';
 
   ra = create_requested_array(con->request);
+  for (job_attr = (char *)cupsArrayFirst(ra); job_attr; job_attr = (char *)cupsArrayNext(ra))
+    if (strcmp(job_attr, "job-id") &&
+       strcmp(job_attr, "job-k-octets") &&
+       strcmp(job_attr, "job-media-progress") &&
+       strcmp(job_attr, "job-more-info") &&
+       strcmp(job_attr, "job-name") &&
+       strcmp(job_attr, "job-originating-user-name") &&
+       strcmp(job_attr, "job-preserved") &&
+       strcmp(job_attr, "job-printer-up-time") &&
+        strcmp(job_attr, "job-printer-uri") &&
+       strcmp(job_attr, "job-state") &&
+       strcmp(job_attr, "job-state-reasons") &&
+       strcmp(job_attr, "job-uri") &&
+       strcmp(job_attr, "time-at-completed") &&
+       strcmp(job_attr, "time-at-creation") &&
+       strcmp(job_attr, "number-of-documents"))
+    {
+      need_load_job = 1;
+      break;
+    }
+
+  if (need_load_job && (limit == 0 || limit > 500) && (list == Jobs || delete_list))
+  {
+   /*
+    * Limit expensive Get-Jobs for job history to 500 jobs...
+    */
+
+    ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "limit", 500);
+
+    if (limit)
+      ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "limit", limit);
+
+    limit = 500;
+
+    cupsdLogClient(con, CUPSD_LOG_INFO, "Limiting Get-Jobs response to %d jobs.", limit);
+  }
 
  /*
   * OK, build a list of jobs for this printer...
@@ -6345,13 +6440,15 @@ get_jobs(cupsd_client_t  *con,          /* I - Client connection */
     {
       job = cupsdFindJob(job_ids->values[i].integer);
 
-      cupsdLoadJob(job);
-
-      if (!job->attrs)
+      if (need_load_job && !job->attrs)
       {
-       cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d",
-                       job->id);
-       continue;
+        cupsdLoadJob(job);
+
+       if (!job->attrs)
+       {
+         cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id);
+         continue;
+       }
       }
 
       if (i > 0)
@@ -6401,13 +6498,19 @@ get_jobs(cupsd_client_t  *con,          /* I - Client connection */
       if (job->id < first_job_id)
        continue;
 
-      cupsdLoadJob(job);
+      current_index ++;
+      if (current_index < first_index)
+        continue;
 
-      if (!job->attrs)
+      if (need_load_job && !job->attrs)
       {
-       cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d",
-                       job->id);
-       continue;
+        cupsdLoadJob(job);
+
+       if (!job->attrs)
+       {
+         cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id);
+         continue;
+       }
       }
 
       if (username[0] && _cups_strcasecmp(username, job->username))
@@ -8141,8 +8244,9 @@ print_job(cupsd_client_t  *con,           /* I - Client connection */
 
   cupsdUpdateQuota(printer, job->username, 0, kbytes);
 
-  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-                               IPP_TAG_INTEGER)) != NULL)
+  job->koctets += kbytes;
+
+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
     attr->values[0].integer += kbytes;
 
  /*
@@ -9375,8 +9479,9 @@ send_document(cupsd_client_t  *con,       /* I - Client connection */
 
   cupsdUpdateQuota(printer, job->username, 0, kbytes);
 
-  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-                               IPP_TAG_INTEGER)) != NULL)
+  job->koctets += kbytes;
+
+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
     attr->values[0].integer += kbytes;
 
   snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
index 0d9aafbc1396987fca97adfbe7c2c6cc2c69eb6b..9d500d1fbf133e11f7d9c11cb76cd83e093fa1d9 100644 (file)
@@ -1675,9 +1675,10 @@ cupsdLoadJob(cupsd_job_t *job)           /* I - Job */
   job->file_time    = 0;
   job->history_time = 0;
 
-  if (job->state_value >= IPP_JOB_CANCELED &&
-      (attr = ippFindAttribute(job->attrs, "time-at-completed",
-                              IPP_TAG_INTEGER)) != NULL)
+  if ((attr = ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER)) != NULL)
+    job->creation_time = attr->values[0].integer;
+
+  if (job->state_value >= IPP_JOB_CANCELED && (attr = ippFindAttribute(job->attrs, "time-at-completed", IPP_TAG_INTEGER)) != NULL)
   {
     job->completed_time = attr->values[0].integer;
 
@@ -1826,6 +1827,12 @@ cupsdLoadJob(cupsd_job_t *job)           /* I - Job */
     cupsdSetString(&job->username, attr->values[0].string.text);
   }
 
+  if (!job->name)
+  {
+    if ((attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL)
+      cupsdSetString(&job->name, attr->values[0].string.text);
+  }
+
  /*
   * Set the job hold-until time and state...
   */
@@ -1850,6 +1857,9 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
     job->state_value              = IPP_JOB_PENDING;
   }
 
+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
+    job->koctets = attr->values[0].integer;
+
   if (!job->num_files)
   {
    /*
@@ -2155,14 +2165,18 @@ cupsdSaveAllJobs(void)
   {
     cupsFilePrintf(fp, "<Job %d>\n", job->id);
     cupsFilePrintf(fp, "State %d\n", job->state_value);
+    cupsFilePrintf(fp, "Created %ld\n", (long)job->creation_time);
     if (job->completed_time)
       cupsFilePrintf(fp, "Completed %ld\n", (long)job->completed_time);
     cupsFilePrintf(fp, "Priority %d\n", job->priority);
     if (job->hold_until)
       cupsFilePrintf(fp, "HoldUntil %ld\n", (long)job->hold_until);
     cupsFilePrintf(fp, "Username %s\n", job->username);
+    if (job->name)
+      cupsFilePutConf(fp, "Name", job->name);
     cupsFilePrintf(fp, "Destination %s\n", job->dest);
     cupsFilePrintf(fp, "DestType %d\n", job->dtype);
+    cupsFilePrintf(fp, "KOctets %d\n", job->koctets);
     cupsFilePrintf(fp, "NumFiles %d\n", job->num_files);
     for (i = 0; i < job->num_files; i ++)
       cupsFilePrintf(fp, "File %d %s/%s %d\n", i + 1, job->filetypes[i]->super,
@@ -4114,7 +4128,7 @@ load_job_cache(const char *filename)      /* I - job.cache filename */
        cupsArrayAdd(ActiveJobs, job);
       else if (job->state_value > IPP_JOB_STOPPED)
       {
-        if (!job->completed_time)
+        if (!job->completed_time || !job->creation_time || !job->name || !job->koctets)
        {
          cupsdLoadJob(job);
          unload_job(job);
@@ -4137,6 +4151,14 @@ load_job_cache(const char *filename)     /* I - job.cache filename */
       else if (job->state_value > IPP_JOB_COMPLETED)
         job->state_value = IPP_JOB_COMPLETED;
     }
+    else if (!_cups_strcasecmp(line, "Name"))
+    {
+      cupsdSetString(&(job->name), value);
+    }
+    else if (!_cups_strcasecmp(line, "Created"))
+    {
+      job->creation_time = strtol(value, NULL, 10);
+    }
     else if (!_cups_strcasecmp(line, "Completed"))
     {
       job->completed_time = strtol(value, NULL, 10);
@@ -4161,6 +4183,10 @@ load_job_cache(const char *filename)     /* I - job.cache filename */
     {
       job->dtype = (cups_ptype_t)atoi(value);
     }
+    else if (!_cups_strcasecmp(line, "KOctets"))
+    {
+      job->koctets = atoi(value);
+    }
     else if (!_cups_strcasecmp(line, "NumFiles"))
     {
       job->num_files = atoi(value);
index ef66078e1f8e7982e785b0eae4028c3087acd430..37b20dadd581981b04759f5b1d61bfaefc4ae796 100644 (file)
@@ -39,6 +39,8 @@ struct cupsd_job_s                    /**** Job request ****/
                                         * waiting on files */
   char                 *username;      /* Printing user */
   char                 *dest;          /* Destination printer or class */
+  char                 *name;          /* Job name/title */
+  int                  koctets;        /* job-k-octets */
   cups_ptype_t         dtype;          /* Destination type */
   cupsd_printer_t      *printer;       /* Printer this job is assigned to */
   int                  num_files;      /* Number of files in job */
@@ -47,6 +49,7 @@ struct cupsd_job_s                    /**** Job request ****/
   ipp_attribute_t      *sheets;        /* job-media-sheets-completed */
   time_t               access_time,    /* Last access time */
                        cancel_time,    /* When to cancel/send SIGTERM */
+                       creation_time,  /* When job was created */
                        completed_time, /* When job was completed (0 if not) */
                        file_time,      /* Job file retain time */
                        history_time,   /* Job history retain time */