1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* hashscan.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* manage scans on hash tables
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2003-08-04 04:40:20 +02:00
|
|
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2003-08-04 04:40:20 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.30 2003/08/04 02:39:57 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
1997-09-07 07:04:48 +02:00
|
|
|
* Because we can be doing an index scan on a relation while we
|
|
|
|
* update it, we need to avoid missing data that moves around in
|
|
|
|
* the index. The routines and global variables in this file
|
|
|
|
* guarantee that all scans in the local address space stay
|
|
|
|
* correctly positioned. This is all we need to worry about, since
|
|
|
|
* write locking guarantees that no one else will be on the same
|
|
|
|
* page at the same time as we are.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* The scheme is to manage a list of active scans in the current
|
|
|
|
* backend. Whenever we add or remove records from an index, we
|
|
|
|
* check the list of active scans to see if any has been affected.
|
|
|
|
* A scan is affected only if it is on the same relation, and the
|
|
|
|
* same page, as the update.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "access/hash.h"
|
1996-10-21 07:45:21 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
typedef struct HashScanListData
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
IndexScanDesc hashsl_scan;
|
1997-09-07 07:04:48 +02:00
|
|
|
struct HashScanListData *hashsl_next;
|
1997-09-08 23:56:23 +02:00
|
|
|
} HashScanListData;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
typedef HashScanListData *HashScanList;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
static HashScanList HashScans = (HashScanList) NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
2002-05-24 20:57:57 +02:00
|
|
|
static void _hash_scandel(IndexScanDesc scan,
|
2002-09-04 22:31:48 +02:00
|
|
|
BlockNumber blkno, OffsetNumber offno);
|
2002-05-24 20:57:57 +02:00
|
|
|
|
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/*
|
|
|
|
* AtEOXact_hash() --- clean up hash subsystem at xact abort or commit.
|
|
|
|
*
|
|
|
|
* This is here because it needs to touch this module's static var HashScans.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
AtEOXact_hash(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Note: these actions should only be necessary during xact abort; but
|
|
|
|
* they can't hurt during a commit.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset the active-scans list to empty. We do not need to free the
|
|
|
|
* list elements, because they're all palloc()'d, so they'll go away
|
|
|
|
* at end of transaction anyway.
|
|
|
|
*/
|
|
|
|
HashScans = NULL;
|
|
|
|
|
|
|
|
/* If we were building a hash, we ain't anymore. */
|
|
|
|
BuildingHash = false;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* _Hash_regscan() -- register a new scan.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
_hash_regscan(IndexScanDesc scan)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HashScanList new_el;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
new_el = (HashScanList) palloc(sizeof(HashScanListData));
|
|
|
|
new_el->hashsl_scan = scan;
|
|
|
|
new_el->hashsl_next = HashScans;
|
|
|
|
HashScans = new_el;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* _hash_dropscan() -- drop a scan from the scan list
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
_hash_dropscan(IndexScanDesc scan)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HashScanList chk,
|
|
|
|
last;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
last = (HashScanList) NULL;
|
|
|
|
for (chk = HashScans;
|
|
|
|
chk != (HashScanList) NULL && chk->hashsl_scan != scan;
|
|
|
|
chk = chk->hashsl_next)
|
|
|
|
last = chk;
|
|
|
|
|
|
|
|
if (chk == (HashScanList) NULL)
|
2000-04-12 19:17:23 +02:00
|
|
|
elog(ERROR, "hash scan list trashed; can't find 0x%p", (void *) scan);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (last == (HashScanList) NULL)
|
|
|
|
HashScans = chk->hashsl_next;
|
|
|
|
else
|
|
|
|
last->hashsl_next = chk->hashsl_next;
|
|
|
|
|
|
|
|
pfree(chk);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_hash_adjscans(Relation rel, ItemPointer tid)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HashScanList l;
|
|
|
|
Oid relid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
relid = RelationGetRelid(rel);
|
1997-09-07 07:04:48 +02:00
|
|
|
for (l = HashScans; l != (HashScanList) NULL; l = l->hashsl_next)
|
|
|
|
{
|
2002-05-21 01:51:44 +02:00
|
|
|
if (relid == l->hashsl_scan->indexRelation->rd_id)
|
1997-09-07 07:04:48 +02:00
|
|
|
_hash_scandel(l->hashsl_scan, ItemPointerGetBlockNumber(tid),
|
|
|
|
ItemPointerGetOffsetNumber(tid));
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
ItemPointer current;
|
2002-05-24 20:57:57 +02:00
|
|
|
ItemPointer mark;
|
1997-09-08 04:41:22 +02:00
|
|
|
Buffer buf;
|
|
|
|
Buffer metabuf;
|
|
|
|
HashScanOpaque so;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
so = (HashScanOpaque) scan->opaque;
|
|
|
|
current = &(scan->currentItemData);
|
2002-05-24 20:57:57 +02:00
|
|
|
mark = &(scan->currentMarkData);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (ItemPointerIsValid(current)
|
|
|
|
&& ItemPointerGetBlockNumber(current) == blkno
|
|
|
|
&& ItemPointerGetOffsetNumber(current) >= offno)
|
|
|
|
{
|
2002-05-24 20:57:57 +02:00
|
|
|
metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
|
|
|
|
buf = so->hashso_curbuf;
|
1997-09-07 07:04:48 +02:00
|
|
|
_hash_step(scan, &buf, BackwardScanDirection, metabuf);
|
|
|
|
}
|
|
|
|
|
2002-05-24 20:57:57 +02:00
|
|
|
if (ItemPointerIsValid(mark)
|
|
|
|
&& ItemPointerGetBlockNumber(mark) == blkno
|
|
|
|
&& ItemPointerGetOffsetNumber(mark) >= offno)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-24 20:57:57 +02:00
|
|
|
/*
|
|
|
|
* The idea here is to exchange the current and mark positions,
|
|
|
|
* then step backwards (affecting current), then exchange again.
|
|
|
|
*/
|
|
|
|
ItemPointerData tmpitem;
|
2002-09-04 22:31:48 +02:00
|
|
|
Buffer tmpbuf;
|
2002-05-24 20:57:57 +02:00
|
|
|
|
|
|
|
tmpitem = *mark;
|
|
|
|
*mark = *current;
|
|
|
|
*current = tmpitem;
|
|
|
|
tmpbuf = so->hashso_mrkbuf;
|
|
|
|
so->hashso_mrkbuf = so->hashso_curbuf;
|
|
|
|
so->hashso_curbuf = tmpbuf;
|
|
|
|
|
|
|
|
metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
|
|
|
|
buf = so->hashso_curbuf;
|
1997-09-07 07:04:48 +02:00
|
|
|
_hash_step(scan, &buf, BackwardScanDirection, metabuf);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2002-05-24 20:57:57 +02:00
|
|
|
tmpitem = *mark;
|
|
|
|
*mark = *current;
|
|
|
|
*current = tmpitem;
|
|
|
|
tmpbuf = so->hashso_mrkbuf;
|
|
|
|
so->hashso_mrkbuf = so->hashso_curbuf;
|
|
|
|
so->hashso_curbuf = tmpbuf;
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|