|
|
|
|
@ -8,7 +8,7 @@ |
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California |
|
|
|
|
* |
|
|
|
|
* IDENTIFICATION |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.62 2006/03/05 15:58:20 momjian Exp $ |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.63 2006/04/03 13:44:33 teodor Exp $ |
|
|
|
|
* |
|
|
|
|
*------------------------------------------------------------------------- |
|
|
|
|
*/ |
|
|
|
|
@ -20,37 +20,8 @@ |
|
|
|
|
#include "utils/memutils.h" |
|
|
|
|
#include "utils/resowner.h" |
|
|
|
|
|
|
|
|
|
/* routines defined and used here */ |
|
|
|
|
static void gistregscan(IndexScanDesc scan); |
|
|
|
|
static void gistdropscan(IndexScanDesc scan); |
|
|
|
|
static void gistadjone(IndexScanDesc scan, int op, BlockNumber blkno, |
|
|
|
|
OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn); |
|
|
|
|
static void adjustiptr(IndexScanDesc scan, ItemPointer iptr, GISTSearchStack *stk, |
|
|
|
|
int op, BlockNumber blkno, OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn); |
|
|
|
|
static void gistfreestack(GISTSearchStack *s); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Whenever we start a GiST scan in a backend, we register it in |
|
|
|
|
* private space. Then if the GiST index gets updated, we check all |
|
|
|
|
* registered scans and adjust them if the tuple they point at got |
|
|
|
|
* moved by the update. We only need to do this in private space, |
|
|
|
|
* because when we update an GiST we have a write lock on the tree, so |
|
|
|
|
* no other process can have any locks at all on it. A single |
|
|
|
|
* transaction can have write and read locks on the same object, so |
|
|
|
|
* that's why we need to handle this case. |
|
|
|
|
*/ |
|
|
|
|
typedef struct GISTScanListData |
|
|
|
|
{ |
|
|
|
|
IndexScanDesc gsl_scan; |
|
|
|
|
ResourceOwner gsl_owner; |
|
|
|
|
struct GISTScanListData *gsl_next; |
|
|
|
|
} GISTScanListData; |
|
|
|
|
|
|
|
|
|
typedef GISTScanListData *GISTScanList; |
|
|
|
|
|
|
|
|
|
/* pointer to list of local scans on GiSTs */ |
|
|
|
|
static GISTScanList GISTScans = NULL; |
|
|
|
|
|
|
|
|
|
Datum |
|
|
|
|
gistbeginscan(PG_FUNCTION_ARGS) |
|
|
|
|
{ |
|
|
|
|
@ -60,7 +31,6 @@ gistbeginscan(PG_FUNCTION_ARGS) |
|
|
|
|
IndexScanDesc scan; |
|
|
|
|
|
|
|
|
|
scan = RelationGetIndexScan(r, nkeys, key); |
|
|
|
|
gistregscan(scan); |
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(scan); |
|
|
|
|
} |
|
|
|
|
@ -254,189 +224,17 @@ gistendscan(PG_FUNCTION_ARGS) |
|
|
|
|
pfree(scan->opaque); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gistdropscan(scan); |
|
|
|
|
|
|
|
|
|
PG_RETURN_VOID(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
gistregscan(IndexScanDesc scan) |
|
|
|
|
{ |
|
|
|
|
GISTScanList l; |
|
|
|
|
|
|
|
|
|
l = (GISTScanList) palloc(sizeof(GISTScanListData)); |
|
|
|
|
l->gsl_scan = scan; |
|
|
|
|
l->gsl_owner = CurrentResourceOwner; |
|
|
|
|
l->gsl_next = GISTScans; |
|
|
|
|
GISTScans = l; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
gistdropscan(IndexScanDesc scan) |
|
|
|
|
{ |
|
|
|
|
GISTScanList l; |
|
|
|
|
GISTScanList prev; |
|
|
|
|
|
|
|
|
|
prev = NULL; |
|
|
|
|
|
|
|
|
|
for (l = GISTScans; l != NULL && l->gsl_scan != scan; l = l->gsl_next) |
|
|
|
|
prev = l; |
|
|
|
|
|
|
|
|
|
if (l == NULL) |
|
|
|
|
elog(ERROR, "GiST scan list corrupted -- could not find 0x%p", |
|
|
|
|
(void *) scan); |
|
|
|
|
|
|
|
|
|
if (prev == NULL) |
|
|
|
|
GISTScans = l->gsl_next; |
|
|
|
|
else |
|
|
|
|
prev->gsl_next = l->gsl_next; |
|
|
|
|
|
|
|
|
|
pfree(l); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ReleaseResources_gist() --- clean up gist subsystem resources. |
|
|
|
|
* |
|
|
|
|
* This is here because it needs to touch this module's static var GISTScans. |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
ReleaseResources_gist(void) |
|
|
|
|
{ |
|
|
|
|
GISTScanList l; |
|
|
|
|
GISTScanList prev; |
|
|
|
|
GISTScanList next; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note: this should be a no-op during normal query shutdown. However, in |
|
|
|
|
* an abort situation ExecutorEnd is not called and so there may be open |
|
|
|
|
* index scans to clean up. |
|
|
|
|
*/ |
|
|
|
|
prev = NULL; |
|
|
|
|
|
|
|
|
|
for (l = GISTScans; l != NULL; l = next) |
|
|
|
|
{ |
|
|
|
|
next = l->gsl_next; |
|
|
|
|
if (l->gsl_owner == CurrentResourceOwner) |
|
|
|
|
{ |
|
|
|
|
if (prev == NULL) |
|
|
|
|
GISTScans = next; |
|
|
|
|
else |
|
|
|
|
prev->gsl_next = next; |
|
|
|
|
|
|
|
|
|
pfree(l); |
|
|
|
|
/* prev does not change */ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
prev = l; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
gistadjscans(Relation rel, int op, BlockNumber blkno, OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn) |
|
|
|
|
{ |
|
|
|
|
GISTScanList l; |
|
|
|
|
Oid relid; |
|
|
|
|
|
|
|
|
|
if (XLogRecPtrIsInvalid(newlsn) || XLogRecPtrIsInvalid(oldlsn)) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
relid = RelationGetRelid(rel); |
|
|
|
|
for (l = GISTScans; l != NULL; l = l->gsl_next) |
|
|
|
|
{ |
|
|
|
|
if (l->gsl_scan->indexRelation->rd_id == relid) |
|
|
|
|
gistadjone(l->gsl_scan, op, blkno, offnum, newlsn, oldlsn); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* gistadjone() -- adjust one scan for update. |
|
|
|
|
* |
|
|
|
|
* By here, the scan passed in is on a modified relation. Op tells |
|
|
|
|
* us what the modification is, and blkno and offind tell us what |
|
|
|
|
* block and offset index were affected. This routine checks the |
|
|
|
|
* current and marked positions, and the current and marked stacks, |
|
|
|
|
* to see if any stored location needs to be changed because of the |
|
|
|
|
* update. If so, we make the change here. |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
gistadjone(IndexScanDesc scan, |
|
|
|
|
int op, |
|
|
|
|
BlockNumber blkno, |
|
|
|
|
OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn) |
|
|
|
|
{ |
|
|
|
|
GISTScanOpaque so = (GISTScanOpaque) scan->opaque; |
|
|
|
|
|
|
|
|
|
adjustiptr(scan, &(scan->currentItemData), so->stack, op, blkno, offnum, newlsn, oldlsn); |
|
|
|
|
adjustiptr(scan, &(scan->currentMarkData), so->markstk, op, blkno, offnum, newlsn, oldlsn); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* adjustiptr() -- adjust current and marked item pointers in the scan |
|
|
|
|
* |
|
|
|
|
* Depending on the type of update and the place it happened, we |
|
|
|
|
* need to do nothing, to back up one record, or to start over on |
|
|
|
|
* the same page. |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
adjustiptr(IndexScanDesc scan, |
|
|
|
|
ItemPointer iptr, GISTSearchStack *stk, |
|
|
|
|
int op, |
|
|
|
|
BlockNumber blkno, |
|
|
|
|
OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn) |
|
|
|
|
{ |
|
|
|
|
OffsetNumber curoff; |
|
|
|
|
GISTScanOpaque so; |
|
|
|
|
|
|
|
|
|
if (ItemPointerIsValid(iptr)) |
|
|
|
|
{ |
|
|
|
|
if (ItemPointerGetBlockNumber(iptr) == blkno) |
|
|
|
|
{ |
|
|
|
|
curoff = ItemPointerGetOffsetNumber(iptr); |
|
|
|
|
so = (GISTScanOpaque) scan->opaque; |
|
|
|
|
|
|
|
|
|
switch (op) |
|
|
|
|
{ |
|
|
|
|
case GISTOP_DEL: |
|
|
|
|
/* back up one if we need to */ |
|
|
|
|
if (curoff >= offnum && XLByteEQ(stk->lsn, oldlsn)) /* the same vesrion of
|
|
|
|
|
* page */ |
|
|
|
|
{ |
|
|
|
|
if (curoff > FirstOffsetNumber) |
|
|
|
|
{ |
|
|
|
|
/* just adjust the item pointer */ |
|
|
|
|
ItemPointerSet(iptr, blkno, OffsetNumberPrev(curoff)); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
* remember that we're before the current tuple |
|
|
|
|
*/ |
|
|
|
|
ItemPointerSet(iptr, blkno, FirstOffsetNumber); |
|
|
|
|
if (iptr == &(scan->currentItemData)) |
|
|
|
|
so->flags |= GS_CURBEFORE; |
|
|
|
|
else |
|
|
|
|
so->flags |= GS_MRKBEFORE; |
|
|
|
|
} |
|
|
|
|
stk->lsn = newlsn; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
elog(ERROR, "unrecognized GiST scan adjust operation: %d", |
|
|
|
|
op); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
gistfreestack(GISTSearchStack *s) |
|
|
|
|
{ |
|
|
|
|
{
|
|
|
|
|
while (s != NULL) |
|
|
|
|
{ |
|
|
|
|
GISTSearchStack *p = s->next; |
|
|
|
|
|
|
|
|
|
pfree(s); |
|
|
|
|
s = p; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|