Bruce Momjian wrote:
> pg_migrator has become more popular recently, so it seems time to look
> at some enhancements that would improve pg_migrator.  None of these are
> required, but rather changes that would be nice to have:
> 
> 1)  Right now pg_migrator preserves relfilenodes for TOAST files because
> this is required for proper migration.  Now that we have shown that
> strategically-placed global variables with a server-side function to set
> them is a viable solution, it would be nice to preserve all relfilenodes
> from the old server.  This would simplify pg_migrator by no long
> requiring place-holder relfilenodes or the renaming of TOAST files.  A
> simpler solution would just be to allow TOAST table creation to
> automatically remove placeholder files and create specified relfilenodes
> via global variables.

Attached is a patch that implements #1 above by preserving all
relfilenodes, with pg_dump support.   It uses the same method I used for
preserving pg_type/pg_enum.  I have tested this on the regression
database and it successfully preserved all relfilenodes.

This patch also removes the 'force' parameter in toast functions that
Tom added for 8.4 --- it is no longer needed.

-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +
Index: src/backend/catalog/heap.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/heap.c,v
retrieving revision 1.364
diff -c -c -r1.364 heap.c
*** src/backend/catalog/heap.c	2 Jan 2010 16:57:36 -0000	1.364
--- src/backend/catalog/heap.c	5 Jan 2010 02:37:21 -0000
***************
*** 96,101 ****
--- 96,104 ----
  			   char *relname);
  static List *insert_ordered_unique_oid(List *list, Oid datum);
  
+ Oid binary_upgrade_next_heap_relfilenode = InvalidOid;
+ Oid binary_upgrade_next_toast_relfilenode = InvalidOid;
+ 
  
  /* ----------------------------------------------------------------
   *				XXX UGLY HARD CODED BADNESS FOLLOWS XXX
***************
*** 942,956 ****
  					 errmsg("only shared relations can be placed in pg_global tablespace")));
  	}
  
! 	/*
! 	 * Allocate an OID for the relation, unless we were told what to use.
! 	 *
! 	 * The OID will be the relfilenode as well, so make sure it doesn't
! 	 * collide with either pg_class OIDs or existing physical files.
! 	 */
! 	if (!OidIsValid(relid))
  		relid = GetNewRelFileNode(reltablespace, shared_relation,
  								  pg_class_desc);
  
  	/*
  	 * Determine the relation's initial permissions.
--- 945,973 ----
  					 errmsg("only shared relations can be placed in pg_global tablespace")));
  	}
  
! 	if ((relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE) &&
! 		OidIsValid(binary_upgrade_next_heap_relfilenode))
! 	{
! 		relid = binary_upgrade_next_heap_relfilenode;
! 		binary_upgrade_next_heap_relfilenode = InvalidOid;
! 	}
! 	else if (relkind == RELKIND_TOASTVALUE &&
! 		OidIsValid(binary_upgrade_next_toast_relfilenode))
! 	{
! 		relid = binary_upgrade_next_toast_relfilenode;
! 		binary_upgrade_next_toast_relfilenode = InvalidOid;
! 	}
! 	else if (!OidIsValid(relid))
! 	{
! 		/*
! 		 * Allocate an OID for the relation, unless we were told what to use.
! 		 *
! 		 * The OID will be the relfilenode as well, so make sure it doesn't
! 		 * collide with either pg_class OIDs or existing physical files.
! 		 */
  		relid = GetNewRelFileNode(reltablespace, shared_relation,
  								  pg_class_desc);
+ 	}
  
  	/*
  	 * Determine the relation's initial permissions.
Index: src/backend/catalog/index.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.328
diff -c -c -r1.328 index.c
*** src/backend/catalog/index.c	2 Jan 2010 16:57:36 -0000	1.328
--- src/backend/catalog/index.c	5 Jan 2010 02:37:21 -0000
***************
*** 79,84 ****
--- 79,87 ----
  				tups_inserted;
  } v_i_state;
  
+ /* For simple relation creation, this is the toast index relfilenode */
+ Oid binary_upgrade_next_index_relfilenode = InvalidOid;
+ 
  /* non-export function prototypes */
  static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
  						 IndexInfo *indexInfo,
***************
*** 640,654 ****
  											accessMethodObjectId,
  											classObjectId);
  
