From d7892e026396cffb19ebb760fcd12f966054294b Mon Sep 17 00:00:00 2001
From: Hiroshi Inoue <inoue@tpf.co.jp>
Date: Fri, 8 Dec 2000 06:17:58 +0000
Subject: [PATCH] REINDEX under WAL.

---
 src/backend/catalog/index.c        | 199 ++++++++++++++++++++++++++---
 src/backend/commands/indexcmds.c   |   8 +-
 src/backend/tcop/utility.c         |   4 +-
 src/backend/utils/cache/relcache.c |  61 ++++++++-
 src/include/catalog/index.h        |   7 +-
 5 files changed, 252 insertions(+), 27 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index d379246a92..aabc3a33d0 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.130 2000/11/16 22:30:17 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.131 2000/12/08 06:17:57 inoue Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -76,7 +76,7 @@ static void DefaultBuild(Relation heapRelation, Relation indexRelation,
 						 IndexInfo *indexInfo, Node *oldPred,
 						 IndexStrategy indexStrategy);
 static Oid	IndexGetRelation(Oid indexId);
-static bool activate_index(Oid indexId, bool activate);
+static bool activate_index(Oid indexId, bool activate, bool inplace);
 
 
 static bool reindexing = false;
@@ -1430,7 +1430,11 @@ setRelhasindex(Oid relid, bool hasindex)
 	 */
 	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
+#ifdef	OLD_FILE_NAMING
 	if (!IsIgnoringSystemIndexes())
