aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gist.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-04-03 15:09:37 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-04-03 15:44:20 +0300
commit05a5623766d527e1683901687dffc1cee9d7d273 (patch)
tree0c37db5c580c22bc61d072438ce35773fb38e18c /src/backend/access/gist/gist.c
parentb7a424371499f1c0b8f2b092a4178ec1b9e368f8 (diff)
downloadpostgresql-05a5623766d527e1683901687dffc1cee9d7d273.tar.gz
postgresql-05a5623766d527e1683901687dffc1cee9d7d273.zip
Avoid palloc in critical section in GiST WAL-logging.
Memory allocation can fail if you run out of memory, and inside a critical section that will lead to a PANIC. Use conservatively-sized arrays in stack instead. There was previously no explicit limit on the number of pages a GiST split can produce, it was only limited by the number of LWLocks that can be held simultaneously (100 at the moment). This patch adds an explicit limit of 75 pages. That should be plenty, a typical split shouldn't produce more than 2-3 page halves. The bug has been there forever, but only backpatch down to 9.1. The code was changed significantly in 9.1, and it doesn't seem worth the risk or trouble to adapt this for 9.0 and 8.4.
Diffstat (limited to 'src/backend/access/gist/gist.c')
-rw-r--r--src/backend/access/gist/gist.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 7dbc5dd08ec..7172f210286 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -356,6 +356,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
SplitedPageLayout rootpg;
BlockNumber blkno = BufferGetBlockNumber(buffer);
bool is_rootsplit;
+ int npage;
is_rootsplit = (blkno == GIST_ROOT_BLKNO);
@@ -377,6 +378,19 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate,
dist = gistSplit(state->r, page, itvec, tlen, giststate);
/*
+ * Check that split didn't produce too many pages.
+ */
+ npage = 0;
+ for (ptr = dist; ptr; ptr = ptr->next)
+ npage++;
+ /* in a root split, we'll add one more page to the list below */
+ if (is_rootsplit)
+ npage++;
+ if (npage > GIST_MAX_SPLIT_PAGES)
+ elog(ERROR, "GiST page split into too many halves (%d, maximum %d)",
+ npage, GIST_MAX_SPLIT_PAGES);
+
+ /*
* Set up pages to work with. Allocate new buffers for all but the
* leftmost page. The original page becomes the new leftmost page, and
* is just replaced with the new contents.