! 	/*
! 	 * Allocate an OID for the index, unless we were told what to use.
! 	 *
! 	 * The OID will be the relfilenode as well, so make sure it doesn't
! 	 * collide with either pg_class OIDs or existing physical files.
! 	 */
! 	if (!OidIsValid(indexRelationId))
  		indexRelationId = GetNewRelFileNode(tableSpaceId, shared_relation,
  											pg_class);
  
  	/*
  	 * create the index relation's relcache entry and physical disk file. (If
--- 643,664 ----
  											accessMethodObjectId,
  											classObjectId);
  
! 	if (OidIsValid(binary_upgrade_next_index_relfilenode))
! 	{
! 		indexRelationId = binary_upgrade_next_index_relfilenode;
! 		binary_upgrade_next_index_relfilenode = InvalidOid;
! 	}
! 	else if (!OidIsValid(indexRelationId))
! 	{
! 		/*
! 		 * Allocate an OID for the index, unless we were told what to use.
! 		 *
! 		 * The OID will be the relfilenode as well, so make sure it doesn't
! 		 * collide with either pg_class OIDs or existing physical files.
! 		 */
  		indexRelationId = GetNewRelFileNode(tableSpaceId, shared_relation,
  											pg_class);
+ 	}
  
  	/*
  	 * create the index relation's relcache entry and physical disk file. (If
Index: src/backend/catalog/toasting.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/toasting.c,v
retrieving revision 1.26
diff -c -c -r1.26 toasting.c
*** src/backend/catalog/toasting.c	2 Jan 2010 16:57:36 -0000	1.26
--- src/backend/catalog/toasting.c	5 Jan 2010 02:37:21 -0000
***************
*** 32,53 ****
  #include "utils/syscache.h"
  
  Oid binary_upgrade_next_pg_type_toast_oid = InvalidOid;
  
  static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
! 				   Datum reloptions, bool force);
  static bool needs_toast_table(Relation rel);
  
  
  /*
   * AlterTableCreateToastTable
   *		If the table needs a toast table, and doesn't already have one,
!  *		then create a toast table for it.  (With the force option, make
!  *		a toast table even if it appears unnecessary.)
!  *
!  * The caller can also specify the OID to be used for the toast table.
!  * Usually, toastOid should be InvalidOid to allow a free OID to be assigned.
!  * (This option, as well as the force option, is not used by core Postgres,
!  * but is provided to support pg_migrator.)
   *
   * reloptions for the toast table can be passed, too.  Pass (Datum) 0
   * for default reloptions.
--- 32,48 ----
  #include "utils/syscache.h"
  
  Oid binary_upgrade_next_pg_type_toast_oid = InvalidOid;
+ extern Oid binary_upgrade_next_toast_relfilenode;
  
  static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
! 				   Datum reloptions);
  static bool needs_toast_table(Relation rel);
  
  
  /*
   * AlterTableCreateToastTable
   *		If the table needs a toast table, and doesn't already have one,
!  *		then create a toast table for it.
   *
   * reloptions for the toast table can be passed, too.  Pass (Datum) 0
   * for default reloptions.
***************
*** 57,64 ****
   * to end with CommandCounterIncrement if it makes any changes.
   */
  void
! AlterTableCreateToastTable(Oid relOid, Oid toastOid,
! 						   Datum reloptions, bool force)
  {
  	Relation	rel;
  
--- 52,58 ----
   * to end with CommandCounterIncrement if it makes any changes.
   */
  void
! AlterTableCreateToastTable(Oid relOid, Datum reloptions)
  {
  	Relation	rel;
  
***************
*** 70,76 ****
  	rel = heap_open(relOid, AccessExclusiveLock);
  
  	/* create_toast_table does all the work */
! 	(void) create_toast_table(rel, toastOid, InvalidOid, reloptions, force);
  
  	heap_close(rel, NoLock);
  }
--- 64,70 ----
  	rel = heap_open(relOid, AccessExclusiveLock);
  
  	/* create_toast_table does all the work */
! 	(void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);
  
  	heap_close(rel, NoLock);
  }
***************
*** 96,102 ****
  						relName)));
  
  	/* create_toast_table does all the work */
! 	if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0, false))
  		elog(ERROR, "\"%s\" does not require a toast table",
  			 relName);
  
--- 90,96 ----
  						relName)));
  
  	/* create_toast_table does all the work */
