aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-07-08 22:18:09 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-07-08 22:18:09 +0000
commitc54053355a4a521c18f6f4d936172a931f037be8 (patch)
tree5547123d03c6cadf0e0f5aac9f4407b6ed8469b4
parent756aeaf0f3ca5e17908ae728b20eadea85e76565 (diff)
downloadpostgresql-c54053355a4a521c18f6f4d936172a931f037be8.tar.gz
postgresql-c54053355a4a521c18f6f4d936172a931f037be8.zip
Fix performance bug in write_syslog(): the code to preferentially break the
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.
-rw-r--r--src/backend/utils/error/elog.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 3faef16851e..1c1203ec569 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -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);