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 ,
4749 IndexTuple * tuples , int32 ntuples , BlockNumber rightlink )
4850{
4951 Page page = BufferGetPage (buffer );
50- int i ,
52+ int32 i ,
5153 freesize ,
5254 size = 0 ;
5355 OffsetNumber l ,
@@ -100,8 +102,6 @@ writeListPage(Relation index, Buffer buffer,
100102 GinPageGetOpaque (page )-> maxoff = 0 ;
101103 }
102104
103- freesize = PageGetFreeSpace (page );
104-
105105 MarkBufferDirty (buffer );
106106
107107 if (!index -> rd_istemp )
@@ -110,26 +110,30 @@ writeListPage(Relation index, Buffer buffer,
110110 ginxlogInsertListPage data ;
111111 XLogRecPtr 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 ;
115119 rdata [0 ].data = (char * ) & data ;
116120 rdata [0 ].len = sizeof (ginxlogInsertListPage );
117121 rdata [0 ].next = rdata + 1 ;
118122
119- rdata [1 ].buffer = InvalidBuffer ;
123+ rdata [1 ].buffer = buffer ;
124+ rdata [1 ].buffer_std = true;
120125 rdata [1 ].data = workspace ;
121126 rdata [1 ].len = size ;
122127 rdata [1 ].next = NULL ;
123128
124- data .blkno = BufferGetBlockNumber (buffer );
125- data .rightlink = rightlink ;
126- data .ntuples = ntuples ;
127-
128129 recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_INSERT_LISTPAGE , rdata );
129130 PageSetLSN (page , recptr );
130131 PageSetTLI (page , ThisTimeLineID );
131132 }
132133
134+ /* get free space before releasing buffer */
135+ freesize = PageGetExactFreeSpace (page );
136+
133137 UnlockReleaseBuffer (buffer );
134138
135139 END_CRIT_SECTION ();
@@ -165,7 +169,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
165169 {
166170 res -> nPendingPages ++ ;
167171 writeListPage (index , prevBuffer ,
168- tuples + startTuple , i - startTuple ,
172+ tuples + startTuple ,
173+ i - startTuple ,
169174 BufferGetBlockNumber (curBuffer ));
170175 }
171176 else
@@ -180,7 +185,7 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
180185
181186 tupsize = 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 */
186191 i -- ;
@@ -197,7 +202,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
197202 */
198203 res -> tail = BufferGetBlockNumber (curBuffer );
199204 res -> tailFreeSize = writeListPage (index , curBuffer ,
200- tuples + startTuple , ntuples - startTuple ,
205+ tuples + startTuple ,
206+ ntuples - startTuple ,
201207 InvalidBlockNumber );
202208 res -> nPendingPages ++ ;
203209 /* that was only one heap tuple */
@@ -237,7 +243,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
237243 metabuffer = ReadBuffer (index , GIN_METAPAGE_BLKNO );
238244 metapage = 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
266272 if (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 ));
275280 makeSublist (index , collector -> tuples , collector -> ntuples , & sublist );
276281
277282 /*
@@ -283,45 +288,44 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
283288 if (metadata -> head == InvalidBlockNumber )
284289 {
285290 /*
286- * Sublist becomes main list
291+ * Main list is empty, so just copy sublist into main list
287292 */
288293 START_CRIT_SECTION ();
294+
289295 memcpy (metadata , & sublist , sizeof (GinMetaPageData ));
290- memcpy (& data .metadata , & sublist , sizeof (GinMetaPageData ));
291296 }
292297 else
293298 {
294299 /*
295- * merge lists
300+ * Merge lists
296301 */
297-
298302 data .prevTail = metadata -> tail ;
303+ data .newRightlink = sublist .head ;
304+
299305 buffer = ReadBuffer (index , metadata -> tail );
300306 LockBuffer (buffer , GIN_EXCLUSIVE );
301307 page = BufferGetPage (buffer );
308+
302309 Assert (GinPageGetOpaque (page )-> rightlink == InvalidBlockNumber );
303310
304311 START_CRIT_SECTION ();
305312
306313 GinPageGetOpaque (page )-> rightlink = sublist .head ;
314+
315+ MarkBufferDirty (buffer );
316+
307317 metadata -> tail = sublist .tail ;
308318 metadata -> tailFreeSize = sublist .tailFreeSize ;
309319
310320 metadata -> nPendingPages += sublist .nPendingPages ;
311321 metadata -> nPendingHeapTuples += sublist .nPendingHeapTuples ;
312-
313- memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
314- data .newRightlink = sublist .head ;
315-
316- MarkBufferDirty (buffer );
317322 }
318323 }
319324 else
320325 {
321326 /*
322- * Insert into tail page, metapage is already locked
327+ * Insert into tail page. Metapage is already locked
323328 */
324-
325329 OffsetNumber l ,
326330 off ;
327331 int i ,
@@ -331,6 +335,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
331335 buffer = ReadBuffer (index , metadata -> tail );
332336 LockBuffer (buffer , GIN_EXCLUSIVE );
333337 page = BufferGetPage (buffer );
338+
334339 off = (PageIsEmpty (page )) ? FirstOffsetNumber :
335340 OffsetNumberNext (PageGetMaxOffsetNumber (page ));
336341
@@ -368,20 +373,24 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
368373 off ++ ;
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+
373380 MarkBufferDirty (buffer );
374381 }
375382
376383 /*
377- * Make real write
384+ * Write metabuffer, make xlog entry
378385 */
379-
380386 MarkBufferDirty (metabuffer );
387+
381388 if (!index -> rd_istemp )
382389 {
383390 XLogRecPtr recptr ;
384391
392+ memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
393+
385394 recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_UPDATE_META_PAGE , rdata );
386395 PageSetLSN (metapage , recptr );
387396 PageSetTLI (metapage , ThisTimeLineID );
@@ -552,7 +561,6 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
552561 metadata -> nPendingPages = 0 ;
553562 metadata -> nPendingHeapTuples = 0 ;
554563 }
555- memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
556564
557565 MarkBufferDirty (metabuffer );
558566
@@ -567,6 +575,8 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
567575 {
568576 XLogRecPtr recptr ;
569577
578+ memcpy (& data .metadata , metadata , sizeof (GinMetaPageData ));
579+
570580 recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_DELETE_LISTPAGE , rdata );
571581 PageSetLSN (metapage , recptr );
572582 PageSetTLI (metapage , ThisTimeLineID );
0 commit comments