1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-23 03:21:12 +03:00

Fix problem reported by Alex Korn: if a relation has been dropped and

recreated since the start of our transaction, our first reference to it
errored out because we'd try to reuse our old relcache entry for it.
Do this by accepting SI inval messages just before relcache search in
heap_openr, so that dead relcache entries will be flushed before we
search.  Also, break heap_open/openr into two pairs of routines,
relation_open(r) and heap_open(r).  The relation_open routines make
no tests on relkind and so can be used to open anything that has a
pg_class entry.  The heap_open routines are wrappers that add a relkind
test to preserve their established behavior.  Use the relation_open
routines in several places that had various kluge solutions for opening
rels that might be either heap or index rels.

Also, remove the old 'heap stats' code that's been superseded by Jan's
stats collector, and clean up some inconsistencies in error reporting
between the different types of ALTER TABLE.
This commit is contained in:
Tom Lane
2001-11-02 16:30:29 +00:00
parent 5d4b94085e
commit 7d05310828
14 changed files with 164 additions and 608 deletions

View File

@ -4,7 +4,7 @@
# Makefile for access/heap
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/access/heap/Makefile,v 1.11 2000/08/31 16:09:33 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/access/heap/Makefile,v 1.12 2001/11/02 16:30:29 tgl Exp $
#
#-------------------------------------------------------------------------
@ -12,7 +12,7 @@ subdir = src/backend/access/heap
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = heapam.o hio.o stats.o tuptoaster.o
OBJS = heapam.o hio.o tuptoaster.o
all: SUBSYS.o

View File

