Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7d05310

Browse files
committed
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.
1 parent 5d4b940 commit 7d05310

File tree

14 files changed

+150
-594
lines changed

14 files changed

+150
-594
lines changed

src/backend/access/heap/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
# Makefile for access/heap
55
#
66
# IDENTIFICATION
7-
# $Header: /cvsroot/pgsql/src/backend/access/heap/Makefile,v 1.11 2000/08/31 16:09:33 petere Exp $
7+
# $Header: /cvsroot/pgsql/src/backend/access/heap/Makefile,v 1.12 2001/11/02 16:30:29 tgl Exp $
88
#
99
#-------------------------------------------------------------------------
1010

1111
subdir = src/backend/access/heap
1212
top_builddir = ../../../..
1313
include $(top_builddir)/src/Makefile.global
1414

15-
OBJS = heapam.o hio.o stats.o tuptoaster.o
15+
OBJS = heapam.o hio.o tuptoaster.o
1616

1717
all: SUBSYS.o
1818

src/backend/access/heap/heapam.c

+78-82
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.126 2001/10/25 05:49:21 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.127 2001/11/02 16:30:29 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
15-
* heap_open - open a heap relation by relationId
15+
* relation_open - open any relation by relation OID
16+
* relation_openr - open any relation by name
17+
* relation_close - close any relation
18+
* heap_open - open a heap relation by relation OID
1619
* heap_openr - open a heap relation by name
17-
* heap_open[r]_nofail - same, but return NULL on failure instead of elog
18-
* heap_close - close a heap relation
20+
* heap_close - (now just a macro for relation_close)
1921
* heap_beginscan - begin relation scan
2022
* heap_rescan - restart a relation scan
2123
* heap_endscan - end relation scan
@@ -440,15 +442,21 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
440442
*/
441443

442444
/* ----------------
443-
* heap_open - open a heap relation by relationId
445+
* relation_open - open any relation by relation OID
444446
*
445447
* If lockmode is not "NoLock", the specified kind of lock is
446-
* obtained on the relation.
448+
* obtained on the relation. (Generally, NoLock should only be
449+
* used if the caller knows it has some appropriate lock on the
450+
* relation already.)
451+
*
447452
* An error is raised if the relation does not exist.
453+
*
454+
* NB: a "relation" is anything with a pg_class entry. The caller is
455+
* expected to check whether the relkind is something it can handle.
448456
* ----------------
449457
*/
450458
Relation
451-
heap_open(Oid relationId, LOCKMODE lockmode)
459+
relation_open(Oid relationId, LOCKMODE lockmode)
452460
{
453461
Relation r;
454462

@@ -466,26 +474,20 @@ heap_open(Oid relationId, LOCKMODE lockmode)
466474
if (!RelationIsValid(r))
467475
elog(ERROR, "Relation %u does not exist", relationId);
468476

469-
/* Under no circumstances will we return an index as a relation. */
470-
if (r->rd_rel->relkind == RELKIND_INDEX)
471-
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
472-
473477
if (lockmode != NoLock)
474478
LockRelation(r, lockmode);
475479

476480
return r;
477481
}
478482

479483
/* ----------------
480-
* heap_openr - open a heap relation by name
484+
* relation_openr - open any relation by name
481485
*
482-
* If lockmode is not "NoLock", the specified kind of lock is
483-
* obtained on the relation.
484-
* An error is raised if the relation does not exist.
486+
* As above, but lookup by name instead of OID.
485487
* ----------------
486488
*/
487489
Relation
488-
heap_openr(const char *relationName, LOCKMODE lockmode)
490+
relation_openr(const char *relationName, LOCKMODE lockmode)
489491
{
490492
Relation r;
491493

@@ -497,116 +499,111 @@ heap_openr(const char *relationName, LOCKMODE lockmode)
497499
IncrHeapAccessStat(local_openr);
498500
IncrHeapAccessStat(global_openr);
499501

502+
/*
503+
* Check for shared-cache-inval messages before trying to open the
504+
* relation. This is needed to cover the case where the name identifies
505+
* a rel that has been dropped and recreated since the start of our
506+
* transaction: if we don't flush the old relcache entry then we'll
507+
* latch onto that entry and suffer an error when we do LockRelation.
508+
* Note that relation_open does not need to do this, since a relation's
509+
* OID never changes.
510+
*
511+
* We skip this if asked for NoLock, on the assumption that the caller
512+
* has already ensured some appropriate lock is held.
513+
*/
514+
if (lockmode != NoLock)
515+
AcceptInvalidationMessages();
516+
500517
/* The relcache does all the real work... */
501518
r = RelationNameGetRelation(relationName);
502519

503520
if (!RelationIsValid(r))
504-
elog(ERROR, "Relation '%s' does not exist", relationName);
505-
506-
/* Under no circumstances will we return an index as a relation. */
507-
if (r->rd_rel->relkind == RELKIND_INDEX)
508-
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
521+
elog(ERROR, "Relation \"%s\" does not exist", relationName);
509522

510523
if (lockmode != NoLock)
511524
LockRelation(r, lockmode);
512525

513-
pgstat_initstats(&r->pgstat_info, r);
514-
515-
pgstat_initstats(&r->pgstat_info, r);
516-
517526
return r;
518527
}
519528