! 	if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0))
  		elog(ERROR, "\"%s\" does not require a toast table",
  			 relName);
  
***************
*** 108,119 ****
   * create_toast_table --- internal workhorse
   *
   * rel is already opened and exclusive-locked
!  * toastOid and toastIndexOid are normally InvalidOid, but
!  * either or both can be nonzero to specify caller-assigned OIDs
   */
  static bool
! create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
! 				   Datum reloptions, bool force)
  {
  	Oid			relOid = RelationGetRelid(rel);
  	HeapTuple	reltup;
--- 102,112 ----
   * create_toast_table --- internal workhorse
   *
   * rel is already opened and exclusive-locked
!  * toastOid and toastIndexOid are normally InvalidOid, but during
!  * bootstrap they can be nonzero to specify hand-assigned OIDs
   */
  static bool
! create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions)
  {
  	Oid			relOid = RelationGetRelid(rel);
  	HeapTuple	reltup;
***************
*** 152,163 ****
  
  	/*
  	 * Check to see whether the table actually needs a TOAST table.
! 	 *
! 	 * Caller can optionally override this check.  (Note: at present no
! 	 * callers in core Postgres do so, but this option is needed by
! 	 * pg_migrator.)
  	 */
! 	if (!force && !needs_toast_table(rel))
  		return false;
  
  	/*
--- 145,154 ----
  
  	/*
  	 * Check to see whether the table actually needs a TOAST table.
! 	 * If the relfilenode is specified, force toast file creation.
  	 */
! 	if (!needs_toast_table(rel) &&
! 		!OidIsValid(binary_upgrade_next_toast_relfilenode))
  		return false;
  
  	/*
Index: src/backend/commands/cluster.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/cluster.c,v
retrieving revision 1.189
diff -c -c -r1.189 cluster.c
*** src/backend/commands/cluster.c	2 Jan 2010 16:57:37 -0000	1.189
--- src/backend/commands/cluster.c	5 Jan 2010 02:37:21 -0000
***************
*** 743,749 ****
  		if (isNull)
  			reloptions = (Datum) 0;
  	}
! 	AlterTableCreateToastTable(OIDNewHeap, InvalidOid, reloptions, false);
  
  	if (OidIsValid(toastid))
  		ReleaseSysCache(tuple);
--- 743,749 ----
  		if (isNull)
  			reloptions = (Datum) 0;
  	}
! 	AlterTableCreateToastTable(OIDNewHeap, reloptions);
  
  	if (OidIsValid(toastid))
  		ReleaseSysCache(tuple);
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.313
diff -c -c -r1.313 tablecmds.c
*** src/backend/commands/tablecmds.c	2 Jan 2010 16:57:37 -0000	1.313
--- src/backend/commands/tablecmds.c	5 Jan 2010 02:37:21 -0000
***************
*** 2614,2621 ****
  			(tab->subcmds[AT_PASS_ADD_COL] ||
  			 tab->subcmds[AT_PASS_ALTER_TYPE] ||
  			 tab->subcmds[AT_PASS_COL_ATTRS]))
! 			AlterTableCreateToastTable(tab->relid, InvalidOid,
! 									   (Datum) 0, false);
  	}
  }
  
--- 2614,2620 ----
  			(tab->subcmds[AT_PASS_ADD_COL] ||
  			 tab->subcmds[AT_PASS_ALTER_TYPE] ||
  			 tab->subcmds[AT_PASS_COL_ATTRS]))
! 			AlterTableCreateToastTable(tab->relid, (Datum) 0);
  	}
  }
  
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.339
diff -c -c -r1.339 execMain.c
*** src/backend/executor/execMain.c	2 Jan 2010 16:57:40 -0000	1.339
--- src/backend/executor/execMain.c	5 Jan 2010 02:37:22 -0000
***************
*** 2194,2200 ****
  
  	(void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
  
! 	AlterTableCreateToastTable(intoRelationId, InvalidOid, reloptions, false);
  
  	/*
  	 * And open the constructed table for writing.
--- 2194,2200 ----
  
  	(void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
  
! 	AlterTableCreateToastTable(intoRelationId, reloptions);
  
  	/*
  	 * And open the constructed table for writing.
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.326
diff -c -c -r1.326 utility.c
*** src/backend/tcop/utility.c	2 Jan 2010 16:57:53 -0000	1.326
--- src/backend/tcop/utility.c	5 Jan 2010 02:37:22 -0000
***************
*** 491,504 ****
  															"toast",
  															validnsps,
  															true, false);
! 						(void) heap_reloptions(RELKIND_TOASTVALUE,
! 											   toast_options,
  											   true);
  
! 						AlterTableCreateToastTable(relOid,
! 												   InvalidOid,
! 												   toast_options,
! 												   false);
  					}
  					else
  					{
--- 491,500 ----
  															"toast",
  															validnsps,
  															true, false);
! 						(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
  											   true);
  
! 						AlterTableCreateToastTable(relOid, toast_options);
  					}
  					else
  					{
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.564
diff -c -c -r1.564 pg_dump.c
*** src/bin/pg_dump/pg_dump.c	2 Jan 2010 16:57:59 -0000	1.564
--- src/bin/pg_dump/pg_dump.c	5 Jan 2010 02:37:22 -0000
***************
*** 200,206 ****
  					PQExpBuffer upgrade_buffer, Oid pg_type_oid);
  static bool binary_upgrade_set_type_oids_by_rel_oid(
  					PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
! static void binary_upgrade_clear_pg_type_toast_oid(PQExpBuffer upgrade_buffer);
  static const char *getAttrName(int attrnum, TableInfo *tblInfo);
  static const char *fmtCopyColumnList(const TableInfo *ti);
  static void do_sql_command(PGconn *conn, const char *query);
--- 200,207 ----
  					PQExpBuffer upgrade_buffer, Oid pg_type_oid);
  static bool binary_upgrade_set_type_oids_by_rel_oid(
  					PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
! static void binary_upgrade_set_relfilenodes(PQExpBuffer upgrade_buffer,
! 					Oid pg_class_oid, bool is_index);
  static const char *getAttrName(int attrnum, TableInfo *tblInfo);
  static const char *fmtCopyColumnList(const TableInfo *ti);
  static void do_sql_command(PGconn *conn, const char *query);
***************
*** 2289,2309 ****
  }
  
  static void
! binary_upgrade_clear_pg_type_toast_oid(PQExpBuffer upgrade_buffer)
  {
! 	/*
! 	 *	One complexity is that while the heap might now have a TOAST table,
! 	 *	the TOAST table might have been created long after creation when
! 	 *	the table was loaded with wide data.  For that reason, we clear
! 	 *	binary_upgrade_set_next_pg_type_toast_oid so it is not reused
! 	 *	by a later table.  Logically any later creation that needs a TOAST
! 	 *	table should have its own TOAST pg_type oid, but we are cautious.
! 	 */
! 	appendPQExpBuffer(upgrade_buffer,
! 		"\n-- For binary upgrade, clear toast oid because it might not have been needed\n");
  	appendPQExpBuffer(upgrade_buffer,
! 		"SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
! 		InvalidOid);
  }
  
  /*
--- 2290,2367 ----
  }
  
  static void
! binary_upgrade_set_relfilenodes(PQExpBuffer upgrade_buffer, Oid pg_class_oid,
! 								bool is_index)
  {
! 	PQExpBuffer upgrade_query = createPQExpBuffer();
! 	int			ntups;
! 	PGresult   *upgrade_res;
! 	Oid			pg_class_relfilenode;
! 	Oid			pg_class_reltoastrelid;
! 	Oid			pg_class_reltoastidxid;
! 
! 	appendPQExpBuffer(upgrade_query,
! 					  "SELECT c.relfilenode, c.reltoastrelid, t.reltoastidxid "
! 					  "FROM pg_catalog.pg_class c LEFT JOIN "
! 					  "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
! 					  "WHERE c.oid = '%u'::pg_catalog.oid;",
! 					  pg_class_oid);
! 
! 	upgrade_res = PQexec(g_conn, upgrade_query->data);
! 	check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
! 
! 	/* Expecting a single result only */
! 	ntups = PQntuples(upgrade_res);
! 	if (ntups != 1)
! 	{
! 		write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
! 							   "query returned %d rows instead of one: %s\n",
! 								 ntups),
! 				  ntups, upgrade_query->data);
! 		exit_nicely();
! 	}
! 
! 	pg_class_relfilenode = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "relfilenode")));
! 	pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
! 	pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
! 
  	appendPQExpBuffer(upgrade_buffer,
! 						"\n-- For binary upgrade, must preserve relfilenodes\n");
! 
! 	if (!is_index)
! 		appendPQExpBuffer(upgrade_buffer,
! 			"SELECT binary_upgrade.set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
! 			pg_class_relfilenode);
! 	else
! 		appendPQExpBuffer(upgrade_buffer,
! 			"SELECT binary_upgrade.set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
! 			pg_class_relfilenode);
! 	
! 	if (OidIsValid(pg_class_reltoastrelid))
! 	{
! 		/*
! 		 *  One complexity is that the table definition might not require
! 		 *	the creation of a TOAST table, and the TOAST table might have
! 		 *	been created long after table creation, when the table was
! 		 *	loaded with wide data.  By setting the TOAST relfilenode we
! 		 *	force creation of the TOAST heap and TOAST index by the
! 		 *	backend so we can cleanly migrate the files during binary
! 		 *	migration.
! 		 */
! 
! 		appendPQExpBuffer(upgrade_buffer,
! 			"SELECT binary_upgrade.set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
! 			pg_class_reltoastrelid);
! 
! 		/* every toast table has an index */
! 		appendPQExpBuffer(upgrade_buffer,
! 			"SELECT binary_upgrade.set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
! 			pg_class_reltoastidxid);
! 	}
! 	appendPQExpBuffer(upgrade_buffer, "\n");
! 
! 	PQclear(upgrade_res);
! 	destroyPQExpBuffer(upgrade_query);
  }
  
  /*
***************
*** 10480,10485 ****
--- 10538,10546 ----
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
  
+ 		if (binary_upgrade)
+ 			binary_upgrade_set_relfilenodes(q, tbinfo->dobj.catId.oid, false);
+ 
  		appendPQExpBuffer(q, "CREATE TABLE %s (",
  						  fmtId(tbinfo->dobj.name));
  		actual_atts = 0;
***************
*** 10781,10789 ****
  		}
  	}
  
- 	if (binary_upgrade && toast_set)
- 		binary_upgrade_clear_pg_type_toast_oid(q);
- 
  	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
  				 tbinfo->dobj.name,
  				 tbinfo->dobj.namespace->dobj.name,
--- 10842,10847 ----
***************
*** 10926,10931 ****
--- 10984,10992 ----
  	 */
  	if (indxinfo->indexconstraint == 0)
  	{
+ 		if (binary_upgrade)
+ 			binary_upgrade_set_relfilenodes(q, indxinfo->dobj.catId.oid, true);
+ 
  		/* Plain secondary index */
  		appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
  
***************
*** 11006,11011 ****
--- 11067,11075 ----
  			exit_nicely();
  		}
  
