88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.129 2006/03/05 15:58:20 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.130 2006/03/30 23:03:09 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -90,6 +90,7 @@ gistbuild(PG_FUNCTION_ARGS)
9090double reltuples ;
9191GISTBuildState buildstate ;
9292Buffer buffer ;
93+ Page page ;
9394
9495/*
9596 * We expect to be called exactly once for any index relation. If that's
@@ -104,33 +105,33 @@ gistbuild(PG_FUNCTION_ARGS)
104105
105106/* initialize the root page */
106107buffer = gistNewBuffer (index );
108+ Assert (BufferGetBlockNumber (buffer )== GIST_ROOT_BLKNO );
109+ page = BufferGetPage (buffer );
110+
111+ START_CRIT_SECTION ();
112+
107113GISTInitBuffer (buffer ,F_LEAF );
108114if (!index -> rd_istemp )
109115{
110116XLogRecPtr recptr ;
111117XLogRecData rdata ;
112- Page page ;
113118
114- rdata .buffer = InvalidBuffer ;
115119rdata .data = (char * )& (index -> rd_node );
116120rdata .len = sizeof (RelFileNode );
121+ rdata .buffer = InvalidBuffer ;
117122rdata .next = NULL ;
118123
119- page = BufferGetPage (buffer );
120-
121- START_CRIT_SECTION ();
122-
123124recptr = XLogInsert (RM_GIST_ID ,XLOG_GIST_CREATE_INDEX ,& rdata );
124125PageSetLSN (page ,recptr );
125126PageSetTLI (page ,ThisTimeLineID );
126-
127- END_CRIT_SECTION ();
128127}
129128else
130- PageSetLSN (BufferGetPage ( buffer ) ,XLogRecPtrForTemp );
129+ PageSetLSN (page ,XLogRecPtrForTemp );
131130LockBuffer (buffer ,GIST_UNLOCK );
132131WriteBuffer (buffer );
133132
133+ END_CRIT_SECTION ();
134+
134135/* build the index */
135136buildstate .numindexattrs = indexInfo -> ii_NumIndexAttrs ;
136137buildstate .indtuples = 0 ;
@@ -305,13 +306,27 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
305306bool is_splitted = false;
306307bool is_leaf = (GistPageIsLeaf (state -> stack -> page )) ? true : false;
307308
309+ /*
310+ * XXX this code really ought to work by locking, but not modifying,
311+ * all the buffers it needs; then starting a critical section; then
312+ * modifying the buffers in an already-determined way and writing an
313+ * XLOG record to reflect that. Since it doesn't, we've got to put
314+ * a critical section around the entire process, which is horrible
315+ * from a robustness point of view.
316+ */
317+ START_CRIT_SECTION ();
308318
309319if (!is_leaf )
310320
311321/*
312322 * This node's key has been modified, either because a child split
313323 * occurred or because we needed to adjust our key for an insert in a
314324 * child node. Therefore, remove the old version of this node's key.
325+ *
326+ * Note: for WAL replay, in the non-split case we handle this by
327+ * setting up a one-element todelete array; in the split case, it's
328+ * handled implicitly because the tuple vector passed to gistSplit
329+ * won't include this tuple.
315330 */
316331
317332PageIndexTupleDelete (state -> stack -> page ,state -> stack -> childoffnum );
@@ -336,9 +351,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
336351XLogRecData * rdata ;
337352
338353rdata = formSplitRdata (state -> r -> rd_node ,state -> stack -> blkno ,
339- & (state -> key ),dist );
340-
341- START_CRIT_SECTION ();
354+ is_leaf ,& (state -> key ),dist );
342355
343356recptr = XLogInsert (RM_GIST_ID ,XLOG_GIST_PAGE_SPLIT ,rdata );
344357ptr = dist ;
@@ -348,8 +361,6 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
348361PageSetTLI (BufferGetPage (ptr -> buffer ),ThisTimeLineID );
349362ptr = ptr -> next ;
350363}
351-
352- END_CRIT_SECTION ();
353364}
354365else
355366{
@@ -410,7 +421,6 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
410421else
411422ourpage = dist ;
412423
413-
414424/* now gets all needed data, and sets nsn's */
415425page = (Page )BufferGetPage (ourpage -> buffer );
416426opaque = GistPageGetOpaque (page );
@@ -437,8 +447,11 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
437447WriteBuffer (ptr -> buffer );
438448ptr = ptr -> next ;
439449}
450+
451+ WriteNoReleaseBuffer (state -> stack -> buffer );
440452}
441- WriteNoReleaseBuffer (state -> stack -> buffer );
453+
454+ END_CRIT_SECTION ();
442455}
443456else
444457{
@@ -451,7 +464,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
451464if (!state -> r -> rd_istemp )
452465{
453466OffsetNumber noffs = 0 ,
454- offs [MAXALIGN ( sizeof ( OffsetNumber )) / sizeof ( OffsetNumber ) ];
467+ offs [1 ];
455468XLogRecPtr recptr ;
456469XLogRecData * rdata ;
457470
@@ -462,17 +475,14 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
462475noffs = 1 ;
463476}
464477
465- rdata = formUpdateRdata (state -> r -> rd_node ,state -> stack -> blkno ,
466- offs ,noffs , false,state -> itup ,state -> ituplen ,
478+ rdata = formUpdateRdata (state -> r -> rd_node ,state -> stack -> buffer ,
479+ offs ,noffs , false,
480+ state -> itup ,state -> ituplen ,
467481& (state -> key ));
468482
469- START_CRIT_SECTION ();
470-
471- recptr = XLogInsert (RM_GIST_ID ,XLOG_GIST_ENTRY_UPDATE ,rdata );
483+ recptr = XLogInsert (RM_GIST_ID ,XLOG_GIST_PAGE_UPDATE ,rdata );
472484PageSetLSN (state -> stack -> page ,recptr );
473485PageSetTLI (state -> stack -> page ,ThisTimeLineID );
474-
475- END_CRIT_SECTION ();
476486}
477487else
478488PageSetLSN (state -> stack -> page ,XLogRecPtrForTemp );
@@ -481,6 +491,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
481491state -> needInsertComplete = false;
482492WriteNoReleaseBuffer (state -> stack -> buffer );
483493
494+ END_CRIT_SECTION ();
495+
484496if (!is_leaf )/* small optimization: inform scan ablout
485497 * deleting... */
486498gistadjscans (state -> r ,GISTOP_DEL ,state -> stack -> blkno ,
@@ -636,30 +648,14 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
636648}
637649
638650/*
639- * Should have the same interface as XLogReadBuffer
640- */
641- static Buffer
642- gistReadAndLockBuffer (Relation r ,BlockNumber blkno )
643- {
644- Buffer buffer = ReadBuffer (r ,blkno );
645-
646- LockBuffer (buffer ,GIST_SHARE );
647- return buffer ;
648- }
649-
650- /*
651- * Traverse the tree to find path from root page.
651+ * Traverse the tree to find path from root page to specified "child" block.
652652 *
653653 * returns from the begining of closest parent;
654654 *
655- * Function is used in both regular and recovery mode, so must work with
656- * different read functions (gistReadAndLockBuffer and XLogReadBuffer)
657- *
658655 * To prevent deadlocks, this should lock only one page simultaneously.
659656 */
660657GISTInsertStack *
661- gistFindPath (Relation r ,BlockNumber child ,
662- Buffer (* myReadBuffer ) (Relation ,BlockNumber ))
658+ gistFindPath (Relation r ,BlockNumber child )
663659{
664660Page page ;
665661Buffer buffer ;
@@ -677,7 +673,8 @@ gistFindPath(Relation r, BlockNumber child,
677673
678674while (top && top -> blkno != child )
679675{
680- buffer = myReadBuffer (r ,top -> blkno );/* locks buffer */
676+ buffer = ReadBuffer (r ,top -> blkno );
677+ LockBuffer (buffer ,GIST_SHARE );
681678gistcheckpage (r ,buffer );
682679page = (Page )BufferGetPage (buffer );
683680
@@ -833,7 +830,7 @@ gistFindCorrectParent(Relation r, GISTInsertStack *child)
833830}
834831
835832/* ok, find new path */
836- ptr = parent = gistFindPath (r ,child -> blkno , gistReadAndLockBuffer );
833+ ptr = parent = gistFindPath (r ,child -> blkno );
837834Assert (ptr != NULL );
838835
839836/* read all buffers as expected by caller */
@@ -1192,27 +1189,31 @@ gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer ke
11921189
11931190Assert (BufferGetBlockNumber (buffer )== GIST_ROOT_BLKNO );
11941191page = BufferGetPage (buffer );
1195- GISTInitBuffer (buffer ,0 );
11961192
1193+ START_CRIT_SECTION ();
1194+
1195+ GISTInitBuffer (buffer ,0 );/* XXX not F_LEAF? */
11971196gistfillbuffer (r ,page ,itup ,len ,FirstOffsetNumber );
1197+
11981198if (!r -> rd_istemp )
11991199{
12001200XLogRecPtr recptr ;
12011201XLogRecData * rdata ;
12021202
1203- rdata = formUpdateRdata (r -> rd_node ,GIST_ROOT_BLKNO ,
1204- NULL ,0 , false,itup ,len ,key );
1205-
1206- START_CRIT_SECTION ();
1203+ rdata = formUpdateRdata (r -> rd_node ,buffer ,
1204+ NULL ,0 , false,
1205+ itup ,len ,key );
12071206
12081207recptr = XLogInsert (RM_GIST_ID ,XLOG_GIST_NEW_ROOT ,rdata );
12091208PageSetLSN (page ,recptr );
12101209PageSetTLI (page ,ThisTimeLineID );
1211-
1212- END_CRIT_SECTION ();
12131210}
12141211else
12151212PageSetLSN (page ,XLogRecPtrForTemp );
1213+
1214+ WriteNoReleaseBuffer (buffer );
1215+
1216+ END_CRIT_SECTION ();
12161217}
12171218
12181219void