]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix performance bug in write_syslog(): the code to preferentially break the
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 8 Jul 2008 22:18:09 +0000 (22:18 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 8 Jul 2008 22:18:09 +0000 (22:18 +0000)
log message at newlines cost O(N^2) for very long messages with few or no
newlines.  For messages in the megabyte range this became the dominant cost.
Per gripe from Achilleas Mantzios.

Patch all the way back, since this is a safe change with no portability
risks.  I am also thinking of increasing PG_SYSLOG_LIMIT, but that should
be done separately.

src/backend/utils/error/elog.c

index 3faef16851e17f1968a47ded74411a940aabcd80..1c1203ec5699d25593d9d31c10dcb764d0b046b6 100644 (file)
@@ -42,7 +42,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.155.4.7 2007/07/21 22:12:24 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.155.4.8 2008/07/08 22:18:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1170,6 +1170,7 @@ write_syslog(int level, const char *line)
        static unsigned long seq = 0;
 
        int                     len;
+       const char *nlpos;
 
        if (!openlog_done)
        {
@@ -1222,10 +1223,11 @@ write_syslog(int level, const char *line)
         * smaller pieces.
         *
         * We divide into multiple syslog() calls if message is too long
-        * or if the message contains embedded NewLine(s) '\n'.
+        * or if the message contains embedded newline(s).
         */
        len = strlen(line);
-       if (len > PG_SYSLOG_LIMIT || strchr(line, '\n') != NULL)
+       nlpos = strchr(line, '\n');
+       if (len > PG_SYSLOG_LIMIT || nlpos != NULL)
        {
                int                     chunk_nr = 0;
 
@@ -1240,15 +1242,19 @@ write_syslog(int level, const char *line)
                        {
                                line++;
                                len--;
+                               /* we need to recompute the next newline's position, too */
+                               nlpos = strchr(line, '\n');
                                continue;
                        }
 
-                       strncpy(buf, line, PG_SYSLOG_LIMIT);
-                       buf[PG_SYSLOG_LIMIT] = '\0';
-                       if (strchr(buf, '\n') != NULL)
-                               *strchr(buf, '\n') = '\0';
-
-                       buflen = strlen(buf);
+                       /* copy one line, or as much as will fit, to buf */
+                       if (nlpos != NULL)
+                               buflen = nlpos - line;
+                       else
+                               buflen = len;
+                       buflen = Min(buflen, PG_SYSLOG_LIMIT);
+                       memcpy(buf, line, buflen);
+                       buf[buflen] = '\0';
 
                        /* trim to multibyte letter boundary */
                        buflen = pg_mbcliplen(buf, buflen, buflen);