Avoid allocations in critical sections.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 4 Apr 2014 10:12:38 +0000 (13:12 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 4 Apr 2014 10:22:45 +0000 (13:22 +0300)
If a palloc in a critical section fails, it becomes a PANIC.

src/backend/access/nbtree/nbtinsert.c
src/backend/access/spgist/spgdoinsert.c
src/backend/access/transam/xlog.c
src/backend/storage/page/bufpage.c

index 3ed9b5cc2900f89b4c04506557d8dac2064ab085..a324aa27a9187ad204c329d6b9373830da344b38 100644 (file)
@@ -1839,8 +1839,10 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
    BTPageOpaque rootopaque;
    ItemId      itemid;
    IndexTuple  item;
-   Size        itemsz;
-   IndexTuple  new_item;
+   IndexTuple  left_item;
+   Size        left_item_sz;
+   IndexTuple  right_item;
+   Size        right_item_sz;
    Buffer      metabuf;
    Page        metapg;
    BTMetaPageData *metad;
@@ -1859,6 +1861,26 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
    metapg = BufferGetPage(metabuf);
    metad = BTPageGetMeta(metapg);
 
+   /*
+    * Create downlink item for left page (old root).  Since this will be the
+    * first item in a non-leaf page, it implicitly has minus-infinity key
+    * value, so we need not store any actual key in it.
+    */
+   left_item_sz = sizeof(IndexTupleData);
+   left_item = (IndexTuple) palloc(left_item_sz);
+   left_item->t_info = left_item_sz;
+   ItemPointerSet(&(left_item->t_tid), lbkno, P_HIKEY);
+
+   /*
+    * Create downlink item for right page.  The key for it is obtained from
+    * the "high key" position in the left page.
+    */
+   itemid = PageGetItemId(lpage, P_HIKEY);
+   right_item_sz = ItemIdGetLength(itemid);
+   item = (IndexTuple) PageGetItem(lpage, itemid);
+   right_item = CopyIndexTuple(item);
+   ItemPointerSet(&(right_item->t_tid), rbkno, P_HIKEY);
+
    /* NO EREPORT(ERROR) from here till newroot op is logged */
    START_CRIT_SECTION();
 
@@ -1876,16 +1898,6 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
    metad->btm_fastroot = rootblknum;
    metad->btm_fastlevel = rootopaque->btpo.level;
 
-   /*
-    * Create downlink item for left page (old root).  Since this will be the
-    * first item in a non-leaf page, it implicitly has minus-infinity key
-    * value, so we need not store any actual key in it.
-    */
-   itemsz = sizeof(IndexTupleData);
-   new_item = (IndexTuple) palloc(itemsz);
-   new_item->t_info = itemsz;
-   ItemPointerSet(&(new_item->t_tid), lbkno, P_HIKEY);
-
    /*
     * Insert the left page pointer into the new root page.  The root page is
     * the rightmost page on its level so there is no "high key" in it; the
@@ -1894,32 +1906,20 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
     * Note: we *must* insert the two items in item-number order, for the
     * benefit of _bt_restore_page().
     */
-   if (PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY,
+   if (PageAddItem(rootpage, (Item) left_item, left_item_sz, P_HIKEY,
                    false, false) == InvalidOffsetNumber)
        elog(PANIC, "failed to add leftkey to new root page"
             " while splitting block %u of index \"%s\"",
             BufferGetBlockNumber(lbuf), RelationGetRelationName(rel));
-   pfree(new_item);
-
-   /*
-    * Create downlink item for right page.  The key for it is obtained from
-    * the "high key" position in the left page.
-    */
-   itemid = PageGetItemId(lpage, P_HIKEY);
-   itemsz = ItemIdGetLength(itemid);
-   item = (IndexTuple) PageGetItem(lpage, itemid);
-   new_item = CopyIndexTuple(item);
-   ItemPointerSet(&(new_item->t_tid), rbkno, P_HIKEY);
 
    /*
     * insert the right page pointer into the new root page.
     */
-   if (PageAddItem(rootpage, (Item) new_item, itemsz, P_FIRSTKEY,
+   if (PageAddItem(rootpage, (Item) right_item, right_item_sz, P_FIRSTKEY,
                    false, false) == InvalidOffsetNumber)
        elog(PANIC, "failed to add rightkey to new root page"
             " while splitting block %u of index \"%s\"",
             BufferGetBlockNumber(lbuf), RelationGetRelationName(rel));
-   pfree(new_item);
 
    MarkBufferDirty(rootbuf);
    MarkBufferDirty(metabuf);
@@ -1967,6 +1967,9 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
    /* done with metapage */
    _bt_relbuf(rel, metabuf);
 
+   pfree(left_item);
+   pfree(right_item);
+
    return rootbuf;
 }
 
index 35676d69c63c008a85be01caa286bdd7063250e0..0f8c884ee053def93a30eacb2d6a5010247df5b9 100644 (file)
@@ -121,7 +121,8 @@ cmpOffsetNumbers(const void *a, const void *b)
  *
  * NB: this is used during WAL replay, so beware of trying to make it too
  * smart.  In particular, it shouldn't use "state" except for calling
- * spgFormDeadTuple().
+ * spgFormDeadTuple().  This is also used in a critical section, so no
+ * pallocs either!
  */
 void
 spgPageIndexMultiDelete(SpGistState *state, Page page,
@@ -130,7 +131,7 @@ spgPageIndexMultiDelete(SpGistState *state, Page page,
                        BlockNumber blkno, OffsetNumber offnum)
 {
    OffsetNumber firstItem;
-   OffsetNumber *sortednos;
+   OffsetNumber sortednos[MaxIndexTuplesPerPage];
    SpGistDeadTuple tuple = NULL;
    int         i;
 
@@ -144,7 +145,6 @@ spgPageIndexMultiDelete(SpGistState *state, Page page,
     * replacement tuples.)  However, we must not scribble on the caller's
     * array, so we have to make a copy.
     */
-   sortednos = (OffsetNumber *) palloc(sizeof(OffsetNumber) * nitems);
    memcpy(sortednos, itemnos, sizeof(OffsetNumber) * nitems);
    if (nitems > 1)
        qsort(sortednos, nitems, sizeof(OffsetNumber), cmpOffsetNumbers);
@@ -172,8 +172,6 @@ spgPageIndexMultiDelete(SpGistState *state, Page page,
        else if (tupstate == SPGIST_PLACEHOLDER)
            SpGistPageGetOpaque(page)->nPlaceholder++;
    }
-
-   pfree(sortednos);
 }
 
 /*
index e245aa6ef8a9ba0dac6b89519c428bd447a1fe34..2f715903245153198387ceee16cbacebe3c6ad64 100644 (file)
@@ -2449,6 +2449,7 @@ XLogFileInit(uint32 log, uint32 seg,
 {
    char        path[MAXPGPATH];
    char        tmppath[MAXPGPATH];
+   char        zbuffer_raw[BLCKSZ + MAXIMUM_ALIGNOF];
    char       *zbuffer;
    uint32      installed_log;
    uint32      installed_seg;
@@ -2506,11 +2507,11 @@ XLogFileInit(uint32 log, uint32 seg,
     * fdatasync(2) or O_DSYNC will be sufficient to sync future writes to the
     * log file.
     *
-    * Note: palloc zbuffer, instead of just using a local char array, to
-    * ensure it is reasonably well-aligned; this may save a few cycles
-    * transferring data to the kernel.
+    * Note: ensure the buffer is reasonably well-aligned; this may save a few
+    * cycles transferring data to the kernel.
     */
-   zbuffer = (char *) palloc0(XLOG_BLCKSZ);
+   zbuffer = (char *) MAXALIGN(zbuffer_raw);
+   memset(zbuffer, 0, BLCKSZ);
    for (nbytes = 0; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
    {
        errno = 0;
@@ -2530,7 +2531,6 @@ XLogFileInit(uint32 log, uint32 seg,
                     errmsg("could not write to file \"%s\": %m", tmppath)));
        }
    }
-   pfree(zbuffer);
 
    if (pg_fsync(fd) != 0)
        ereport(ERROR,
index 90a731cc3ae6855b62a67ef60c9d0dd447c8c768..4d7e46a3b2cbabd6889456ca92aa2ad3abe8ca0b 100644 (file)
@@ -15,6 +15,7 @@
 #include "postgres.h"
 
 #include "access/htup.h"
+#include "access/itup.h"
 
 
 /* ----------------------------------------------------------------
@@ -362,8 +363,6 @@ PageRepairFragmentation(Page page)
    Offset      pd_lower = ((PageHeader) page)->pd_lower;
    Offset      pd_upper = ((PageHeader) page)->pd_upper;
    Offset      pd_special = ((PageHeader) page)->pd_special;
-   itemIdSort  itemidbase,
-               itemidptr;
    ItemId      lp;
    int         nline,
                nstorage,
@@ -413,10 +412,11 @@ PageRepairFragmentation(Page page)
        ((PageHeader) page)->pd_upper = pd_special;
    }
    else
-   {                           /* nstorage != 0 */
+   {
        /* Need to compact the page the hard way */
-       itemidbase = (itemIdSort) palloc(sizeof(itemIdSortData) * nstorage);
-       itemidptr = itemidbase;
+       itemIdSortData itemidbase[MaxHeapTuplesPerPage];
+       itemIdSort  itemidptr = itemidbase;
+
        totallen = 0;
        for (i = 0; i < nline; i++)
        {
@@ -461,8 +461,6 @@ PageRepairFragmentation(Page page)
        }
 
        ((PageHeader) page)->pd_upper = upper;
-
-       pfree(itemidbase);
    }
 
    /* Set hint bit for PageAddItem */
@@ -711,8 +709,8 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
    Offset      pd_lower = phdr->pd_lower;
    Offset      pd_upper = phdr->pd_upper;
    Offset      pd_special = phdr->pd_special;
-   itemIdSort  itemidbase,
-               itemidptr;
+   itemIdSortData  itemidbase[MaxIndexTuplesPerPage];
+   itemIdSort  itemidptr;
    ItemId      lp;
    int         nline,
                nused;
@@ -724,6 +722,8 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
    int         nextitm;
    OffsetNumber offnum;
 
+   Assert(nitems < MaxIndexTuplesPerPage);
+
    /*
     * If there aren't very many items to delete, then retail
     * PageIndexTupleDelete is the best way.  Delete the items in reverse
@@ -758,7 +758,6 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
     * still validity-checking.
     */
    nline = PageGetMaxOffsetNumber(page);
-   itemidbase = (itemIdSort) palloc(sizeof(itemIdSortData) * nline);
    itemidptr = itemidbase;
    totallen = 0;
    nused = 0;
@@ -824,6 +823,4 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
 
    phdr->pd_lower = SizeOfPageHeaderData + nused * sizeof(ItemIdData);
    phdr->pd_upper = upper;
-
-   pfree(itemidbase);
 }