520529
/* ----------------
521-
* heap_open_nofail - open a heap relation by relationId,
522-
* do not raise error on failure
530+
* relation_close - close any relation
531+
*
532+
* If lockmode is not "NoLock", we first release the specified lock.
523533
*
524-
* The caller must check for a NULL return value indicating
525-
* that no such relation exists.
526-
* No lock is obtained on the relation, either.
534+
* Note that it is often sensible to hold a lock beyond relation_close;
535+
* in that case, the lock is released automatically at xact end.
527536
* ----------------
528537
*/
529-
Relation
530-
heap_open_nofail(Oid relationId)
538+
void
539+
relation_close(Relation relation, LOCKMODE lockmode)
531540
{
532-
Relation r;
541+
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
533542

534543
/*
535544
* increment access statistics
536545
*/
537-
IncrHeapAccessStat(local_open);
538-
IncrHeapAccessStat(global_open);
539-
540-
/* The relcache does all the real work... */
541-
r = RelationIdGetRelation(relationId);
546+
IncrHeapAccessStat(local_close);
547+
IncrHeapAccessStat(global_close);
542548

543-
/* Under no circumstances will we return an index as a relation. */
544-
if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
545-
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
549+
if (lockmode != NoLock)
550+
UnlockRelation(relation, lockmode);
546551

547-
return r;
552+
/* The relcache does the real work... */
553+
RelationClose(relation);
548554
}
549555

556+
550557
/* ----------------
551-
* heap_openr_nofail - open a heap relation by name,
552-
* do not raise error on failure
558+
* heap_open - open a heap relation by relation OID
553559
*
554-
* The caller must check for a NULL return value indicating
555-
* that no such relation exists.
556-
* No lock is obtained on the relation, either.
560+
* This is essentially relation_open plus check that the relation
561+
* is not an index or special relation. (The caller should also check
562+
* that it's not a view before assuming it has storage.)
557563
* ----------------
558564
*/
559565
Relation
560-
heap_openr_nofail(const char *relationName)
566+
heap_open(Oid relationId, LOCKMODE lockmode)
561567
{
562568
Relation r;
563569

564-
/*
565-
* increment access statistics
566-
*/
567-
IncrHeapAccessStat(local_openr);
568-
IncrHeapAccessStat(global_openr);
570+
r = relation_open(relationId, lockmode);
569571

570-
/* The relcache does all the real work... */
571-
r = RelationNameGetRelation(relationName);
572-
573-
/* Under no circumstances will we return an index as a relation. */
574-
if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
575-
elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
576-
577-
if (RelationIsValid(r))
578-
pgstat_initstats(&r->pgstat_info, r);
572+
if (r->rd_rel->relkind == RELKIND_INDEX)
573+
elog(ERROR, "%s is an index relation",
574+
RelationGetRelationName(r));
575+
else if (r->rd_rel->relkind == RELKIND_SPECIAL)
576+
elog(ERROR, "%s is a special relation",
577+
RelationGetRelationName(r));
579578

580-
if (RelationIsValid(r))
581-
pgstat_initstats(&r->pgstat_info, r);
579+
pgstat_initstats(&r->pgstat_info, r);
582580

583581
return r;
584582
}
585583

586584
/* ----------------
587-
* heap_close - close a heap relation
585+
* heap_openr - open a heap relation by name
588586
*
589-
* If lockmode is not "NoLock", we first release the specified lock.
590-
* Note that it is often sensible to hold a lock beyond heap_close;
591-
* in that case, the lock is released automatically at xact end.
587+
* As above, but lookup by name instead of OID.
592588
* ----------------
593589
*/
594-
void
595-
heap_close(Relation relation, LOCKMODE lockmode)
590+
Relation
591+
heap_openr(const char *relationName, LOCKMODE lockmode)
596592
{
597-
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
593+
Relation r;
598594

599-
/*
600-
* increment access statistics
601-
*/
602-
IncrHeapAccessStat(local_close);
603-
IncrHeapAccessStat(global_close);
595+
r = relation_openr(relationName, lockmode);
604596

605-
if (lockmode != NoLock)
606-
UnlockRelation(relation, lockmode);
597+
if (r->rd_rel->relkind == RELKIND_INDEX)
598+
elog(ERROR, "%s is an index relation",
599+
RelationGetRelationName(r));
600+
else if (r->rd_rel->relkind == RELKIND_SPECIAL)
601+
elog(ERROR, "%s is a special relation",
602+
RelationGetRelationName(r));
607603

608-
/* The relcache does the real work... */
609-
RelationClose(relation);
604+
pgstat_initstats(&r->pgstat_info, r);
605+
606+
return r;
610607
}
611608

612609

@@ -2332,8 +2329,7 @@ newsame:;
23322329
}
23332330

23342331
/* undo */
2335-
if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied
2336-
* ?! */
2332+
if (XLByteLT(PageGetLSN(page), lsn)) /* changes not applied?! */
23372333
elog(STOP, "heap_update_undo: bad new tuple page LSN");
23382334

23392335
elog(STOP, "heap_update_undo: unimplemented");

0 commit comments

Comments
 (0)