1111 * Portions Copyright (c) 1994, Regents of the University of California
1212 *
1313 * IDENTIFICATION
14- *$PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.3 2009/06/11 14:48:53 momjian Exp $
14+ *$PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.4 2009/09/15 20:31:30 tgl Exp $
1515 *
1616 *-------------------------------------------------------------------------
1717 */
@@ -41,13 +41,15 @@ typedef struct DatumArray
4141
4242/*
4343 * Build a pending-list page from the given array of tuples, and write it out.
44+ *
45+ * Returns amount of free space left on the page.
4446 */
4547static int32
4648writeListPage (Relation index ,Buffer buffer ,
4749IndexTuple * tuples ,int32 ntuples ,BlockNumber rightlink )
4850{
4951Page page = BufferGetPage (buffer );
50- int i ,
52+ int32 i ,
5153freesize ,
5254size = 0 ;
5355OffsetNumber l ,
@@ -100,8 +102,6 @@ writeListPage(Relation index, Buffer buffer,
100102GinPageGetOpaque (page )-> maxoff = 0 ;
101103}
102104
103- freesize = PageGetFreeSpace (page );
104-
105105MarkBufferDirty (buffer );
106106
107107if (!index -> rd_istemp )
@@ -110,26 +110,30 @@ writeListPage(Relation index, Buffer buffer,
110110ginxlogInsertListPage data ;
111111XLogRecPtr recptr ;
112112
113- rdata [0 ].buffer = buffer ;
114- rdata [0 ].buffer_std = true;
113+ data .node = index -> rd_node ;
114+ data .blkno = BufferGetBlockNumber (buffer );
115+ data .rightlink = rightlink ;
116+ data .ntuples = ntuples ;
117+
118+ rdata [0 ].buffer = InvalidBuffer ;
115119rdata [0 ].data = (char * )& data ;
116120rdata [0 ].len = sizeof (ginxlogInsertListPage );
117121rdata [0 ].next = rdata + 1 ;
118122
119- rdata [1 ].buffer = InvalidBuffer ;
123+ rdata [1 ].buffer = buffer ;
124+ rdata [1 ].buffer_std = true;
120125rdata [1 ].data = workspace ;
121126rdata [1 ].len = size ;
122127rdata [1 ].next = NULL ;
123128
124- data .blkno = BufferGetBlockNumber (buffer );
125- data .rightlink = rightlink ;
126- data .ntuples = ntuples ;
127-
128129recptr = XLogInsert (RM_GIN_ID ,XLOG_GIN_INSERT_LISTPAGE ,rdata );
129130PageSetLSN (page ,recptr );
130131PageSetTLI (page ,ThisTimeLineID );
131132}
132133
134+ /* get free space before releasing buffer */
135+ freesize = PageGetExactFreeSpace (page );
136+
133137UnlockReleaseBuffer (buffer );
134138
135139END_CRIT_SECTION ();
@@ -165,7 +169,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
165169{
166170res -> nPendingPages ++ ;
167171writeListPage (index ,prevBuffer ,
168- tuples + startTuple ,i - startTuple ,
172+ tuples + startTuple ,
173+ i - startTuple ,
169174BufferGetBlockNumber (curBuffer ));
170175}
171176else
@@ -180,7 +185,7 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
180185
181186tupsize = MAXALIGN (IndexTupleSize (tuples [i ]))+ sizeof (ItemIdData );
182187
183- if (size + tupsize >= GinListPageSize )
188+ if (size + tupsize > GinListPageSize )
184189{
185190/* won't fit, force a new page and reprocess */
186191i -- ;
@@ -197,7 +202,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
197202 */
198203res -> tail = BufferGetBlockNumber (curBuffer );
199204res -> tailFreeSize = writeListPage (index ,curBuffer ,
200- tuples + startTuple ,ntuples - startTuple ,
205+ tuples + startTuple ,
206+ ntuples - startTuple ,
201207InvalidBlockNumber );
202208res -> nPendingPages ++ ;
203209/* that was only one heap tuple */
@@ -237,7 +243,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
237243metabuffer = ReadBuffer (index ,GIN_METAPAGE_BLKNO );
238244metapage = BufferGetPage (metabuffer );
239245
240- if (collector -> sumsize + collector -> ntuples * sizeof (ItemIdData )> GIN_PAGE_FREESIZE )
246+ if (collector -> sumsize + collector -> ntuples * sizeof (ItemIdData )> GinListPageSize )
241247{
242248/*
243249 * Total size is greater than one page => make sublist
@@ -265,13 +271,12 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
265271
266272if (separateList )
267273{
268- GinMetaPageData sublist ;
269-
270274/*
271275 * We should make sublist separately and append it to the tail
272276 */
273- memset ( & sublist , 0 , sizeof ( GinMetaPageData )) ;
277+ GinMetaPageData sublist ;
274278
279+ memset (& sublist ,0 ,sizeof (GinMetaPageData ));
275280makeSublist (index ,collector -> tuples ,collector -> ntuples ,& sublist );
276281
277282/*
@@ -283,45 +288,44 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
283288if (metadata -> head == InvalidBlockNumber )
284289{
285290/*
286- *Sublist becomes main list
291+ *Main list is empty, so just copy sublist into main list
287292 */
288293START_CRIT_SECTION ();
294+
289295memcpy (metadata ,& sublist ,sizeof (GinMetaPageData ));
290- memcpy (& data .metadata ,& sublist ,sizeof (GinMetaPageData ));
291296}
292297else
293298{
294299/*
295- *merge lists
300+ *Merge lists
296301 */
297-
298302data .prevTail = metadata -> tail ;
303+ data .newRightlink = sublist .head ;
304+
299305buffer = ReadBuffer (index ,metadata -> tail );
300306LockBuffer (buffer ,GIN_EXCLUSIVE );
301307page = BufferGetPage (buffer );
308+
302309Assert (GinPageGetOpaque (page )-> rightlink == InvalidBlockNumber );
303310
304311START_CRIT_SECTION ();
305312
306313GinPageGetOpaque (page )-> rightlink = sublist .head ;
314+
315+ MarkBufferDirty (buffer );
316+
307317metadata -> tail = sublist .tail ;
308318metadata -> tailFreeSize = sublist .tailFreeSize ;
309319
310320metadata -> nPendingPages += sublist .nPendingPages ;
311321metadata -> nPendingHeapTuples += sublist .nPendingHeapTuples ;
312-
313- memcpy (& data .metadata ,metadata ,sizeof (GinMetaPageData ));
314- data .newRightlink = sublist .head ;
315-
316- MarkBufferDirty (buffer );
317322}
318323}
319324else
320325{
321326/*
322- * Insert into tail page, metapage is already locked
327+ * Insert into tail page. Metapage is already locked
323328 */
324-
325329OffsetNumber l ,
326330off ;
327331int i ,
@@ -331,6 +335,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
331335buffer = ReadBuffer (index ,metadata -> tail );
332336LockBuffer (buffer ,GIN_EXCLUSIVE );
333337page = BufferGetPage (buffer );
338+
334339off = (PageIsEmpty (page )) ?FirstOffsetNumber :
335340OffsetNumberNext (PageGetMaxOffsetNumber (page ));
336341
@@ -368,20 +373,24 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
368373off ++ ;
369374}
370375
371- metadata -> tailFreeSize -= collector -> sumsize + collector -> ntuples * sizeof (ItemIdData );
372- memcpy (& data .metadata ,metadata ,sizeof (GinMetaPageData ));
376+ Assert ((ptr - rdata [1 ].data ) <=collector -> sumsize );
377+
378+ metadata -> tailFreeSize = PageGetExactFreeSpace (page );
379+
373380MarkBufferDirty (buffer );
374381}
375382
376383/*
377- *Make real write
384+ *Write metabuffer, make xlog entry
378385 */
379-
380386MarkBufferDirty (metabuffer );
387+
381388if (!index -> rd_istemp )
382389{
383390XLogRecPtr recptr ;
384391
392+ memcpy (& data .metadata ,metadata ,sizeof (GinMetaPageData ));
393+
385394recptr = XLogInsert (RM_GIN_ID ,XLOG_GIN_UPDATE_META_PAGE ,rdata );
386395PageSetLSN (metapage ,recptr );
387396PageSetTLI (metapage ,ThisTimeLineID );
@@ -552,7 +561,6 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
552561metadata -> nPendingPages = 0 ;
553562metadata -> nPendingHeapTuples = 0 ;
554563}
555- memcpy (& data .metadata ,metadata ,sizeof (GinMetaPageData ));
556564
557565MarkBufferDirty (metabuffer );
558566
@@ -567,6 +575,8 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
567575{
568576XLogRecPtr recptr ;
569577
578+ memcpy (& data .metadata ,metadata ,sizeof (GinMetaPageData ));
579+
570580recptr = XLogInsert (RM_GIN_ID ,XLOG_GIN_DELETE_LISTPAGE ,rdata );
571581PageSetLSN (metapage ,recptr );
572582PageSetTLI (metapage ,ThisTimeLineID );