]> granicus.if.org Git - postgresql/commitdiff
Fix GIN data page split ratio calculation.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 12 Sep 2014 08:23:59 +0000 (11:23 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 12 Sep 2014 08:27:56 +0000 (11:27 +0300)
The code that tried to split a page at 75/25 ratio, when appending to the
end of an index, was buggy in two ways. First, there was a silly typo that
caused it to just fill the left page as full as possible. But the logic as
it was intended wasn't correct either, and would actually have given a ratio
closer to 60/40 than 75/25.

Gaetano Mendola spotted the typo. Backpatch to 9.4, where this code was added.

src/backend/access/gin/gindatapage.c

index 76e0cb3e19f7bdea54edb9e468efea1d902b8940..e2d15a85fe41f91224b4c595181318f8a7d435e6 100644 (file)
@@ -621,9 +621,9 @@ dataPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                /*
                 * Had to split.
                 *
-                * We already divided the segments between the left and the right
-                * page. The left page was filled as full as possible, and the rest
-                * overflowed to the right page. When building a new index, that's
+                * leafRepackItems already divided the segments between the left and
+                * the right page. It filled the left page as full as possible, and
+                * put the rest to the right page. When building a new index, that's
                 * good, because the table is scanned from beginning to end and there
                 * won't be any more insertions to the left page during the build.
                 * This packs the index as tight as possible. But otherwise, split
@@ -631,9 +631,10 @@ dataPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                 * until they're balanced.
                 *
                 * As a further heuristic, when appending items to the end of the
-                * page, split 75/25, one the assumption that subsequent insertions
-                * will probably also go to the end. This packs the index somewhat
-                * tighter when appending to a table, which is very common.
+                * page, try make the left page 75% full, one the assumption that
+                * subsequent insertions will probably also go to the end. This packs
+                * the index somewhat tighter when appending to a table, which is very
+                * common.
                 */
                if (!btree->isBuild)
                {
@@ -645,14 +646,18 @@ dataPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                                if (lastleftinfo->action != GIN_SEGMENT_DELETE)
                                {
                                        segsize = SizeOfGinPostingList(lastleftinfo->seg);
+
+                                       /*
+                                        * Note that we check that the right page doesn't become
+                                        * more full than the left page even when appending. It's
+                                        * possible that we added enough items to make both pages
+                                        * more than 75% full.
+                                        */
+                                       if ((leaf->lsize - segsize) - (leaf->rsize + segsize) < 0)
+                                               break;
                                        if (append)
                                        {
-                                               if ((leaf->lsize - segsize) - (leaf->lsize - segsize) < BLCKSZ / 4)
-                                                       break;
-                                       }
-                                       else
-                                       {
-                                               if ((leaf->lsize - segsize) - (leaf->rsize + segsize) < 0)
+                                               if ((leaf->lsize - segsize) < (BLCKSZ * 3) / 4)
                                                        break;
                                        }