1111 *
1212 *
1313 * IDENTIFICATION
14- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.126 2004/06/18 06 :13:22 tgl Exp $
14+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.127 2004/07/11 23 :13:53 tgl Exp $
1515 *
1616 *-------------------------------------------------------------------------
1717 */
@@ -485,6 +485,7 @@ static void
485485rebuild_relation (Relation OldHeap , Oid indexOid )
486486{
487487 Oid tableOid = RelationGetRelid (OldHeap );
488+ Oid tableSpace = OldHeap -> rd_rel -> reltablespace ;
488489 Oid OIDNewHeap ;
489490 char NewHeapName [NAMEDATALEN ];
490491 ObjectAddress object ;
@@ -505,7 +506,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
505506 */
506507 snprintf (NewHeapName , sizeof (NewHeapName ), "pg_temp_%u" , tableOid );
507508
508- OIDNewHeap = make_new_heap (tableOid , NewHeapName );
509+ OIDNewHeap = make_new_heap (tableOid , NewHeapName , tableSpace );
509510
510511 /*
511512 * We don't need CommandCounterIncrement() because make_new_heap did
@@ -520,8 +521,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
520521 /* To make the new heap's data visible (probably not needed?). */
521522 CommandCounterIncrement ();
522523
523- /* Swap the relfilenodes of the old and new heaps. */
524- swap_relfilenodes (tableOid , OIDNewHeap );
524+ /* Swap the physical files of the old and new heaps. */
525+ swap_relation_files (tableOid , OIDNewHeap );
525526
526527 CommandCounterIncrement ();
527528
@@ -550,7 +551,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
550551 * Create the new table that we will fill with correctly-ordered data.
551552 */
552553Oid
553- make_new_heap (Oid OIDOldHeap , const char * NewName )
554+ make_new_heap (Oid OIDOldHeap , const char * NewName , Oid NewTableSpace )
554555{
555556 TupleDesc OldHeapDesc ,
556557 tupdesc ;
@@ -568,7 +569,7 @@ make_new_heap(Oid OIDOldHeap, const char *NewName)
568569
569570 OIDNewHeap = heap_create_with_catalog (NewName ,
570571 RelationGetNamespace (OldHeap ),
571- OldHeap -> rd_rel -> reltablespace ,
572+ NewTableSpace ,
572573 tupdesc ,
573574 OldHeap -> rd_rel -> relkind ,
574575 OldHeap -> rd_rel -> relisshared ,
@@ -646,13 +647,16 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
646647}
647648
648649/*
649- * Swap the relfilenodes for two given relations.
650+ * Swap the physical files of two given relations.
651+ *
652+ * We swap the physical identity (reltablespace and relfilenode) while
653+ * keeping the same logical identities of the two relations.
650654 *
651655 * Also swap any TOAST links, so that the toast data moves along with
652656 * the main-table data.
653657 */
654658void
655- swap_relfilenodes (Oid r1 , Oid r2 )
659+ swap_relation_files (Oid r1 , Oid r2 )
656660{
657661 Relation relRelation ,
658662 rel ;
@@ -695,12 +699,16 @@ swap_relfilenodes(Oid r1, Oid r2)
695699 relation_close (rel , NoLock );
696700
697701 /*
698- * Actually swap the filenode and TOAST fields in the two tuples
702+ * Actually swap the fields in the two tuples
699703 */
700704 swaptemp = relform1 -> relfilenode ;
701705 relform1 -> relfilenode = relform2 -> relfilenode ;
702706 relform2 -> relfilenode = swaptemp ;
703707
708+ swaptemp = relform1 -> reltablespace ;
709+ relform1 -> reltablespace = relform2 -> reltablespace ;
710+ relform2 -> reltablespace = swaptemp ;
711+
704712 swaptemp = relform1 -> reltoastrelid ;
705713 relform1 -> reltoastrelid = relform2 -> reltoastrelid ;
706714 relform2 -> reltoastrelid = swaptemp ;
@@ -793,13 +801,16 @@ swap_relfilenodes(Oid r1, Oid r2)
793801
794802 /*
795803 * Blow away the old relcache entries now. We need this kluge because
796- * relcache.c indexes relcache entries by rd_node as well as OID. It
797- * will get confused if it is asked to (re)build an entry with a new
798- * rd_node value when there is still another entry laying about with
799- * that same rd_node value. (Fortunately, since one of the entries is
800- * local in our transaction, it's sufficient to clear out our own
801- * relcache this way; the problem cannot arise for other backends when
802- * they see our update on the non-local relation.)
804+ * relcache.c keeps a link to the smgr relation for the physical file,
805+ * and that will be out of date as soon as we do CommandCounterIncrement.
806+ * Whichever of the rels is the second to be cleared during cache
807+ * invalidation will have a dangling reference to an already-deleted smgr
808+ * relation. Rather than trying to avoid this by ordering operations
809+ * just so, it's easiest to not have the relcache entries there at all.
810+ * (Fortunately, since one of the entries is local in our transaction,
811+ * it's sufficient to clear out our own relcache this way; the problem
812+ * cannot arise for other backends when they see our update on the
813+ * non-local relation.)
803814 */
804815 RelationForgetRelation (r1 );
805816 RelationForgetRelation (r2 );
0 commit comments