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