mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-17 02:20:31 +02:00
d747140279
provided by Andrew.
154 lines
3.6 KiB
C
154 lines
3.6 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* hashscan.c
|
|
* manage scans on hash tables
|
|
*
|
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.47 2009/06/11 14:48:53 momjian Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "access/hash.h"
|
|
#include "access/relscan.h"
|
|
#include "utils/memutils.h"
|
|
#include "utils/rel.h"
|
|
#include "utils/resowner.h"
|
|
|
|
|
|
/*
|
|
* We track all of a backend's active scans on hash indexes using a list
|
|
* of HashScanListData structs, which are allocated in TopMemoryContext.
|
|
* It's okay to use a long-lived context because we rely on the ResourceOwner
|
|
* mechanism to clean up unused entries after transaction or subtransaction
|
|
* abort. We can't safely keep the entries in the executor's per-query
|
|
* context, because that might be already freed before we get a chance to
|
|
* clean up the list. (XXX seems like there should be a better way to
|
|
* manage this...)
|
|
*/
|
|
typedef struct HashScanListData
|
|
{
|
|
IndexScanDesc hashsl_scan;
|
|
ResourceOwner hashsl_owner;
|
|
struct HashScanListData *hashsl_next;
|
|
} HashScanListData;
|
|
|
|
typedef HashScanListData *HashScanList;
|
|
|
|
static HashScanList HashScans = NULL;
|
|
|
|
|
|
/*
|
|
* ReleaseResources_hash() --- clean up hash subsystem resources.
|
|
*
|
|
* This is here because it needs to touch this module's static var HashScans.
|
|
*/
|
|
void
|
|
ReleaseResources_hash(void)
|
|
{
|
|
HashScanList l;
|
|
HashScanList prev;
|
|
HashScanList next;
|
|
|
|
/*
|
|
* Release all HashScanList items belonging to the current ResourceOwner.
|
|
* Note that we do not release the underlying IndexScanDesc; that's in
|
|
* executor memory and will go away on its own (in fact quite possibly has
|
|
* gone away already, so we mustn't try to touch it here).
|
|
*
|
|
* 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 = HashScans; l != NULL; l = next)
|
|
{
|
|
next = l->hashsl_next;
|
|
if (l->hashsl_owner == CurrentResourceOwner)
|
|
{
|
|
if (prev == NULL)
|
|
HashScans = next;
|
|
else
|
|
prev->hashsl_next = next;
|
|
|
|
pfree(l);
|
|
/* prev does not change */
|
|
}
|
|
else
|
|
prev = l;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* _hash_regscan() -- register a new scan.
|
|
*/
|
|
void
|
|
_hash_regscan(IndexScanDesc scan)
|
|
{
|
|
HashScanList new_el;
|
|
|
|
new_el = (HashScanList) MemoryContextAlloc(TopMemoryContext,
|
|
sizeof(HashScanListData));
|
|
new_el->hashsl_scan = scan;
|
|
new_el->hashsl_owner = CurrentResourceOwner;
|
|
new_el->hashsl_next = HashScans;
|
|
HashScans = new_el;
|
|
}
|
|
|
|
/*
|
|
* _hash_dropscan() -- drop a scan from the scan list
|
|
*/
|
|
void
|
|
_hash_dropscan(IndexScanDesc scan)
|
|
{
|
|
HashScanList chk,
|
|
last;
|
|
|
|
last = NULL;
|
|
for (chk = HashScans;
|
|
chk != NULL && chk->hashsl_scan != scan;
|
|
chk = chk->hashsl_next)
|
|
last = chk;
|
|
|
|
if (chk == NULL)
|
|
elog(ERROR, "hash scan list trashed; cannot find 0x%p", (void *) scan);
|
|
|
|
if (last == NULL)
|
|
HashScans = chk->hashsl_next;
|
|
else
|
|
last->hashsl_next = chk->hashsl_next;
|
|
|
|
pfree(chk);
|
|
}
|
|
|
|
/*
|
|
* Is there an active scan in this bucket?
|
|
*/
|
|
bool
|
|
_hash_has_active_scan(Relation rel, Bucket bucket)
|
|
{
|
|
Oid relid = RelationGetRelid(rel);
|
|
HashScanList l;
|
|
|
|
for (l = HashScans; l != NULL; l = l->hashsl_next)
|
|
{
|
|
if (relid == l->hashsl_scan->indexRelation->rd_id)
|
|
{
|
|
HashScanOpaque so = (HashScanOpaque) l->hashsl_scan->opaque;
|
|
|
|
if (so->hashso_bucket_valid &&
|
|
so->hashso_bucket == bucket)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|