+#else
+	if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
+#endif /* OLD_FILE_NAMING */
 	{
 		tuple = SearchSysCacheCopy(RELOID,
 								   ObjectIdGetDatum(relid),
@@ -1462,7 +1466,11 @@ setRelhasindex(Oid relid, bool hasindex)
 	 *	Update hasindex in pg_class.
 	 * ----------------
 	 */
+	if (pg_class_scan)
+		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
 	((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
+	if (pg_class_scan)
+		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
 
 	if (pg_class_scan)
 	{
@@ -1471,6 +1479,7 @@ setRelhasindex(Oid relid, bool hasindex)
 		/* Send out shared cache inval if necessary */
 		if (!IsBootstrapProcessingMode())
 			RelationInvalidateHeapTuple(pg_class, tuple);
+		BufferSync();
 	}
 	else
 	{
@@ -1496,6 +1505,75 @@ setRelhasindex(Oid relid, bool hasindex)
 	heap_close(pg_class, RowExclusiveLock);
 }
 
+#ifndef OLD_FILE_NAMING
+void
+setNewRelfilenode(Relation relation)
+{
+	Relation	pg_class, idescs[Num_pg_class_indices];
+	Oid		newrelfilenode;
+	bool		in_place_update = false;
+	HeapTupleData 	lockTupleData;
+	HeapTuple 	classTuple;
+	Buffer		buffer;
+	RelationData	workrel;
+	
+	Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
+
+	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
+	 /* Fetch and lock the classTuple associated with this relation */
+	if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
+		elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
+	if (IsIgnoringSystemIndexes())
+		in_place_update = true;
+	/* Allocate a new relfilenode */
+	newrelfilenode = newoid();
+	/* update pg_class tuple with new relfilenode */
+	if (!in_place_update)
+	{
+		classTuple = heap_copytuple(&lockTupleData);
+		ReleaseBuffer(buffer);
+		((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
+		heap_update(pg_class, &classTuple->t_self, classTuple, NULL);
+	}
+	/* unlink old relfilenode */
+	DropRelationBuffers(relation);
+	smgrunlink(DEFAULT_SMGR, relation);
+	/* cleanup pg_internal.init if necessary */
+	if (relation->rd_isnailed)
+		unlink(RELCACHE_INIT_FILENAME);
+	/* create another storage file. Is it a little ugly ? */
+	memcpy((char *) &workrel, relation, sizeof(RelationData));
+	workrel.rd_node.relNode = newrelfilenode;
+	heap_storage_create(&workrel);
+	/* update pg_class tuple with new relfilenode in place */
+	if (in_place_update)
+	{
+		classTuple = &lockTupleData;
+		/* Send out shared cache inval if necessary */
+		if (!IsBootstrapProcessingMode())
+			RelationInvalidateHeapTuple(pg_class, classTuple);
+		/* Update the buffer in-place */
+		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
+		((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
+		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
+		WriteBuffer(buffer);
+		BufferSync();
+	}
+	/* Keep the catalog indices up to date */
+	if (!in_place_update && pg_class->rd_rel->relhasindex)
+	{
+		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
+							   idescs);
+		CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
+		CatalogCloseIndices(Num_pg_class_indices, idescs);
+		heap_freetuple(classTuple);
+	}
+	heap_close(pg_class, NoLock);
+	/* Make sure the relfilenode change */
+	CommandCounterIncrement();
+}
+#endif /* OLD_FILE_NAMING */
+
 /* ----------------
  *		UpdateStats
  * ----------------
@@ -1552,7 +1630,12 @@ UpdateStats(Oid relid, long reltuples)
 	 */
 	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
+#ifdef	OLD_FILE_NAMING
 	in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
+#else
+	in_place_upd = (IsIgnoringSystemIndexes() || (IsReindexProcessing() &&
+			relid == RelOid_pg_class));
+#endif /* OLD_FILE_NAMING */
 
 	if (!in_place_upd)
 	{
@@ -1631,8 +1714,10 @@ UpdateStats(Oid relid, long reltuples)
 		 * visibility of changes, so we cheat.  Also cheat if REINDEX.
 		 */
 		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
 		rd_rel->relpages = relpages;
 		rd_rel->reltuples = reltuples;
+		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
 		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
 		if (!IsBootstrapProcessingMode())
 			RelationInvalidateHeapTuple(pg_class, tuple);
@@ -1924,11 +2009,11 @@ IndexGetRelation(Oid indexId)
  * ---------------------------------
  */
 static bool
-activate_index(Oid indexId, bool activate)
+activate_index(Oid indexId, bool activate, bool inplace)
 {
 	if (!activate)				/* Currently does nothing */
 		return true;
-	return reindex_index(indexId, false);
+	return reindex_index(indexId, false, inplace);
 }
 
 /* --------------------------------
@@ -1936,7 +2021,7 @@ activate_index(Oid indexId, bool activate)
  * --------------------------------
  */
 bool
-reindex_index(Oid indexId, bool force)
+reindex_index(Oid indexId, bool force, bool inplace)
 {
 	Relation	iRel,
 				indexRelation,
@@ -1996,18 +2081,25 @@ reindex_index(Oid indexId, bool force)
 	if (iRel == NULL)
 		elog(ERROR, "reindex_index: can't open index relation");
 
+#ifndef OLD_FILE_NAMING
+	if (!inplace)
+		setNewRelfilenode(iRel);
+#endif /* OLD_FILE_NAMING */
 	/* Obtain exclusive lock on it, just to be sure */
 	LockRelation(iRel, AccessExclusiveLock);
 
-	/*
-	 * Release any buffers associated with this index.	If they're dirty,
-	 * they're just dropped without bothering to flush to disk.
-	 */
-	DropRelationBuffers(iRel);
+	if (inplace)
+	{
+		/*
+	 	 * Release any buffers associated with this index.	If they're dirty,
+	 	 * they're just dropped without bothering to flush to disk.
+	 	 */
+		DropRelationBuffers(iRel);
 
-	/* Now truncate the actual data and set blocks to zero */
-	smgrtruncate(DEFAULT_SMGR, iRel, 0);
-	iRel->rd_nblocks = 0;
+		/* Now truncate the actual data and set blocks to zero */
+		smgrtruncate(DEFAULT_SMGR, iRel, 0);
+		iRel->rd_nblocks = 0;
+	}
 
 	/* Initialize the index and rebuild */
 	InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
@@ -2064,15 +2156,57 @@ reindex_relation(Oid relid, bool force)
 	bool		old,
 				reindexed;
 
-	old = SetReindexProcessing(true);
-	if (IndexesAreActive(relid, true))
+	bool	deactivate_needed, overwrite, upd_pg_class_inplace;
+#ifdef OLD_FILE_NAMING
+	overwrite = upd_pg_class_inplace = deactivate_needed = true;	
+#else
+	Relation rel;
+	overwrite = upd_pg_class_inplace = deactivate_needed = false;	
+	/*
+ 	 * avoid heap_update() pg_class tuples while processing
+ 	 * reindex for pg_class. 
+ 	 */
+	if (IsIgnoringSystemIndexes())
+		upd_pg_class_inplace = true;
+	/*
+	 * ignore the indexes of the target system relation while processing
+	 * reindex.
+	 */ 
+	rel = RelationIdGetRelation(relid);
+	if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
+		deactivate_needed = true;
+#ifndef	ENABLE_REINDEX_NAILED_RELATIONS
+	/* 
+ 	 * nailed relations are never updated.
+ 	 * We couldn't keep the consistency between the relation
+ 	 * descriptors and pg_class tuples.
+ 	 */
+	if (rel->rd_isnailed)
 	{
-		if (!force)
+		if (IsIgnoringSystemIndexes())
 		{
-			SetReindexProcessing(old);
-			return false;
+			overwrite = true;
+			deactivate_needed = true;
+		}
+		else
+			elog(ERROR, "the target relation %u is nailed", relid);
+	}
+#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
+	RelationClose(rel);
+#endif /* OLD_FILE_NAMING */
+	old = SetReindexProcessing(true);
+	if (deactivate_needed)
+	{
+		if (IndexesAreActive(relid, upd_pg_class_inplace))
+		{
+			if (!force)
+			{
+				SetReindexProcessing(old);
+				return false;
+			}
+			activate_indexes_of_a_table(relid, false);
+			CommandCounterIncrement();
 		}
-		activate_indexes_of_a_table(relid, false);
 	}
 
 	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
@@ -2085,7 +2219,7 @@ reindex_relation(Oid relid, bool force)
 	{
 		Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
 
-		if (activate_index(index->indexrelid, true))
+		if (activate_index(index->indexrelid, true, overwrite))
 			reindexed = true;
 		else
 		{
@@ -2096,7 +2230,30 @@ reindex_relation(Oid relid, bool force)
 	heap_endscan(scan);
 	heap_close(indexRelation, AccessShareLock);
 	if (reindexed)
-		setRelhasindex(relid, true);
+	/*
+	 * Ok,we could use the reindexed indexes of the target
+	 * system relation now.
+	 */
+	{ 
+		if (deactivate_needed)
+		{
+			if (!overwrite && relid == RelOid_pg_class)
+			{
+				/* 
+				 * For pg_class, relhasindex should be set
+				 * to true here in place.
+				 */
+				setRelhasindex(relid, true);
+				CommandCounterIncrement();
+				/* 
+				 * However the following setRelhasindex()
+				 * is needed to keep consistency with WAL.
+				 */
+			}
+			setRelhasindex(relid, true);
+		}
+	}
 	SetReindexProcessing(old);
+
 	return reindexed;
 }
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 788701b20f..8e362399d8 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.41 2000/11/16 22:30:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.42 2000/12/08 06:17:58 inoue Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -653,7 +653,11 @@ ReindexIndex(const char *name, bool force /* currently unused */ )
 		elog(ERROR, "relation \"%s\" is of type \"%c\"",
 			 name, ((Form_pg_class) GETSTRUCT(tuple))->relkind);
 
-	if (!reindex_index(tuple->t_data->t_oid, force))
+#ifdef	OLD_FILE_NAMING
+	if (!reindex_index(tuple->t_data->t_oid, force, false))
+#else
+	if (!reindex_index(tuple->t_data->t_oid, force, false))
+#endif /* OLD_FILE_NAMING */
 		elog(NOTICE, "index \"%s\" wasn't reindexed", name);
 
 	ReleaseSysCache(tuple);
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index e725ff391f..03df9c1f3d 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.103 2000/11/16 22:30:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.104 2000/12/08 06:17:58 inoue Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -866,6 +866,7 @@ ProcessUtility(Node *parsetree,
 						relname = (char *) stmt->name;
 						if (IsSystemRelationName(relname))
 						{
+#ifdef	OLD_FILE_NAMING
 							if (!allowSystemTableMods && IsSystemRelationName(relname))
 								elog(ERROR, "\"%s\" is a system table. call REINDEX under standalone postgres with -O -P options",
 								 relname);
@@ -873,6 +874,7 @@ ProcessUtility(Node *parsetree,
 								elog(ERROR, "\"%s\" is a system table. call REINDEX under standalone postgres with -P -O options",
 
 								 relname);
+#endif /* OLD_FILE_NAMING */
 						}
 						if (!pg_ownercheck(GetUserId(), relname, RELNAME))
 							elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index e4551d4c60..deb8cc67df 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.118 2000/11/30 18:38:46 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.119 2000/12/08 06:17:56 inoue Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -250,6 +250,10 @@ do { \
 /* non-export function prototypes */
 
 static void RelationClearRelation(Relation relation, bool rebuildIt);
+#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
+static void RelationReloadClassinfo(Relation relation);
+#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
+static void RelationResetRelation(Relation relation, bool rebuildIt);
 static void RelationFlushRelation(Relation *relationPtr,
 					  int skipLocalRelations);
 static Relation RelationNameCacheGetRelation(const char *relationName);
@@ -387,6 +391,15 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
 	HeapTuple	return_tuple;
 
 	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
+	/*
+	 * If the indexes of pg_class are deactivated
+	 * we have to call scan_pg_rel_seq() instead.
+	 */
+	if (!pg_class_desc->rd_rel->relhasindex)
+	{
+		heap_close(pg_class_desc, AccessShareLock);
+		return scan_pg_rel_seq(buildinfo);
+	}
 
 	switch (buildinfo.infotype)
 	{
@@ -1555,6 +1568,45 @@ RelationClose(Relation relation)
 	RelationDecrementReferenceCount(relation);
 }
 
+#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
+/* --------------------------------
+ * RelationReloadClassinfo
+ *
+ *	This function is especially for nailed relations.
+ *	relhasindex/relfilenode could be changed even for
+ *	nailed relations.
+ * --------------------------------
+ */
+static void
+RelationReloadClassinfo(Relation relation)
+{
+	RelationBuildDescInfo buildinfo;
+	HeapTuple	pg_class_tuple;
+	Form_pg_class	relp;
+
+	if (!relation->rd_rel)
+		return;
+	buildinfo.infotype = INFO_RELID;
+	buildinfo.i.info_id = relation->rd_id;
+	pg_class_tuple = ScanPgRelation(buildinfo);
+	if (!HeapTupleIsValid(pg_class_tuple))
+	{
+		elog(ERROR, "RelationReloadClassinfo system relation id=%d doesn't exist", relation->rd_id);
+		return;
+	}
+	RelationCacheDelete(relation);
+	relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
+	memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
+	relation->rd_node.relNode = relp->relfilenode;
+	RelationCacheInsert(relation);
+	heap_freetuple(pg_class_tuple);
+fprintf(stderr, "RelationClearRelation nailed %s hasindex=%d relfilenode=%d,%d\n",
+RelationGetRelationName(relation), relation->rd_rel->relhasindex,
+relation->rd_rel->relfilenode, relation->rd_node.relNode);
+
+	return;
+}
+#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
 /* --------------------------------
  * RelationClearRelation
  *
@@ -1588,7 +1640,14 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 	 * we'd be unable to recover.
 	 */
 	if (relation->rd_isnailed)
+#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
+	{
+		RelationReloadClassinfo(relation);
+#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
 		return;
+#ifdef	ENABLE_REINDEX_NAILED_RELATIONS
+	}
+#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
 
 	/*
 	 * Remove relation from hash tables
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 967bffb4aa..4a7672350a 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: index.h,v 1.30 2000/11/08 22:10:01 tgl Exp $
+ * $Id: index.h,v 1.31 2000/12/08 06:17:56 inoue Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,13 +49,16 @@ extern void FormIndexDatum(IndexInfo *indexInfo,
 extern void UpdateStats(Oid relid, long reltuples);
 extern bool IndexesAreActive(Oid relid, bool comfirmCommitted);
 extern void setRelhasindex(Oid relid, bool hasindex);
+#ifndef OLD_FILE_NAMING
+extern void setNewRelfilenode(Relation relation);
+#endif /* OLD_FILE_NAMING */
 extern bool SetReindexProcessing(bool processing);
 extern bool IsReindexProcessing(void);
 
 extern void index_build(Relation heapRelation, Relation indexRelation,
 						IndexInfo *indexInfo, Node *oldPred);
 
-extern bool reindex_index(Oid indexId, bool force);
+extern bool reindex_index(Oid indexId, bool force, bool inplace);
 extern bool activate_indexes_of_a_table(Oid relid, bool activate);
 extern bool reindex_relation(Oid relid, bool force);