Skip to content

Commit 5dd0674

Browse files
committed
Don't try to read a multi-GB pg_stat_statements file in one call.
Windows fails on a request to read() more than INT_MAX bytes, and perhaps other platforms could have similar issues. Let's adjust this code to read at most 1GB per call. (One would not have thought the file could get that big, but now we have a field report of trouble, so it can. We likely ought to add some mechanism to limit the size of the query-texts file separately from the size of the hash table. That is not this patch, though.) Per bug #17254 from Yusuke Egashira. It's been like this for awhile, so back-patch to all supported branches. Discussion: https://postgr.es/m/17254-a926c89dc03375c2@postgresql.org
1 parent 91455f7 commit 5dd0674

File tree

1 file changed

+29
-16
lines changed

1 file changed

+29
-16
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,7 @@ qtext_load_file(Size *buffer_size)
19061906
char *buf;
19071907
int fd;
19081908
struct stat stat;
1909+
Size nread;
19091910

19101911
fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY);
19111912
if (fd < 0)
@@ -1946,28 +1947,40 @@ qtext_load_file(Size *buffer_size)
19461947
}
19471948

19481949
/*
1949-
* OK, slurp in the file. If we get a short read and errno doesn't get
1950-
* set, the reason is probably that garbage collection truncated the file
1951-
* since we did the fstat(), so we don't log a complaint --- but we don't
1952-
* return the data, either, since it's most likely corrupt due to
1953-
* concurrent writes from garbage collection.
1950+
* OK, slurp in the file. Windows fails if we try to read more than
1951+
* INT_MAX bytes at once, and other platforms might not like that either,
1952+
* so read a very large file in 1GB segments.
19541953
*/
1955-
errno = 0;
1956-
if (read(fd, buf, stat.st_size) != stat.st_size)
1954+
nread = 0;
1955+
while (nread < stat.st_size)
19571956
{
1958-
if (errno)
1959-
ereport(LOG,
1960-
(errcode_for_file_access(),
1961-
errmsg("could not read pg_stat_statement file \"%s\": %m",
1962-
PGSS_TEXT_FILE)));
1963-
free(buf);
1964-
CloseTransientFile(fd);
1965-
return NULL;
1957+
int toread = Min(1024 * 1024 * 1024, stat.st_size - nread);
1958+
1959+
/*
1960+
* If we get a short read and errno doesn't get set, the reason is
1961+
* probably that garbage collection truncated the file since we did
1962+
* the fstat(), so we don't log a complaint --- but we don't return
1963+
* the data, either, since it's most likely corrupt due to concurrent
1964+
* writes from garbage collection.
1965+
*/
1966+
errno = 0;
1967+
if (read(fd, buf + nread, toread) != toread)
1968+
{
1969+
if (errno)
1970+
ereport(LOG,
1971+
(errcode_for_file_access(),
1972+
errmsg("could not read pg_stat_statement file \"%s\": %m",
1973+
PGSS_TEXT_FILE)));
1974+
free(buf);
1975+
CloseTransientFile(fd);
1976+
return NULL;
1977+
}
1978+
nread += toread;
19661979
}
19671980

19681981
CloseTransientFile(fd);
19691982

1970-
*buffer_size = stat.st_size;
1983+
*buffer_size = nread;
19711984
return buf;
19721985
}
19731986

0 commit comments

Comments
 (0)