+ 		if (binary_upgrade && !coninfo->condef)
+ 			binary_upgrade_set_relfilenodes(q, indxinfo->dobj.catId.oid, true);
+ 
  		appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
  						  fmtId(tbinfo->dobj.name));
  		appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
***************
*** 11416,11422 ****
--- 11480,11489 ----
  		resetPQExpBuffer(query);
  
  		if (binary_upgrade)
+ 		{
+ 			binary_upgrade_set_relfilenodes(query, tbinfo->dobj.catId.oid, false);
  			binary_upgrade_set_type_oids_by_rel_oid(query, tbinfo->dobj.catId.oid);
+ 		}
  
  		appendPQExpBuffer(query,
  						  "CREATE SEQUENCE %s\n",
Index: src/include/catalog/toasting.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/toasting.h,v
retrieving revision 1.11
diff -c -c -r1.11 toasting.h
*** src/include/catalog/toasting.h	2 Jan 2010 16:58:02 -0000	1.11
--- src/include/catalog/toasting.h	5 Jan 2010 02:37:22 -0000
***************
*** 17,24 ****
  /*
   * toasting.c prototypes
   */
! extern void AlterTableCreateToastTable(Oid relOid, Oid toastOid,
! 						   Datum reloptions, bool force);
  extern void BootstrapToastTable(char *relName,
  					Oid toastOid, Oid toastIndexOid);
  
--- 17,23 ----
  /*
   * toasting.c prototypes
   */
! extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions);
  extern void BootstrapToastTable(char *relName,
  					Oid toastOid, Oid toastIndexOid);
  
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to