aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-04-05 22:02:28 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-04-05 22:15:58 +0300
commitffbba6ee1244901b492fe268ea94f72e35aedf38 (patch)
treeafdd2b33949d7733b253baff5c3d98336fc86430 /src
parent6862ca6970d11c47996d99e49a1cf8b55ef9b40d (diff)
downloadpostgresql-ffbba6ee1244901b492fe268ea94f72e35aedf38.tar.gz
postgresql-ffbba6ee1244901b492fe268ea94f72e35aedf38.zip
Fix another palloc in critical section.
Also add a regression test for a GIN index with enough items with the same key, so that a GIN posting tree gets created. Apparently none of the existing GIN tests were large enough for that. This code is new, no backpatching required.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/gin/gindatapage.c35
-rw-r--r--src/test/regress/expected/create_index.out14
-rw-r--r--src/test/regress/sql/create_index.sql14
3 files changed, 48 insertions, 15 deletions
diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c
index 21ce79fc0b1..70801bd05cb 100644
--- a/src/backend/access/gin/gindatapage.c
+++ b/src/backend/access/gin/gindatapage.c
@@ -1706,22 +1706,16 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems,
{
BlockNumber blkno;
Buffer buffer;
+ Page tmppage;
Page page;
Pointer ptr;
int nrootitems;
int rootsize;
- /*
- * Create the root page.
- */
- buffer = GinNewBuffer(index);
- page = BufferGetPage(buffer);
- blkno = BufferGetBlockNumber(buffer);
-
- START_CRIT_SECTION();
-
- GinInitPage(page, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
- GinPageGetOpaque(page)->rightlink = InvalidBlockNumber;
+ /* Construct the new root page in memory first. */
+ tmppage = (Page) palloc(BLCKSZ);
+ GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
+ GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
/*
* Write as many of the items to the root page as fit. In segments
@@ -1729,7 +1723,7 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems,
*/
nrootitems = 0;
rootsize = 0;
- ptr = (Pointer) GinDataLeafPageGetPostingList(page);
+ ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
while (nrootitems < nitems)
{
GinPostingList *segment;
@@ -1750,10 +1744,19 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems,
nrootitems += npacked;
pfree(segment);
}
- GinDataLeafPageSetPostingListSize(page, rootsize);
- MarkBufferDirty(buffer);
+ GinDataLeafPageSetPostingListSize(tmppage, rootsize);
- elog(DEBUG2, "created GIN posting tree with %d items", nrootitems);
+ /*
+ * All set. Get a new physical page, and copy the in-memory page to it.
+ */
+ buffer = GinNewBuffer(index);
+ page = BufferGetPage(buffer);
+ blkno = BufferGetBlockNumber(buffer);
+
+ START_CRIT_SECTION();
+
+ PageRestoreTempPage(tmppage, page);
+ MarkBufferDirty(buffer);
if (RelationNeedsWAL(index))
{
@@ -1787,6 +1790,8 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems,
if (buildStats)
buildStats->nDataPages++;
+ elog(DEBUG2, "created GIN posting tree with %d items", nrootitems);
+
/*
* Add any remaining TIDs to the newly-created posting tree.
*/
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index d10253b9e9b..f13b4f8a08d 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2221,6 +2221,20 @@ RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
--
+-- Try a GIN index with a lot of items with same key. (GIN creates a posting
+-- tree when there are enough duplicates)
+--
+CREATE TABLE array_gin_test (a int[]);
+INSERT INTO array_gin_test SELECT ARRAY[1, g%5, g] FROM generate_series(1, 10000) g;
+CREATE INDEX array_gin_test_idx ON array_gin_test USING gin (a);
+SELECT COUNT(*) FROM array_gin_test WHERE a @> '{2}';
+ count
+-------
+ 2000
+(1 row)
+
+DROP TABLE array_gin_test;
+--
-- HASH
--
CREATE INDEX hash_i4_index ON hash_i4_heap USING hash (random int4_ops);
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index 8ac1d1d280f..cd5c58d468c 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -637,6 +637,20 @@ RESET enable_indexscan;
RESET enable_bitmapscan;
--
+-- Try a GIN index with a lot of items with same key. (GIN creates a posting
+-- tree when there are enough duplicates)
+--
+CREATE TABLE array_gin_test (a int[]);
+
+INSERT INTO array_gin_test SELECT ARRAY[1, g%5, g] FROM generate_series(1, 10000) g;
+
+CREATE INDEX array_gin_test_idx ON array_gin_test USING gin (a);
+
+SELECT COUNT(*) FROM array_gin_test WHERE a @> '{2}';
+
+DROP TABLE array_gin_test;
+
+--
-- HASH
--
CREATE INDEX hash_i4_index ON hash_i4_heap USING hash (random int4_ops);