Re: A little COPY speedup - Mailing list pgsql-patches
From | Heikki Linnakangas |
---|---|
Subject | Re: A little COPY speedup |
Date | |
Msg-id | 45E75182.8040502@enterprisedb.com Whole thread Raw |
In response to | Re: A little COPY speedup (Heikki Linnakangas <heikki@enterprisedb.com>) |
Responses |
Re: A little COPY speedup
|
List | pgsql-patches |
Heikki Linnakangas wrote: > Tom Lane wrote: >> I'm not sure whether I like your flag approach better than the >> last-used-offset one. The previous patch probably buys some teeny >> amount more performance, but the flag seems more robust (noting in >> passing that neither patch attempts to WAL-log its changes, so we really >> need to treat the values as hints). And a change as sketched here would >> leave us 15 free bits for future expansion, which might be nice. > > I'll post a patch along those lines. Here it is. I'm not fond of the macro names for the flag, but couldn't think of anything shorter yet descriptive. -- Heikki Linnakangas EnterpriseDB http://www.enterprisedb.com Index: src/backend/access/heap/heapam.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/heap/heapam.c,v retrieving revision 1.228 diff -c -r1.228 heapam.c *** src/backend/access/heap/heapam.c 9 Feb 2007 03:35:33 -0000 1.228 --- src/backend/access/heap/heapam.c 1 Mar 2007 21:29:14 -0000 *************** *** 3327,3332 **** --- 3327,3335 ---- PageRepairFragmentation(page, NULL); + /* clear the hint flag since we just freed some line pointers */ + HeapPageClearNoFreeLinePointers(page); + PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); Index: src/backend/access/heap/hio.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/heap/hio.c,v retrieving revision 1.65 diff -c -r1.65 hio.c *** src/backend/access/heap/hio.c 5 Feb 2007 04:22:18 -0000 1.65 --- src/backend/access/heap/hio.c 1 Mar 2007 21:33:14 -0000 *************** *** 33,51 **** HeapTuple tuple) { Page pageHeader; ! OffsetNumber offnum; ItemId itemId; Item item; - /* Add the tuple to the page */ pageHeader = BufferGetPage(buffer); offnum = PageAddItem(pageHeader, (Item) tuple->t_data, ! tuple->t_len, InvalidOffsetNumber, LP_USED); if (offnum == InvalidOffsetNumber) elog(PANIC, "failed to add tuple to page"); /* Update tuple->t_self to the actual position where it was stored */ ItemPointerSet(&(tuple->t_self), BufferGetBlockNumber(buffer), offnum); --- 33,65 ---- HeapTuple tuple) { Page pageHeader; ! OffsetNumber offnum, maxoff; ItemId itemId; Item item; pageHeader = BufferGetPage(buffer); + maxoff = PageGetMaxOffsetNumber(pageHeader); + + /* If we know there's no free line pointers, don't waste cycles + * searching for one. We'll set the flag to save work for future + * inserts when that happens. + */ + if(HeapPageNoFreeLinePointers(pageHeader)) + offnum = OffsetNumberNext(maxoff); + else + offnum = InvalidOffsetNumber; + + /* Add the tuple to the page */ offnum = PageAddItem(pageHeader, (Item) tuple->t_data, ! tuple->t_len, offnum, LP_USED); if (offnum == InvalidOffsetNumber) elog(PANIC, "failed to add tuple to page"); + if(offnum > maxoff) + HeapPageSetNoFreeLinePointers(pageHeader); + /* Update tuple->t_self to the actual position where it was stored */ ItemPointerSet(&(tuple->t_self), BufferGetBlockNumber(buffer), offnum); Index: src/backend/commands/vacuum.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/commands/vacuum.c,v retrieving revision 1.346 diff -c -r1.346 vacuum.c *** src/backend/commands/vacuum.c 15 Feb 2007 23:23:22 -0000 1.346 --- src/backend/commands/vacuum.c 1 Mar 2007 21:41:20 -0000 *************** *** 2453,2458 **** --- 2453,2460 ---- START_CRIT_SECTION(); uncnt = PageRepairFragmentation(page, unused); + if(uncnt > 0) + HeapPageClearNoFreeLinePointers(page); MarkBufferDirty(buf); *************** *** 2920,2925 **** --- 2922,2929 ---- } uncnt = PageRepairFragmentation(page, unused); + if(uncnt > 0) + HeapPageClearNoFreeLinePointers(page); MarkBufferDirty(buffer); Index: src/backend/commands/vacuumlazy.c =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/commands/vacuumlazy.c,v retrieving revision 1.85 diff -c -r1.85 vacuumlazy.c *** src/backend/commands/vacuumlazy.c 21 Feb 2007 22:47:45 -0000 1.85 --- src/backend/commands/vacuumlazy.c 1 Mar 2007 21:27:15 -0000 *************** *** 605,610 **** --- 605,612 ---- } uncnt = PageRepairFragmentation(page, unused); + if(uncnt > 0) + HeapPageClearNoFreeLinePointers(page); MarkBufferDirty(buffer); Index: src/include/access/htup.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/access/htup.h,v retrieving revision 1.92 diff -c -r1.92 htup.h *** src/include/access/htup.h 27 Feb 2007 23:48:09 -0000 1.92 --- src/include/access/htup.h 1 Mar 2007 22:13:25 -0000 *************** *** 17,22 **** --- 17,42 ---- #include "storage/itemptr.h" #include "storage/relfilenode.h" + /* We use the pd_amprivate field in the page header to store flags. + * At the moment, there's just one flag. + */ + + /* HP_NOFREELINEPOINTERS flag should be set as a hint when there definitely + * isn't any free line pointers left on the page. However, absence of the + * flag doesn't necessarily mean that there is a free line pointer. + */ + #define HP_NOFREELINEPOINTERS (1 << 0) + + #define HeapPageNoFreeLinePointers(page) \ + (((PageHeader)page)->pd_amprivate & HP_NOFREELINEPOINTERS) + + #define HeapPageSetNoFreeLinePointers(page) \ + (((PageHeader)page)->pd_amprivate |= HP_NOFREELINEPOINTERS) + + #define HeapPageClearNoFreeLinePointers(page) \ + (((PageHeader)page)->pd_amprivate &= ~HP_NOFREELINEPOINTERS) + + /* * MaxTupleAttributeNumber limits the number of (user) columns in a tuple. * The key limit on this value is that the size of the fixed overhead for Index: src/include/storage/bufpage.h =================================================================== RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/storage/bufpage.h,v retrieving revision 1.71 diff -c -r1.71 bufpage.h *** src/include/storage/bufpage.h 21 Feb 2007 20:02:17 -0000 1.71 --- src/include/storage/bufpage.h 1 Mar 2007 22:14:37 -0000 *************** *** 68,74 **** * space"; each AM has an "opaque" structure defined somewhere that is * stored as the page trailer. an access method should always * initialize its pages with PageInit and then set its own opaque ! * fields. */ typedef Pointer Page; --- 68,76 ---- * space"; each AM has an "opaque" structure defined somewhere that is * stored as the page trailer. an access method should always * initialize its pages with PageInit and then set its own opaque ! * fields. In addition to the special space, there's a 16-bit ! * pd_amprivate field in the page header itself reserved for AM-specific ! * use. */ typedef Pointer Page; *************** *** 90,95 **** --- 92,98 ---- * * pd_lsn - identifies xlog record for last change to this page. * pd_tli - ditto. + * pd_amprivate - reserved for AM-specific use * pd_lower - offset to start of free space. * pd_upper - offset to end of free space. * pd_special - offset to start of special space. *************** *** 98,105 **** * The LSN is used by the buffer manager to enforce the basic rule of WAL: * "thou shalt write xlog before data". A dirty buffer cannot be dumped * to disk until xlog has been flushed at least as far as the page's LSN. ! * We also store the TLI for identification purposes (it is not clear that ! * this is actually necessary, but it seems like a good idea). * * The page version number and page size are packed together into a single * uint16 field. This is for historical reasons: before PostgreSQL 7.3, --- 101,109 ---- * The LSN is used by the buffer manager to enforce the basic rule of WAL: * "thou shalt write xlog before data". A dirty buffer cannot be dumped * to disk until xlog has been flushed at least as far as the page's LSN. ! * We also store the 16 least significant bits of the TLI for identification ! * purposes (it is not clear that this is actually necessary, but it seems ! * like a good idea). * * The page version number and page size are packed together into a single * uint16 field. This is for historical reasons: before PostgreSQL 7.3, *************** *** 119,125 **** /* XXX LSN is member of *any* block, not only page-organized ones */ XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog * record for last change to this page */ ! TimeLineID pd_tli; /* TLI of last change */ LocationIndex pd_lower; /* offset to start of free space */ LocationIndex pd_upper; /* offset to end of free space */ LocationIndex pd_special; /* offset to start of special space */ --- 123,131 ---- /* XXX LSN is member of *any* block, not only page-organized ones */ XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog * record for last change to this page */ ! uint16 pd_tli; /* least significant bits of the TLI ! * corresponding the LSN. */ ! uint16 pd_amprivate; /* am-specific information */ LocationIndex pd_lower; /* offset to start of free space */ LocationIndex pd_upper; /* offset to end of free space */ LocationIndex pd_special; /* offset to start of special space */ *************** *** 304,313 **** #define PageSetLSN(page, lsn) \ (((PageHeader) (page))->pd_lsn = (lsn)) #define PageGetTLI(page) \ (((PageHeader) (page))->pd_tli) #define PageSetTLI(page, tli) \ ! (((PageHeader) (page))->pd_tli = (tli)) /* ---------------------------------------------------------------- * extern declarations --- 310,320 ---- #define PageSetLSN(page, lsn) \ (((PageHeader) (page))->pd_lsn = (lsn)) + /* NOTE: only the 16 least significant bits are stored */ #define PageGetTLI(page) \ (((PageHeader) (page))->pd_tli) #define PageSetTLI(page, tli) \ ! (((PageHeader) (page))->pd_tli = (tli) & 0x0000FFFF) /* ---------------------------------------------------------------- * extern declarations
pgsql-patches by date: