diff options
| author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2010-11-16 11:02:11 +0200 | 
|---|---|---|
| committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2010-11-16 11:32:02 +0200 | 
| commit | 821bb177227be9287f8fd50c2398c7bc5c3929e3 (patch) | |
| tree | 8b52493d0fd23f6013b23c102093fe811d993852 /src/backend/access/gist | |
| parent | e086197aaa8de484dafcb1cc991640980e252d70 (diff) | |
The GiST scan algorithm uses LSNs to detect concurrent pages splits, but
temporary indexes are not WAL-logged. We used a constant LSN for temporary
indexes, on the assumption that we don't need to worry about concurrent page
splits in temporary indexes because they're only visible to the current
session. But that assumption is wrong, it's possible to insert rows and
split pages in the same session, while a scan is in progress. For example,
by opening a cursor and fetching some rows, and INSERTing new rows before
fetching some more.
Fix by generating fake increasing LSNs, used in place of real LSNs in
temporary GiST indexes.
Diffstat (limited to 'src/backend/access/gist')
| -rw-r--r-- | src/backend/access/gist/gist.c | 10 | ||||
| -rw-r--r-- | src/backend/access/gist/gistutil.c | 21 | ||||
| -rw-r--r-- | src/backend/access/gist/gistvacuum.c | 2 | 
3 files changed, 26 insertions, 7 deletions
| diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index cec08c72267..4a5d4bf6f10 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -22,8 +22,6 @@  #include "storage/indexfsm.h"  #include "utils/memutils.h" -const XLogRecPtr XLogRecPtrForTemp = {1, 1}; -  /* Working state for gistbuild and its callback */  typedef struct  { @@ -132,7 +130,7 @@ gistbuild(PG_FUNCTION_ARGS)  		PageSetTLI(page, ThisTimeLineID);  	}  	else -		PageSetLSN(page, XLogRecPtrForTemp); +		PageSetLSN(page, GetXLogRecPtrForTemp());  	UnlockReleaseBuffer(buffer); @@ -423,7 +421,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)  		{  			for (ptr = dist; ptr; ptr = ptr->next)  			{ -				PageSetLSN(ptr->page, XLogRecPtrForTemp); +				PageSetLSN(ptr->page, GetXLogRecPtrForTemp());  			}  		} @@ -491,7 +489,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)  			PageSetTLI(state->stack->page, ThisTimeLineID);  		}  		else -			PageSetLSN(state->stack->page, XLogRecPtrForTemp); +			PageSetLSN(state->stack->page, GetXLogRecPtrForTemp());  		if (state->stack->blkno == GIST_ROOT_BLKNO)  			state->needInsertComplete = false; @@ -1027,7 +1025,7 @@ gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer ke  		PageSetTLI(page, ThisTimeLineID);  	}  	else -		PageSetLSN(page, XLogRecPtrForTemp); +		PageSetLSN(page, GetXLogRecPtrForTemp());  	END_CRIT_SECTION();  } diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 03c5773d4d3..a23047642fd 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -677,3 +677,24 @@ gistoptions(PG_FUNCTION_ARGS)  		PG_RETURN_BYTEA_P(result);  	PG_RETURN_NULL();  } + +/* + * Temporary GiST indexes are not WAL-logged, but we need LSNs to detect + * concurrent page splits anyway. GetXLogRecPtrForTemp() provides a fake + * sequence of LSNs for that purpose. Each call generates an LSN that is + * greater than any previous value returned by this function in the same + * session. + */ +XLogRecPtr +GetXLogRecPtrForTemp(void) +{ +	static XLogRecPtr counter = {0, 1}; + +	counter.xrecoff++; +	if (counter.xrecoff == 0) +	{ +		counter.xlogid++; +		counter.xrecoff++; +	} +	return counter; +} diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index abd3d999565..33f7c8c76ae 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -268,7 +268,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)  					pfree(rdata);  				}  				else -					PageSetLSN(page, XLogRecPtrForTemp); +					PageSetLSN(page, GetXLogRecPtrForTemp());  				END_CRIT_SECTION();  			} | 