@ -8,14 +8,16 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.126 2001/10/25 05:49:21 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.127 2001/11/02 16:30:29 tgl Exp $
*
*
* INTERFACE ROUTINES
* heap_open - open a heap relation by relationId
* relation_open - open any relation by relation OID
* relation_openr - open any relation by name
* relation_close - close any relation
* heap_open - open a heap relation by relation OID
* heap_openr - open a heap relation by name
* heap_open[r]_nofail - same, but return NULL on failure instead of elog
* heap_close - close a heap relation
* heap_close - (now just a macro for relation_close)
* heap_beginscan - begin relation scan
* heap_rescan - restart a relation scan
* heap_endscan - end relation scan
@ -440,15 +442,21 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
*/
/* ----------------
* heap_open - open a heap relation by relationId
* relation_open - open any relation by relation OID
*
* If lockmode is not "NoLock", the specified kind of lock is
* obtained on the relation.
* obtained on the relation. (Generally, NoLock should only be
* used if the caller knows it has some appropriate lock on the
* relation already.)
*
* An error is raised if the relation does not exist.
*
* NB: a "relation" is anything with a pg_class entry. The caller is
* expected to check whether the relkind is something it can handle.
* ----------------
*/
Relation
heap_open(Oid relationId, LOCKMODE lockmode)
relation_open(Oid relationId, LOCKMODE lockmode)
{
Relation r;
@ -466,10 +474,6 @@ heap_open(Oid relationId, LOCKMODE lockmode)
if (!RelationIsValid(r))
elog(ERROR, "Relation %u does not exist", relationId);
/* Under no circumstances will we return an index as a relation. */
if (r->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
if (lockmode != NoLock)
LockRelation(r, lockmode);
@ -477,15 +481,13 @@ heap_open(Oid relationId, LOCKMODE lockmode)
}
/* ----------------
* heap_openr - open a heap relation by name
* relation_openr - open any relation by name
*
* If lockmode is not "NoLock", the specified kind of lock is
* obtained on the relation.
* An error is raised if the relation does not exist.
* As above, but lookup by name instead of OID.
* ----------------
*/
Relation
heap_openr(const char *relationName, LOCKMODE lockmode)
relation_openr(const char *relationName, LOCKMODE lockmode)
{
Relation r;
@ -497,102 +499,44 @@ heap_openr(const char *relationName, LOCKMODE lockmode)
IncrHeapAccessStat(local_openr);
IncrHeapAccessStat(global_openr);
/*
* Check for shared-cache-inval messages before trying to open the
* relation. This is needed to cover the case where the name identifies
* a rel that has been dropped and recreated since the start of our
* transaction: if we don't flush the old relcache entry then we'll
* latch onto that entry and suffer an error when we do LockRelation.
* Note that relation_open does not need to do this, since a relation's
* OID never changes.
*
* We skip this if asked for NoLock, on the assumption that the caller
* has already ensured some appropriate lock is held.
*/
if (lockmode != NoLock)
AcceptInvalidationMessages();
/* The relcache does all the real work... */
r = RelationNameGetRelation(relationName);
if (!RelationIsValid(r))
elog(ERROR, "Relation '%s' does not exist", relationName);
/* Under no circumstances will we return an index as a relation. */
if (r->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
elog(ERROR, "Relation \"%s\" does not exist", relationName);
if (lockmode != NoLock)
LockRelation(r, lockmode);
pgstat_initstats(&r->pgstat_info, r);
pgstat_initstats(&r->pgstat_info, r);
return r;
}
/* ----------------
* heap_open_nofail - open a heap relation by relationId,
* do not raise error on failure
*
* The caller must check for a NULL return value indicating
* that no such relation exists.
* No lock is obtained on the relation, either.
* ----------------
*/
Relation
heap_open_nofail(Oid relationId)
{
Relation r;
/*
* increment access statistics
*/
IncrHeapAccessStat(local_open);
IncrHeapAccessStat(global_open);
/* The relcache does all the real work... */
r = RelationIdGetRelation(relationId);
/* Under no circumstances will we return an index as a relation. */
if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
return r;
}
/* ----------------
* heap_openr_nofail - open a heap relation by name,
* do not raise error on failure
*
* The caller must check for a NULL return value indicating
* that no such relation exists.
* No lock is obtained on the relation, either.
* ----------------
*/
Relation
heap_openr_nofail(const char *relationName)
{
Relation r;
/*
* increment access statistics
*/
IncrHeapAccessStat(local_openr);
IncrHeapAccessStat(global_openr);
/* The relcache does all the real work... */
r = RelationNameGetRelation(relationName);
/* Under no circumstances will we return an index as a relation. */
if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
if (RelationIsValid(r))
pgstat_initstats(&r->pgstat_info, r);
if (RelationIsValid(r))
pgstat_initstats(&r->pgstat_info, r);
return r;
}
/* ----------------
* heap_close - close a heap relation
* relation_close - close any relation
*
* If lockmode is not "NoLock", we first release the specified lock.
* Note that it is often sensible to hold a lock beyond heap_close;
*
* Note that it is often sensible to hold a lock beyond relation_close;
* in that case, the lock is released automatically at xact end.
* ----------------
*/
void
heap_close(Relation relation, LOCKMODE lockmode)
relation_close(Relation relation, LOCKMODE lockmode)
{
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
@ -610,6 +554,59 @@ heap_close(Relation relation, LOCKMODE lockmode)
}
/* ----------------
* heap_open - open a heap relation by relation OID
*
* This is essentially relation_open plus check that the relation
* is not an index or special relation. (The caller should also check
* that it's not a view before assuming it has storage.)
* ----------------
*/
Relation
heap_open(Oid relationId, LOCKMODE lockmode)
{
Relation r;
r = relation_open(relationId, lockmode);
if (r->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "%s is an index relation",
RelationGetRelationName(r));
else if (r->rd_rel->relkind == RELKIND_SPECIAL)
elog(ERROR, "%s is a special relation",
RelationGetRelationName(r));
pgstat_initstats(&r->pgstat_info, r);
return r;
}
/* ----------------
* heap_openr - open a heap relation by name
*
* As above, but lookup by name instead of OID.
* ----------------
*/
Relation
heap_openr(const char *relationName, LOCKMODE lockmode)
{
Relation r;
r = relation_openr(relationName, lockmode);
if (r->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "%s is an index relation",
RelationGetRelationName(r));
else if (r->rd_rel->relkind == RELKIND_SPECIAL)
elog(ERROR, "%s is a special relation",
RelationGetRelationName(r));
pgstat_initstats(&r->pgstat_info, r);
return r;
}
/* ----------------
* heap_beginscan - begin relation scan
* ----------------
@ -2332,8 +2329,7 @@ newsame:;
}
/* undo */
if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied
* ?! */
if (XLByteLT(PageGetLSN(page), lsn)) /* changes not applied?! */
elog(STOP, "heap_update_undo: bad new tuple page LSN");
elog(STOP, "heap_update_undo: unimplemented");

View File

@ -1,333 +0,0 @@
/*-------------------------------------------------------------------------
*
* stats.c
* heap access method debugging statistic collection routines
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.25 2001/10/25 05:49:21 momjian Exp $
*
* NOTES
* initam should be moved someplace else.
*
*-------------------------------------------------------------------------
*/
#include <time.h>
#include "postgres.h"
#include "access/heapam.h"
static void InitHeapAccessStatistics(void);
/* ----------------
* InitHeapAccessStatistics
* ----------------
*/
HeapAccessStatistics heap_access_stats = (HeapAccessStatistics) NULL;
static void
InitHeapAccessStatistics()
{
MemoryContext oldContext;
HeapAccessStatistics stats;
/*
* make sure we don't initialize things twice
*/
if (heap_access_stats != NULL)
return;
/*
* allocate statistics structure from the top memory context
*/
oldContext = MemoryContextSwitchTo(TopMemoryContext);
stats = (HeapAccessStatistics)
palloc(sizeof(HeapAccessStatisticsData));
/*
* initialize fields to default values
*/
stats->global_open = 0;
stats->global_openr = 0;
stats->global_close = 0;
stats->global_beginscan = 0;
stats->global_rescan = 0;
stats->global_endscan = 0;
stats->global_getnext = 0;
stats->global_fetch = 0;
stats->global_insert = 0;
stats->global_delete = 0;
stats->global_replace = 0;
stats->global_mark4update = 0;
stats->global_markpos = 0;
stats->global_restrpos = 0;
stats->global_BufferGetRelation = 0;
stats->global_RelationIdGetRelation = 0;
stats->global_RelationIdGetRelation_Buf = 0;
stats->global_getreldesc = 0;
stats->global_heapgettup = 0;
stats->global_RelationPutHeapTuple = 0;
stats->global_RelationPutLongHeapTuple = 0;
stats->local_open = 0;
stats->local_openr = 0;
stats->local_close = 0;
stats->local_beginscan = 0;
stats->local_rescan = 0;
stats->local_endscan = 0;
stats->local_getnext = 0;
stats->local_fetch = 0;
stats->local_insert = 0;
stats->local_delete = 0;
stats->local_replace = 0;
stats->local_mark4update = 0;
stats->local_markpos = 0;
stats->local_restrpos = 0;
stats->local_BufferGetRelation = 0;
stats->local_RelationIdGetRelation = 0;
stats->local_RelationIdGetRelation_Buf = 0;
stats->local_getreldesc = 0;
stats->local_heapgettup = 0;
stats->local_RelationPutHeapTuple = 0;
stats->local_RelationPutLongHeapTuple = 0;
stats->local_RelationNameGetRelation = 0;
stats->global_RelationNameGetRelation = 0;
/*
* record init times
*/
time(&stats->init_global_timestamp);
time(&stats->local_reset_timestamp);
time(&stats->last_request_timestamp);
/*
* return to old memory context
*/
MemoryContextSwitchTo(oldContext);
heap_access_stats = stats;
}
#ifdef NOT_USED
/* ----------------
* ResetHeapAccessStatistics
* ----------------
*/
void
ResetHeapAccessStatistics()
{
HeapAccessStatistics stats;
/*
* do nothing if stats aren't initialized
*/
if (heap_access_stats == NULL)
return;
stats = heap_access_stats;
/*
* reset local counts
*/
stats->local_open = 0;
stats->local_openr = 0;
stats->local_close = 0;
stats->local_beginscan = 0;
stats->local_rescan = 0;
stats->local_endscan = 0;
stats->local_getnext = 0;
stats->local_fetch = 0;
stats->local_insert = 0;
stats->local_delete = 0;
stats->local_replace = 0;
stats->local_mark4update = 0;
stats->local_markpos = 0;
stats->local_restrpos = 0;
stats->local_BufferGetRelation = 0;
stats->local_RelationIdGetRelation = 0;
stats->local_RelationIdGetRelation_Buf = 0;
stats->local_getreldesc = 0;
stats->local_heapgettup = 0;
stats->local_RelationPutHeapTuple = 0;
stats->local_RelationPutLongHeapTuple = 0;
/*
* reset local timestamps
*/
time(&stats->local_reset_timestamp);
time(&stats->last_request_timestamp);
}
#endif
#ifdef NOT_USED
/* ----------------
* GetHeapAccessStatistics
* ----------------
*/
HeapAccessStatistics
GetHeapAccessStatistics()
{
HeapAccessStatistics stats;
/*
* return nothing if stats aren't initialized
*/
if (heap_access_stats == NULL)
return NULL;
/*
* record the current request time
*/
time(&heap_access_stats->last_request_timestamp);
/*
* allocate a copy of the stats and return it to the caller.
*/
stats = (HeapAccessStatistics)
palloc(sizeof(HeapAccessStatisticsData));
memmove(stats,
heap_access_stats,
sizeof(HeapAccessStatisticsData));
return stats;
}
#endif
#ifdef NOT_USED
/* ----------------
* PrintHeapAccessStatistics
* ----------------
*/
void
PrintHeapAccessStatistics(HeapAccessStatistics stats)
{
/*
* return nothing if stats aren't valid
*/
if (stats == NULL)
return;
printf("======== heap am statistics ========\n");
printf("init_global_timestamp: %s",
ctime(&(stats->init_global_timestamp)));
printf("local_reset_timestamp: %s",
ctime(&(stats->local_reset_timestamp)));
printf("last_request_timestamp: %s",
ctime(&(stats->last_request_timestamp)));
printf("local/global_open: %6d/%6d\n",
stats->local_open, stats->global_open);
printf("local/global_openr: %6d/%6d\n",
stats->local_openr, stats->global_openr);
printf("local/global_close: %6d/%6d\n",
stats->local_close, stats->global_close);
printf("local/global_beginscan: %6d/%6d\n",
stats->local_beginscan, stats->global_beginscan);
printf("local/global_rescan: %6d/%6d\n",
stats->local_rescan, stats->global_rescan);
printf("local/global_endscan: %6d/%6d\n",
stats->local_endscan, stats->global_endscan);
printf("local/global_getnext: %6d/%6d\n",
stats->local_getnext, stats->global_getnext);
printf("local/global_fetch: %6d/%6d\n",
stats->local_fetch, stats->global_fetch);
printf("local/global_insert: %6d/%6d\n",
stats->local_insert, stats->global_insert);
printf("local/global_delete: %6d/%6d\n",
stats->local_delete, stats->global_delete);
printf("local/global_replace: %6d/%6d\n",
stats->local_replace, stats->global_replace);
printf("local/global_mark4update: %6d/%6d\n",
stats->local_mark4update, stats->global_mark4update);
printf("local/global_markpos: %6d/%6d\n",
stats->local_markpos, stats->global_markpos);
printf("local/global_restrpos: %6d/%6d\n",
stats->local_restrpos, stats->global_restrpos);
printf("================\n");
printf("local/global_BufferGetRelation: %6d/%6d\n",
stats->local_BufferGetRelation,
stats->global_BufferGetRelation);
printf("local/global_RelationIdGetRelation: %6d/%6d\n",
stats->local_RelationIdGetRelation,
stats->global_RelationIdGetRelation);
printf("local/global_RelationIdGetRelation_Buf: %6d/%6d\n",
stats->local_RelationIdGetRelation_Buf,
stats->global_RelationIdGetRelation_Buf);
printf("local/global_getreldesc: %6d/%6d\n",
stats->local_getreldesc, stats->global_getreldesc);
printf("local/global_heapgettup: %6d/%6d\n",
stats->local_heapgettup, stats->global_heapgettup);
printf("local/global_RelationPutHeapTuple: %6d/%6d\n",
stats->local_RelationPutHeapTuple,
stats->global_RelationPutHeapTuple);
printf("local/global_RelationPutLongHeapTuple: %6d/%6d\n",
stats->local_RelationPutLongHeapTuple,
stats->global_RelationPutLongHeapTuple);
printf("===================================\n");
printf("\n");
}
#endif
#ifdef NOT_USED
/* ----------------
* PrintAndFreeHeapAccessStatistics
* ----------------
*/
void
PrintAndFreeHeapAccessStatistics(HeapAccessStatistics stats)
{
PrintHeapAccessStatistics(stats);
if (stats != NULL)
pfree(stats);
}
#endif
/* ----------------------------------------------------------------
* access method initialization
* ----------------------------------------------------------------
*/
/* ----------------
* initam should someday be moved someplace else.
* ----------------
*/
void
initam(void)
{
/*
* initialize heap statistics.
*/
InitHeapAccessStatistics();
}