*** postgresql-9.2.2/src/backend/access/heap/heapam.c 2012-12-03 12:16:10.000000000 -0800 --- postgresql-9.2.2dg/src/backend/access/heap/heapam.c 2012-12-12 01:55:58.174653706 -0800 *************** *** 2158,2163 **** --- 2158,2164 ---- Buffer buffer; Buffer vmbuffer = InvalidBuffer; bool all_visible_cleared = false; + bool page_is_empty; int nthispage; /* *************** *** 2173,2299 **** START_CRIT_SECTION(); /* Put as many tuples as fit on this page */ for (nthispage = 0; ndone + nthispage < ntuples; nthispage++) { HeapTuple heaptup = heaptuples[ndone + nthispage]; ! if (PageGetHeapFreeSpace(page) < MAXALIGN(heaptup->t_len) + saveFreeSpace) break; ! RelationPutHeapTuple(relation, buffer, heaptup); } - if (PageIsAllVisible(page)) - { - all_visible_cleared = true; - PageClearAllVisible(page); - visibilitymap_clear(relation, - BufferGetBlockNumber(buffer), - vmbuffer); - } - /* ! * XXX Should we set PageSetPrunable on this page ? See heap_insert() */ ! ! MarkBufferDirty(buffer); ! ! /* XLOG stuff */ ! if (needwal) { ! XLogRecPtr recptr; ! xl_heap_multi_insert *xlrec; ! XLogRecData rdata[2]; ! uint8 info = XLOG_HEAP2_MULTI_INSERT; ! char *tupledata; ! int totaldatalen; ! char *scratchptr = scratch; ! bool init; /* ! * If the page was previously empty, we can reinit the page ! * instead of restoring the whole thing. */ - init = (ItemPointerGetOffsetNumber(&(heaptuples[ndone]->t_self)) == FirstOffsetNumber && - PageGetMaxOffsetNumber(page) == FirstOffsetNumber + nthispage - 1); ! /* allocate xl_heap_multi_insert struct from the scratch area */ ! xlrec = (xl_heap_multi_insert *) scratchptr; ! scratchptr += SizeOfHeapMultiInsert; ! /* ! * Allocate offsets array. Unless we're reinitializing the page, ! * in that case the tuples are stored in order starting at ! * FirstOffsetNumber and we don't need to store the offsets ! * explicitly. ! */ ! if (!init) ! scratchptr += nthispage * sizeof(OffsetNumber); ! /* the rest of the scratch space is used for tuple data */ ! tupledata = scratchptr; ! xlrec->all_visible_cleared = all_visible_cleared; ! xlrec->node = relation->rd_node; ! xlrec->blkno = BufferGetBlockNumber(buffer); ! xlrec->ntuples = nthispage; ! ! /* ! * Write out an xl_multi_insert_tuple and the tuple data itself ! * for each tuple. ! */ ! for (i = 0; i < nthispage; i++) ! { ! HeapTuple heaptup = heaptuples[ndone + i]; ! xl_multi_insert_tuple *tuphdr; ! int datalen; if (!init) ! xlrec->offsets[i] = ItemPointerGetOffsetNumber(&heaptup->t_self); ! /* xl_multi_insert_tuple needs two-byte alignment. */ ! tuphdr = (xl_multi_insert_tuple *) SHORTALIGN(scratchptr); ! scratchptr = ((char *) tuphdr) + SizeOfMultiInsertTuple; ! ! tuphdr->t_infomask2 = heaptup->t_data->t_infomask2; ! tuphdr->t_infomask = heaptup->t_data->t_infomask; ! tuphdr->t_hoff = heaptup->t_data->t_hoff; ! ! /* write bitmap [+ padding] [+ oid] + data */ ! datalen = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits); ! memcpy(scratchptr, ! (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits), ! datalen); ! tuphdr->datalen = datalen; ! scratchptr += datalen; ! } ! totaldatalen = scratchptr - tupledata; ! Assert((scratchptr - scratch) < BLCKSZ); ! rdata[0].data = (char *) xlrec; ! rdata[0].len = tupledata - scratch; ! rdata[0].buffer = InvalidBuffer; ! rdata[0].next = &rdata[1]; ! ! rdata[1].data = tupledata; ! rdata[1].len = totaldatalen; ! rdata[1].buffer = buffer; ! rdata[1].buffer_std = true; ! rdata[1].next = NULL; ! /* ! * If we're going to reinitialize the whole page using the WAL ! * record, hide buffer reference from XLogInsert. ! */ ! if (init) ! { ! rdata[1].buffer = InvalidBuffer; ! info |= XLOG_HEAP_INIT_PAGE; ! } ! recptr = XLogInsert(RM_HEAP2_ID, info, rdata); ! PageSetLSN(page, recptr); ! PageSetTLI(page, ThisTimeLineID); } END_CRIT_SECTION(); --- 2174,2309 ---- START_CRIT_SECTION(); /* Put as many tuples as fit on this page */ + page_is_empty = PageGetMaxOffsetNumber(page) == 0; for (nthispage = 0; ndone + nthispage < ntuples; nthispage++) { HeapTuple heaptup = heaptuples[ndone + nthispage]; ! if (PageGetHeapFreeSpace(page) < ! MAXALIGN(heaptup->t_len) + (page_is_empty ? 0 : saveFreeSpace)) break; ! page_is_empty = false; RelationPutHeapTuple(relation, buffer, heaptup); } /* ! * If nthispage > 0 then we modified the (possibly new) page, ! * otherwise there was not enough space for even one new tuple. */ ! if (nthispage > 0) { ! if (PageIsAllVisible(page)) ! { ! all_visible_cleared = true; ! PageClearAllVisible(page); ! visibilitymap_clear(relation, ! BufferGetBlockNumber(buffer), ! vmbuffer); ! } /* ! * XXX Should we set PageSetPrunable on this page ? See heap_insert() */ ! MarkBufferDirty(buffer); ! /* XLOG stuff */ ! if (needwal) ! { ! XLogRecPtr recptr; ! xl_heap_multi_insert *xlrec; ! XLogRecData rdata[2]; ! uint8 info = XLOG_HEAP2_MULTI_INSERT; ! char *tupledata; ! int totaldatalen; ! char *scratchptr = scratch; ! bool init; ! /* ! * If the page was previously empty, we can reinit the page ! * instead of restoring the whole thing. ! */ ! init = (ItemPointerGetOffsetNumber(&(heaptuples[ndone]->t_self)) == FirstOffsetNumber && ! PageGetMaxOffsetNumber(page) == FirstOffsetNumber + nthispage - 1); ! /* allocate xl_heap_multi_insert struct from the scratch area */ ! xlrec = (xl_heap_multi_insert *) scratchptr; ! scratchptr += SizeOfHeapMultiInsert; + /* + * Allocate offsets array. Unless we're reinitializing the page, + * in that case the tuples are stored in order starting at + * FirstOffsetNumber and we don't need to store the offsets + * explicitly. + */ if (!init) ! scratchptr += nthispage * sizeof(OffsetNumber); ! /* the rest of the scratch space is used for tuple data */ ! tupledata = scratchptr; ! xlrec->all_visible_cleared = all_visible_cleared; ! xlrec->node = relation->rd_node; ! xlrec->blkno = BufferGetBlockNumber(buffer); ! xlrec->ntuples = nthispage; ! /* ! * Write out an xl_multi_insert_tuple and the tuple data itself ! * for each tuple. ! */ ! for (i = 0; i < nthispage; i++) ! { ! HeapTuple heaptup = heaptuples[ndone + i]; ! xl_multi_insert_tuple *tuphdr; ! int datalen; ! ! if (!init) ! xlrec->offsets[i] = ItemPointerGetOffsetNumber(&heaptup->t_self); ! /* xl_multi_insert_tuple needs two-byte alignment. */ ! tuphdr = (xl_multi_insert_tuple *) SHORTALIGN(scratchptr); ! scratchptr = ((char *) tuphdr) + SizeOfMultiInsertTuple; ! ! tuphdr->t_infomask2 = heaptup->t_data->t_infomask2; ! tuphdr->t_infomask = heaptup->t_data->t_infomask; ! tuphdr->t_hoff = heaptup->t_data->t_hoff; ! ! /* write bitmap [+ padding] [+ oid] + data */ ! datalen = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits); ! memcpy(scratchptr, ! (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits), ! datalen); ! tuphdr->datalen = datalen; ! scratchptr += datalen; ! } ! totaldatalen = scratchptr - tupledata; ! Assert((scratchptr - scratch) < BLCKSZ); ! ! rdata[0].data = (char *) xlrec; ! rdata[0].len = tupledata - scratch; ! rdata[0].buffer = InvalidBuffer; ! rdata[0].next = &rdata[1]; ! ! rdata[1].data = tupledata; ! rdata[1].len = totaldatalen; ! rdata[1].buffer = buffer; ! rdata[1].buffer_std = true; ! rdata[1].next = NULL; ! ! /* ! * If we're going to reinitialize the whole page using the WAL ! * record, hide buffer reference from XLogInsert. ! */ ! if (init) ! { ! rdata[1].buffer = InvalidBuffer; ! info |= XLOG_HEAP_INIT_PAGE; ! } ! ! recptr = XLogInsert(RM_HEAP2_ID, info, rdata); ! PageSetLSN(page, recptr); ! PageSetTLI(page, ThisTimeLineID); ! } } END_CRIT_SECTION(); *************** *** 2304,2310 **** ndone += nthispage; } - /* * If tuples are cachable, mark them for invalidation from the caches in * case we abort. Note it is OK to do this after releasing the buffer, --- 2314,2319 ----