diff options
| author | Bruce Momjian <bruce@momjian.us> | 2010-05-12 02:19:11 +0000 |
|---|---|---|
| committer | Bruce Momjian <bruce@momjian.us> | 2010-05-12 02:19:11 +0000 |
| commit | c2e9b2f288185a8569f6391ea250c7eeafa6c14b (patch) | |
| tree | 408e8eb0c0aacaf177602789c02d7a416bbd59e1 /contrib/pg_upgrade/relfilenode.c | |
| parent | 28e1742217716076da0700094a369eae5766974c (diff) | |
Add pg_upgrade to /contrib; will be in 9.0 beta2.
Add documentation.
Supports migration from PG 8.3 and 8.4.
Diffstat (limited to 'contrib/pg_upgrade/relfilenode.c')
| -rw-r--r-- | contrib/pg_upgrade/relfilenode.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/contrib/pg_upgrade/relfilenode.c b/contrib/pg_upgrade/relfilenode.c new file mode 100644 index 00000000000..918447fcfaf --- /dev/null +++ b/contrib/pg_upgrade/relfilenode.c @@ -0,0 +1,228 @@ +/* + * relfilenode.c + * + * relfilenode functions + */ + +#include "pg_upgrade.h" + +#ifdef EDB_NATIVE_LANG +#include <fcntl.h> +#endif + +#include "catalog/pg_class.h" +#include "access/transam.h" + + +static void transfer_single_new_db(migratorContext *ctx, pageCnvCtx *pageConverter, + FileNameMap *maps, int size); +static void transfer_relfile(migratorContext *ctx, pageCnvCtx *pageConverter, + const char *fromfile, const char *tofile, + const char *oldnspname, const char *oldrelname, + const char *newnspname, const char *newrelname); + +/* + * transfer_all_new_dbs() + * + * Responsible for upgrading all database. invokes routines to generate mappings and then + * physically link the databases. + */ +const char * +transfer_all_new_dbs(migratorContext *ctx, DbInfoArr *olddb_arr, + DbInfoArr *newdb_arr, char *old_pgdata, char *new_pgdata) +{ + int dbnum; + const char *msg = NULL; + + prep_status(ctx, "Restoring user relation files\n"); + + for (dbnum = 0; dbnum < newdb_arr->ndbs; dbnum++) + { + DbInfo *new_db = &newdb_arr->dbs[dbnum]; + DbInfo *old_db = dbarr_lookup_db(olddb_arr, new_db->db_name); + FileNameMap *mappings; + int n_maps; + pageCnvCtx *pageConverter = NULL; + + n_maps = 0; + mappings = gen_db_file_maps(ctx, old_db, new_db, &n_maps, old_pgdata, + new_pgdata); + + if (n_maps) + { + print_maps(ctx, mappings, n_maps, new_db->db_name); + +#ifdef PAGE_CONVERSION + msg = setupPageConverter(ctx, &pageConverter); +#endif + transfer_single_new_db(ctx, pageConverter, mappings, n_maps); + + pg_free(mappings); + } + } + + prep_status(ctx, ""); /* in case nothing printed */ + check_ok(ctx); + + return msg; +} + + +/* + * get_pg_database_relfilenode() + * + * Retrieves the relfilenode for a few system-catalog tables. We need these + * relfilenodes later in the upgrade process. + */ +void +get_pg_database_relfilenode(migratorContext *ctx, Cluster whichCluster) +{ + PGconn *conn = connectToServer(ctx, "template1", whichCluster); + PGresult *res; + int i_relfile; + + res = executeQueryOrDie(ctx, conn, + "SELECT c.relname, c.relfilenode " + "FROM pg_catalog.pg_class c, " + " pg_catalog.pg_namespace n " + "WHERE c.relnamespace = n.oid AND " + " n.nspname = 'pg_catalog' AND " + " c.relname = 'pg_database' " + "ORDER BY c.relname"); + + i_relfile = PQfnumber(res, "relfilenode"); + if (whichCluster == CLUSTER_OLD) + ctx->old.pg_database_oid = atol(PQgetvalue(res, 0, i_relfile)); + else + ctx->new.pg_database_oid = atol(PQgetvalue(res, 0, i_relfile)); + + PQclear(res); + PQfinish(conn); +} + + +/* + * transfer_single_new_db() + * + * create links for mappings stored in "maps" array. + */ +static void +transfer_single_new_db(migratorContext *ctx, pageCnvCtx *pageConverter, + FileNameMap *maps, int size) +{ + int mapnum; + + for (mapnum = 0; mapnum < size; mapnum++) + { + char old_file[MAXPGPATH]; + char new_file[MAXPGPATH]; + struct dirent **namelist = NULL; + int numFiles; + + /* Copying files might take some time, so give feedback. */ + + snprintf(old_file, sizeof(old_file), "%s/%u", maps[mapnum].old_file, maps[mapnum].old); + snprintf(new_file, sizeof(new_file), "%s/%u", maps[mapnum].new_file, maps[mapnum].new); + pg_log(ctx, PG_REPORT, OVERWRITE_MESSAGE, old_file); + + /* + * Copy/link the relation file to the new cluster + */ + unlink(new_file); + transfer_relfile(ctx, pageConverter, old_file, new_file, + maps[mapnum].old_nspname, maps[mapnum].old_relname, + maps[mapnum].new_nspname, maps[mapnum].new_relname); + + /* fsm/vm files added in PG 8.4 */ + if (GET_MAJOR_VERSION(ctx->old.major_version) >= 804) + { + /* + * Now copy/link any fsm and vm files, if they exist + */ + snprintf(scandir_file_pattern, sizeof(scandir_file_pattern), "%u_", maps[mapnum].old); + numFiles = pg_scandir(ctx, maps[mapnum].old_file, &namelist, dir_matching_filenames, NULL); + + while (numFiles--) + { + snprintf(old_file, sizeof(old_file), "%s/%s", maps[mapnum].old_file, + namelist[numFiles]->d_name); + snprintf(new_file, sizeof(new_file), "%s/%u%s", maps[mapnum].new_file, + maps[mapnum].new, strchr(namelist[numFiles]->d_name, '_')); + + unlink(new_file); + transfer_relfile(ctx, pageConverter, old_file, new_file, + maps[mapnum].old_nspname, maps[mapnum].old_relname, + maps[mapnum].new_nspname, maps[mapnum].new_relname); + + pg_free(namelist[numFiles]); + } + + pg_free(namelist); + } + + /* + * Now copy/link any related segments as well. Remember, PG breaks + * large files into 1GB segments, the first segment has no extension, + * subsequent segments are named relfilenode.1, relfilenode.2, + * relfilenode.3, ... 'fsm' and 'vm' files use underscores so are not + * copied. + */ + snprintf(scandir_file_pattern, sizeof(scandir_file_pattern), "%u.", maps[mapnum].old); + numFiles = pg_scandir(ctx, maps[mapnum].old_file, &namelist, dir_matching_filenames, NULL); + + while (numFiles--) + { + snprintf(old_file, sizeof(old_file), "%s/%s", maps[mapnum].old_file, + namelist[numFiles]->d_name); + snprintf(new_file, sizeof(new_file), "%s/%u%s", maps[mapnum].new_file, + maps[mapnum].new, strchr(namelist[numFiles]->d_name, '.')); + + unlink(new_file); + transfer_relfile(ctx, pageConverter, old_file, new_file, + maps[mapnum].old_nspname, maps[mapnum].old_relname, + maps[mapnum].new_nspname, maps[mapnum].new_relname); + + pg_free(namelist[numFiles]); + } + + pg_free(namelist); + } +} + + +/* + * transfer_relfile() + * + * Copy or link file from old cluster to new one. + */ +static void +transfer_relfile(migratorContext *ctx, pageCnvCtx *pageConverter, const char *oldfile, + const char *newfile, const char *oldnspname, const char *oldrelname, + const char *newnspname, const char *newrelname) +{ + const char *msg; + + if ((ctx->transfer_mode == TRANSFER_MODE_LINK) && (pageConverter != NULL)) + pg_log(ctx, PG_FATAL, "this migration requires page-by-page conversion, " + "you must use copy-mode instead of link-mode\n"); + + if (ctx->transfer_mode == TRANSFER_MODE_COPY) + { + pg_log(ctx, PG_INFO, "copying %s to %s\n", oldfile, newfile); + + if ((msg = copyAndUpdateFile(ctx, pageConverter, oldfile, newfile, true)) != NULL) + pg_log(ctx, PG_FATAL, "error while copying %s.%s(%s) to %s.%s(%s): %s\n", + oldnspname, oldrelname, oldfile, newnspname, newrelname, newfile, msg); + } + else + { + pg_log(ctx, PG_INFO, "linking %s to %s\n", newfile, oldfile); + + if ((msg = linkAndUpdateFile(ctx, pageConverter, oldfile, newfile)) != NULL) + pg_log(ctx, PG_FATAL, + "error while creating link from %s.%s(%s) to %s.%s(%s): %s\n", + oldnspname, oldrelname, oldfile, newnspname, newrelname, + newfile, msg); + } + return; +} |
