Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions

hashscan.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;
}

Generated by  Doxygen 1.6.0   Back to index