aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/relcache.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-02-03 01:14:17 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2010-02-03 01:14:17 +0000
commit70a2b05a59c02464e36d8c9bf23d2eef8502eccd (patch)
tree367ea4f6b3285ec31e88868276f27524fc495674 /src/backend/utils/cache/relcache.c
parentab7c49c98811f539db9294c8f2d1a15380e025f6 (diff)
downloadpostgresql-70a2b05a59c02464e36d8c9bf23d2eef8502eccd.tar.gz
postgresql-70a2b05a59c02464e36d8c9bf23d2eef8502eccd.zip
Assorted cleanups in preparation for using a map file to support altering
the relfilenode of currently-not-relocatable system catalogs. 1. Get rid of inval.c's dependency on relfilenode, by not having it emit smgr invalidations as a result of relcache flushes. Instead, smgr sinval messages are sent directly from smgr.c when an actual relation delete or truncate is done. This makes considerably more structural sense and allows elimination of a large number of useless smgr inval messages that were formerly sent even in cases where nothing was changing at the physical-relation level. Note that this reintroduces the concept of nontransactional inval messages, but that's okay --- because the messages are sent by smgr.c, they will be sent in Hot Standby slaves, just from a lower logical level than before. 2. Move setNewRelfilenode out of catalog/index.c, where it never logically belonged, into relcache.c; which is a somewhat debatable choice as well but better than before. (I considered catalog/storage.c, but that seemed too low level.) Rename to RelationSetNewRelfilenode. 3. Cosmetic cleanups of some other relfilenode manipulations.
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r--src/backend/utils/cache/relcache.c123
1 files changed, 106 insertions, 17 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 30a32d17f9a..ba09331aba9 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.300 2010/01/13 23:07:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.301 2010/02/03 01:14:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,6 +33,7 @@
#include "access/genam.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
+#include "access/transam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/index.h"
@@ -53,6 +54,7 @@
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/schemapg.h"
+#include "catalog/storage.h"
#include "commands/trigger.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
@@ -2377,22 +2379,6 @@ AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
}
}
-/*
- * RelationCacheMarkNewRelfilenode
- *
- * Mark the rel as having been given a new relfilenode in the current
- * (sub) transaction. This is a hint that can be used to optimize
- * later operations on the rel in the same transaction.
- */
-void
-RelationCacheMarkNewRelfilenode(Relation rel)
-{
- /* Mark it... */
- rel->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
- /* ... and now we have eoxact cleanup work to do */
- need_eoxact_work = true;
-}
-
/*
* RelationBuildLocalRelation
@@ -2562,6 +2548,109 @@ RelationBuildLocalRelation(const char *relname,
return rel;
}
+
+/*
+ * RelationSetNewRelfilenode
+ *
+ * Assign a new relfilenode (physical file name) to the relation.
+ *
+ * This allows a full rewrite of the relation to be done with transactional
+ * safety (since the filenode assignment can be rolled back). Note however
+ * that there is no simple way to access the relation's old data for the
+ * remainder of the current transaction. This limits the usefulness to cases
+ * such as TRUNCATE or rebuilding an index from scratch.
+ *
+ * Caller must already hold exclusive lock on the relation.
+ *
+ * The relation is marked with relfrozenxid = freezeXid (InvalidTransactionId
+ * must be passed for indexes). This should be a lower bound on the XIDs
+ * that will be put into the new relation contents.
+ */
+void
+RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid)
+{
+ Oid newrelfilenode;
+ RelFileNode newrnode;
+ Relation pg_class;
+ HeapTuple tuple;
+ Form_pg_class classform;
+
+ /* Can't change relfilenode for nailed tables (indexes ok though) */
+ Assert(!relation->rd_isnailed ||
+ relation->rd_rel->relkind == RELKIND_INDEX);
+ /* Can't change for shared tables or indexes */
+ Assert(!relation->rd_rel->relisshared);
+ /* Indexes must have Invalid frozenxid; other relations must not */
+ Assert((relation->rd_rel->relkind == RELKIND_INDEX &&
+ freezeXid == InvalidTransactionId) ||
+ TransactionIdIsNormal(freezeXid));
+
+ /* Allocate a new relfilenode */
+ newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace,
+ relation->rd_rel->relisshared,
+ NULL);
+
+ /*
+ * Find the pg_class tuple for the given relation. This is not used
+ * during bootstrap, so okay to use heap_update always.
+ */
+ pg_class = heap_open(RelationRelationId, RowExclusiveLock);
+
+ tuple = SearchSysCacheCopy(RELOID,
+ ObjectIdGetDatum(RelationGetRelid(relation)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for relation %u",
+ RelationGetRelid(relation));
+ classform = (Form_pg_class) GETSTRUCT(tuple);
+
+ /*
+ * Create storage for the main fork of the new relfilenode.
+ *
+ * NOTE: any conflict in relfilenode value will be caught here, if
+ * GetNewRelFileNode messes up for any reason.
+ */
+ newrnode = relation->rd_node;
+ newrnode.relNode = newrelfilenode;
+ RelationCreateStorage(newrnode, relation->rd_istemp);
+ smgrclosenode(newrnode);
+
+ /*
+ * Schedule unlinking of the old storage at transaction commit.
+ */
+ RelationDropStorage(relation);
+
+ /*
+ * Now update the pg_class row.
+ */
+ classform->relfilenode = newrelfilenode;
+ classform->relpages = 0; /* it's empty until further notice */
+ classform->reltuples = 0;
+ classform->relfrozenxid = freezeXid;
+ simple_heap_update(pg_class, &tuple->t_self, tuple);
+ CatalogUpdateIndexes(pg_class, tuple);
+
+ heap_freetuple(tuple);
+
+ heap_close(pg_class, RowExclusiveLock);
+
+ /*
+ * Make the pg_class row change visible. This will cause the relcache
+ * entry to get updated, too.
+ */
+ CommandCounterIncrement();
+
+ /*
+ * Mark the rel as having been given a new relfilenode in the current
+ * (sub) transaction. This is a hint that can be used to optimize
+ * later operations on the rel in the same transaction.
+ */
+ relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
+ /* ... and now we have eoxact cleanup work to do */
+ need_eoxact_work = true;
+}
+
+
/*
* RelationCacheInitialize
*