提交 160a7a91 编写于 作者: A Adam Berlin 提交者: Adam Berlin

Upgrade tablespaces

The upgrade workflow for Greenplum works like this:

init-new-cluster -> upgrade-dispatcher -> copy-from-master ->
upgrade-segments

pg_upgrade is only responsible for the upgrade-dispatcher and
upgrade-segments steps, but it depends on the ordering of these steps.

This commit adds support for tablespaces during the copy-from-master step,
as well as adding logic inside of pg_upgrade necessary to map files
from GPDB5's filespaces to GPDB6's tablespaces. Described here:

During the upgrade-dispatcher step, gpupgrade can run pg_upgrade
--mode=dispatcher which will generate a file (old_tablespaces.txt)
into the current directory containing the tablespace information
inside of the GPDB6 cluster. This file can then be used to perform the
copy-from-master step and the upgrade-segments step.
上级 e0135329
......@@ -12,7 +12,9 @@ OBJS = check.o controldata.o dump.o exec.o file.o function.o info.o \
# Source files specific to Greenplum
OBJS += aotable.o gpdb4_heap_convert.o version_gp.o \
check_gp.o file_gp.o reporting.o aomd_filehandler.o
check_gp.o file_gp.o reporting.o aomd_filehandler.o \
old_tablespace_file_contents.o old_tablespace_file_parser.o \
tablespace_gp.o old_tablespace_file_parser_hooks.o
PG_CPPFLAGS = -DFRONTEND -DDLSUFFIX=\"$(DLSUFFIX)\" -I$(srcdir) -I$(libpq_srcdir)
PG_LIBS = $(libpq_pgport)
......@@ -22,7 +24,7 @@ EXTRA_CLEAN = analyze_new_cluster.sh delete_old_cluster.sh log/ tmp_check/ \
pg_upgrade_dump_*.custom pg_upgrade_*.log
EXTRA_CLEAN += clusterConfigPostgresAddonsFile clusterConfigFile gpdemo-env.sh \
hostfile regression.diffs aomd_filehandler.c
hostfile regression.diffs aomd_filehandler.c old_tablespaces.txt
ifdef USE_PGXS
PG_CONFIG = pg_config
......
......@@ -86,6 +86,9 @@ check_and_dump_old_cluster(bool live_check, char **sequence_script_file_name)
get_pg_database_relfilenode(&old_cluster);
if (!user_opts.check && user_opts.segment_mode == DISPATCHER)
generate_old_tablespaces_file(&old_cluster);
/* Extract a list of databases and tables from the old cluster */
get_db_and_rel_infos(&old_cluster);
......
......@@ -459,6 +459,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
int numeric_rel_num = 0;
char typestr[QUERY_ALLOC];
int i;
Oid tablespace_oid;
/*
* If we are upgrading from Greenplum 4.3.x we need to record which rels
......@@ -666,14 +667,35 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
curr->relfilenode = atooid(PQgetvalue(res, relnum, i_relfilenode));
curr->tblsp_alloc = false;
tablespace_oid = atooid(PQgetvalue(res, relnum, i_reltablespace));
/* Is the tablespace oid non-zero? */
if (atooid(PQgetvalue(res, relnum, i_reltablespace)) != 0)
if (tablespace_oid != 0)
{
/*
* The tablespace location might be "", meaning the cluster
* default location, i.e. pg_default or pg_global.
*/
tablespace = PQgetvalue(res, relnum, i_spclocation);
bool is_old_cluster = old_cluster.major_version == cluster->major_version;
if (is_old_cluster &&
!is_old_tablespaces_file_empty(old_cluster.old_tablespace_file_contents))
{
char tablespace_path[MAXPGPATH];
char *tablespace_location = old_tablespace_file_get_tablespace_path_for_oid(
old_cluster.old_tablespace_file_contents, tablespace_oid);
snprintf(tablespace_path, sizeof(tablespace_path), "%s/%u",
tablespace_location,
tablespace_oid);
tablespace = tablespace_path;
Assert(tablespace != NULL);
}
else {
/*
* The tablespace location might be "", meaning the cluster
* default location, i.e. pg_default or pg_global.
*/
tablespace = PQgetvalue(res, relnum, i_spclocation);
}
/* Can we reuse the previous string allocation? */
if (last_tablespace && strcmp(tablespace, last_tablespace) == 0)
......
/*-------------------------------------------------------------------------
*
* old_tablespace_file_contents.c
*
* Copyright (c) 2019-Present Pivotal Software, Inc.
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "old_tablespace_file_contents.h"
#include "old_tablespace_file_parser.h"
struct OldTablespaceRecordData {
char *tablespace_path;
Oid tablespace_oid;
char *tablespace_name;
int dbid;
};
struct OldTablespaceFileContentsData {
int number_of_tablespaces;
OldTablespaceRecord **old_tablespace_records;
};
static int
number_of_tablespaces_matching_dbid(OldTablespaceFileContents *originalContents, int dbid_to_find)
{
int number_of_tablespaces = 0;
for(int i = 0; i < originalContents->number_of_tablespaces; i++)
if (originalContents->old_tablespace_records[i]->dbid == dbid_to_find)
number_of_tablespaces++;
return number_of_tablespaces;
}
static bool
matches_dbid(OldTablespaceRecord *record, int dbid)
{
return record->dbid == dbid;
}
static void
copy_tablespace_record(OldTablespaceRecord *originalRecord, OldTablespaceRecord *newRecord)
{
newRecord->dbid = originalRecord->dbid;
newRecord->tablespace_oid = originalRecord->tablespace_oid;
newRecord->tablespace_name = originalRecord->tablespace_name;
newRecord->tablespace_path = originalRecord->tablespace_path;
}
static void
populate_record_from_csv(OldTablespaceRecord *record, OldTablespaceFileParser_Document *document, int row_index)
{
record->dbid =
OldTablespaceFileParser_get_field_as_int(document, row_index, 0);
record->tablespace_oid =
OldTablespaceFileParser_get_field_as_oid(document, row_index, 1);
record->tablespace_name = pg_strdup(
OldTablespaceFileParser_get_field_as_string(document, row_index, 2));
record->tablespace_path = pg_strdup(
OldTablespaceFileParser_get_field_as_string(document, row_index, 3));
}
static void
initialize_old_tablespace_records(OldTablespaceFileContents *contents, int number_of_tablespaces)
{
contents->old_tablespace_records = palloc0(sizeof(OldTablespaceRecord *) * number_of_tablespaces);
for (int i = 0; i < number_of_tablespaces; i++)
contents->old_tablespace_records[i] = palloc0(sizeof(OldTablespaceRecord));
}
static OldTablespaceFileContents *
make_old_tablespace_file_contents(int number_of_tablespaces)
{
OldTablespaceFileContents *contents = palloc0(sizeof(OldTablespaceFileContents));
contents->number_of_tablespaces = number_of_tablespaces;
initialize_old_tablespace_records(contents, number_of_tablespaces);
return contents;
}
static OldTablespaceFileParser_Document *
get_parser_document(const char *const file_path)
{
FILE *file = fopen(file_path, "r");
OldTablespaceFileParser_Document *document =
OldTablespaceFileParser_parse_file(file);
if (file != NULL)
fclose(file);
return document;
}
bool
is_old_tablespaces_file_empty(OldTablespaceFileContents *contents)
{
return contents && contents->number_of_tablespaces == 0;
}
void
clear_old_tablespace_file_contents(OldTablespaceFileContents *contents)
{
for (int i = 0; i < contents->number_of_tablespaces; i++)
pfree(contents->old_tablespace_records[i]);
pfree(contents->old_tablespace_records);
pfree(contents);
}
int
OldTablespaceFileContents_TotalNumberOfTablespaces(OldTablespaceFileContents *contents)
{
return contents->number_of_tablespaces;
}
char **
OldTablespaceFileContents_GetArrayOfTablespacePaths(OldTablespaceFileContents *contents)
{
char ** tablespace_paths = (char **) pg_malloc(contents->number_of_tablespaces * sizeof(char *));
for (int i = 0; i < contents->number_of_tablespaces; i++)
tablespace_paths[i] = pg_strdup(contents->old_tablespace_records[i]->tablespace_path);
return tablespace_paths;
}
OldTablespaceRecord *
OldTablespaceFileContents_GetTablespaceRecord(OldTablespaceFileContents *contents, int dbid, char *tablespace_name)
{
for (int i = 0; i < OldTablespaceFileContents_TotalNumberOfTablespaces(contents); i++)
{
OldTablespaceRecord *current_record = contents->old_tablespace_records[i];
if (strcmp(current_record->tablespace_name, tablespace_name) == 0 && current_record->dbid == dbid)
return current_record;
}
return NULL;
}
/*
* expects file to have the fields:
*
* [dbid],[tablespace oid],[tablespace name],[path]
*
*/
OldTablespaceFileContents *
parse_old_tablespace_file_contents(const char *const file_path)
{
OldTablespaceFileParser_Document *document = get_parser_document(file_path);
OldTablespaceFileContents *contents = make_old_tablespace_file_contents(
OldTablespaceFileParser_number_of_rows(document));
for (int i = 0; i < contents->number_of_tablespaces; i++)
populate_record_from_csv(contents->old_tablespace_records[i], document, i);
OldTablespaceFileParser_clear_document(document);
return contents;
}
OldTablespaceFileContents*
filter_old_tablespace_file_for_dbid(OldTablespaceFileContents *originalContents, int dbid_to_find)
{
int match_index = 0;
OldTablespaceFileContents *result = make_old_tablespace_file_contents(
number_of_tablespaces_matching_dbid(originalContents, dbid_to_find));
for(int i = 0; i < originalContents->number_of_tablespaces; i++)
{
OldTablespaceRecord *originalRecord = originalContents->old_tablespace_records[i];
OldTablespaceRecord *newRecord = result->old_tablespace_records[match_index];
if (matches_dbid(originalRecord, dbid_to_find))
{
match_index++;
copy_tablespace_record(originalRecord, newRecord);
}
}
return result;
}
char *
old_tablespace_file_get_tablespace_path_for_oid(OldTablespaceFileContents *contents, Oid tablespace_oid)
{
OldTablespaceRecord *currentRecord;
for (int i = 0; i < contents->number_of_tablespaces; i++)
{
currentRecord = contents->old_tablespace_records[i];
if (currentRecord->tablespace_oid == tablespace_oid)
return currentRecord->tablespace_path;
}
return NULL;
}
OldTablespaceRecord **
OldTablespaceFileContents_GetTablespaceRecords(OldTablespaceFileContents *contents)
{
return contents->old_tablespace_records;
}
char *
OldTablespaceRecord_GetTablespaceName(OldTablespaceRecord *record)
{
return record->tablespace_name;
}
char *
OldTablespaceRecord_GetDirectoryPath(OldTablespaceRecord *record)
{
return record->tablespace_path;
}
/*-------------------------------------------------------------------------
*
* old_tablespace_file_contents.h
*
* Data type to hold Greenplum 5's filespace and tablespace information
* to be used by upgrade.
*
* Copyright (c) 2019-Present Pivotal Software, Inc.
*/
#ifndef OLD_TABLESPACE_FILE_CONTENTS_H
#define OLD_TABLESPACE_FILE_CONTENTS_H
#include "postgres_ext.h"
#include "postgres_fe.h"
typedef struct OldTablespaceFileContentsData OldTablespaceFileContents;
typedef struct OldTablespaceRecordData OldTablespaceRecord;
int
OldTablespaceFileContents_TotalNumberOfTablespaces(OldTablespaceFileContents *contents);
char **
OldTablespaceFileContents_GetArrayOfTablespacePaths(OldTablespaceFileContents *contents);
/*
* Return an OldTablespaceFileContents containing tablespaces in the given csv
* file.
*
* File contents expected to contain rows with the structure:
*
* "dbid","tablespace oid","tablespace path"
*
*/
OldTablespaceFileContents *
parse_old_tablespace_file_contents(const char *file_path);
/*
* Return an OldTablespaceFileContents containing only tablespaces for the
* given dbid
*/
OldTablespaceFileContents *
filter_old_tablespace_file_for_dbid(OldTablespaceFileContents *contents, int dbid);
OldTablespaceRecord *
OldTablespaceFileContents_GetTablespaceRecord(
OldTablespaceFileContents *contents,
int dbid,
char *tablespace_name);
OldTablespaceRecord **
OldTablespaceFileContents_GetTablespaceRecords(OldTablespaceFileContents *contents);
char *
OldTablespaceRecord_GetTablespaceName(OldTablespaceRecord *record);
char *
OldTablespaceRecord_GetDirectoryPath(OldTablespaceRecord *record);
/*
* free memory allocated for OldTablespaceFileContents
*/
void clear_old_tablespace_file_contents(OldTablespaceFileContents *contents);
bool is_old_tablespaces_file_empty(OldTablespaceFileContents *contents);
/*
* Get the file path for a given old tablespace for the given tablespace oid
*/
char *old_tablespace_file_get_tablespace_path_for_oid(
OldTablespaceFileContents *contents, Oid oid);
#endif /* OLD_TABLESPACE_FILE_CONTENTS_H */
/*-------------------------------------------------------------------------
*
* old_tablespace_file_parser.c
*
* Copyright (c) 2019-Present Pivotal Software, Inc.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "old_tablespace_file_parser.h"
#include "postgres_fe.h"
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
#define MAX_ROW_LENGTH 2000
#define MAX_NUMBER_OF_COLUMNS 10
typedef struct OldTablespaceFileParser_Row {
int number_of_cells;
char **cells;
} OldTablespaceFileParser_Row;
struct OldTablespaceFileParser_DocumentData
{
int number_of_rows;
OldTablespaceFileParser_Row **rows;
};
static void
parse_row(int current_row_index, OldTablespaceFileParser_Document *document, char row[MAX_ROW_LENGTH])
{
char *tokens[MAX_NUMBER_OF_COLUMNS] = {0};
int number_of_tokens = 0;
char *token = NULL;
char *token_position;
char *newline_position;
char *row_text = pg_strdup(row);
token = strtok_r(row_text, ",", &token_position);
while (token != NULL && number_of_tokens < MAX_NUMBER_OF_COLUMNS)
{
tokens[number_of_tokens] = strtok_r(token, "\n", &newline_position);
number_of_tokens++;
token = strtok_r(NULL, ",", &token_position);
}
OldTablespaceFileParser_Row *parser_row = palloc0(sizeof(OldTablespaceFileParser_Row));
parser_row->number_of_cells = number_of_tokens;
parser_row->cells = palloc0(sizeof(char*) * number_of_tokens);
for (int i = 0; i < number_of_tokens; i++)
parser_row->cells[i] = pg_strdup(tokens[i]);
document->rows[current_row_index] = parser_row;
pfree(row_text);
}
static void
free_parser_row(OldTablespaceFileParser_Row *row)
{
for (int i = 0; i < row->number_of_cells; i++)
pfree(row->cells[i]);
pfree(row);
}
static OldTablespaceFileParser_Document *
make_document(int number_of_rows)
{
OldTablespaceFileParser_Document *document = palloc0(sizeof(OldTablespaceFileParser_Document));
document->number_of_rows = number_of_rows;
document->rows = palloc0(sizeof(document->rows) * document->number_of_rows);
return document;
}
OldTablespaceFileParser_Document *
OldTablespaceFileParser_parse_file(FILE *file)
{
int number_of_rows = 0;
int current_row_index = 0;
char contents[MAX_ROW_LENGTH];
if (file == NULL)
return make_document(0);
/*
* determine number of rows
*/
while ((fgets(contents, MAX_ROW_LENGTH, file)) != NULL)
number_of_rows++;
/*
* reset the for reading again
*/
rewind(file);
/*
* initialize document
*/
OldTablespaceFileParser_Document *document = make_document(number_of_rows);
/*
* populate document
*/
char *row_contents = palloc0(sizeof(char) * MAX_ROW_LENGTH);
while ((fgets(row_contents, MAX_ROW_LENGTH, file)) != NULL)
parse_row(current_row_index++, document, row_contents);
return document;
}
char *
OldTablespaceFileParser_get_field_as_string(OldTablespaceFileParser_Document *document, int row_index, int field_index)
{
if (row_index >= document->number_of_rows)
{
OldTablespaceFileParser_invalid_access_error_for_row(row_index);
return NULL;
}
OldTablespaceFileParser_Row *row = document->rows[row_index];
if (field_index >= row->number_of_cells)
{
OldTablespaceFileParser_invalid_access_error_for_field(row_index, field_index);
return NULL;
}
return row->cells[field_index];
}
int
OldTablespaceFileParser_number_of_rows(OldTablespaceFileParser_Document *document)
{
return document->number_of_rows;
}
int
OldTablespaceFileParser_get_field_as_int(OldTablespaceFileParser_Document *document, int row_index, int field_index)
{
char *field = OldTablespaceFileParser_get_field_as_string(document,
row_index,
field_index);
if (field == NULL) return -1;
return atoi(field);
}
Oid
OldTablespaceFileParser_get_field_as_oid(OldTablespaceFileParser_Document *document, int row_index, int field_index)
{
char *field = OldTablespaceFileParser_get_field_as_string(document,
row_index,
field_index);
if (field == NULL) return InvalidOid;
return atooid(field);
}
void
OldTablespaceFileParser_clear_document(OldTablespaceFileParser_Document *document)
{
for (int i = 0; i < document->number_of_rows; i++)
free_parser_row(document->rows[i]);
pfree(document);
}
/*-------------------------------------------------------------------------
*
* old_tablespace_file_parser.h
*
* Responsible for reading a file and being able to extract data from it
* for use when populating OldTablespaceFileContents.
*
* Copyright (c) 2019-Present Pivotal Software, Inc.
*
*/
#include <stdio.h>
#include "postgres_ext.h"
typedef struct OldTablespaceFileParser_DocumentData OldTablespaceFileParser_Document;
enum OldTablespaceFileParser_Field {
OldTablespace_gp_dbid,
OldTablespace_tablespace_oid,
OldTablespace_tablespace_name,
OldTablespace_tablespace_path
};
/*
* Read through file and present contents as rows:
*
* File is expected to have rows structured as
*
* [gp dbid],[tablespace oid],[tablespace name],[tablespace path]
*/
OldTablespaceFileParser_Document *OldTablespaceFileParser_parse_file(FILE *file);
/*
* free memory allocated by OldTablespaceFileParser_parse_file
*/
void OldTablespaceFileParser_clear_document(OldTablespaceFileParser_Document *document);
/*
* Return the number of records in the document
*/
int OldTablespaceFileParser_number_of_rows(OldTablespaceFileParser_Document *document);
char *OldTablespaceFileParser_get_field_as_string(OldTablespaceFileParser_Document* document, int row_number, int field_index);
int OldTablespaceFileParser_get_field_as_int(OldTablespaceFileParser_Document* document, int row_index, int field_index);
Oid OldTablespaceFileParser_get_field_as_oid(OldTablespaceFileParser_Document *document, int row_index, int field_index);
/*
* Expected to be implemented by the main runner.
*/
extern void OldTablespaceFileParser_invalid_access_error_for_row(int row_index);
extern void OldTablespaceFileParser_invalid_access_error_for_field(int row_index, int field_index);
#include "pg_upgrade.h"
#include "old_tablespace_file_parser.h"
void
OldTablespaceFileParser_invalid_access_error_for_row(int invalid_row_index)
{
pg_fatal("attempted to read an invalid row from an old tablespace file. row index %d",
invalid_row_index);
}
void
OldTablespaceFileParser_invalid_access_error_for_field(int invalid_row_index, int invalid_field_index)
{
pg_fatal("attempted to read an invalid field from an old tablespace file. row index %d, field index %d",
invalid_row_index, invalid_field_index);
}
......@@ -26,11 +26,10 @@ static void check_required_directory(char **dirpath,
const char *envVarName, bool useCwd,
const char *cmdLineOption, const char *description);
#define FIX_DEFAULT_READ_ONLY "-c default_transaction_read_only=false"
#define GP_DBID_NOT_SET -1
UserOpts user_opts;
/*
* parseCommandLine()
*
......@@ -62,6 +61,9 @@ parseCommandLine(int argc, char *argv[])
{"progress", no_argument, NULL, 2},
{"add-checksum", no_argument, NULL, 3},
{"remove-checksum", no_argument, NULL, 4},
{"old-gp-dbid", required_argument, NULL, 5},
{"new-gp-dbid", required_argument, NULL, 6},
{"old-tablespaces-file", required_argument, NULL, 7},
{NULL, 0, NULL, 0}
};
......@@ -73,6 +75,11 @@ parseCommandLine(int argc, char *argv[])
time_t run_time = time(NULL);
user_opts.transfer_mode = TRANSFER_MODE_COPY;
user_opts.old_tablespace_file_path = NULL;
old_cluster.gp_dbid = GP_DBID_NOT_SET;
new_cluster.gp_dbid = GP_DBID_NOT_SET;
old_cluster.old_tablespace_file_contents = NULL;
os_info.progname = get_progname(argv[0]);
......@@ -228,6 +235,18 @@ parseCommandLine(int argc, char *argv[])
case 4: /* --remove-checksum */
user_opts.checksum_mode = CHECKSUM_REMOVE;
break;
case 5: /* --old-gp-dbid */
old_cluster.gp_dbid = atoi(optarg);
break;
case 6: /* --new-gp-dbid */
new_cluster.gp_dbid = atoi(optarg);
break;
case 7: /* --old-tablespaces-file */
user_opts.old_tablespace_file_path = pg_strdup(optarg);
break;
default:
pg_fatal("Try \"%s --help\" for more information.\n",
......@@ -279,6 +298,18 @@ parseCommandLine(int argc, char *argv[])
if (user_opts.transfer_mode != TRANSFER_MODE_COPY &&
user_opts.checksum_mode != CHECKSUM_NONE)
pg_log(PG_FATAL, "Adding and removing checksums only supported in copy mode.\n");
if (old_cluster.gp_dbid == GP_DBID_NOT_SET)
pg_fatal("--old-gp-dbid must be set");
if (new_cluster.gp_dbid == GP_DBID_NOT_SET)
pg_fatal("--new-gp-dbid must be set");
if (user_opts.old_tablespace_file_path) {
populate_old_cluster_with_old_tablespaces(
&old_cluster,
user_opts.old_tablespace_file_path);
}
}
......@@ -310,6 +341,9 @@ Options:\n\
--progress enable progress reporting\n\
--remove-checksum remove data checksums when creating new cluster\n\
--add-checksum add data checksumming to the new cluster\n\
--old-gp-dbid greenplum database id of the old segment\n\
--new-gp-dbid greenplum database id of the new segment\n\
--old-tablespaces-file file containing the tablespaces from an old gpdb five cluster\n\
-?, --help show this help, then exit\n\
\n\
Before running pg_upgrade you must:\n\
......
......@@ -15,6 +15,8 @@
#include "libpq-fe.h"
#include "pqexpbuffer.h"
#include "old_tablespace_file_contents.h"
/* Use port in the private/dynamic port number range */
#define DEF_PGUPORT 50432
......@@ -39,6 +41,7 @@
#define GLOBALS_OIDS_DUMP_FILE "pg_upgrade_dump_globals_oids.sql"
#define DB_OIDS_DUMP_FILE_MASK "pg_upgrade_dump_%u_oids.sql"
#define OLD_TABLESPACES_FILE "old_tablespaces.txt"
/* needs to be kept in sync with pg_class.h */
#define RELSTORAGE_EXTERNAL 'x'
......@@ -407,6 +410,9 @@ typedef struct
const char *tablespace_suffix; /* directory specification */
char *global_reserved_oids; /* OID preassign calls for shared objects */
int gp_dbid; /* greenplum database id of the cluster */
OldTablespaceFileContents *old_tablespace_file_contents;
} ClusterInfo;
......@@ -435,6 +441,7 @@ typedef struct
bool progress;
segmentMode segment_mode;
checksumMode checksum_mode;
char *old_tablespace_file_path;
} UserOpts;
......@@ -582,6 +589,12 @@ void transfer_all_new_dbs(DbInfoArr *old_db_arr,
void init_tablespaces(void);
/* tablespace_gp.c */
void populate_old_cluster_with_old_tablespaces(ClusterInfo *oldCluster, const char *file_path);
void generate_old_tablespaces_file(ClusterInfo *oldCluster);
void populate_gpdb6_cluster_tablespace_suffix(ClusterInfo *cluster);
/* server.c */
......@@ -699,3 +712,11 @@ void check_greenplum(void);
void report_progress(ClusterInfo *cluster, progress_type op, char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
void close_progress(void);
static inline bool
is_gpdb6(ClusterInfo *cluster)
{
return GET_MAJOR_VERSION(cluster->major_version) == 904;
}
......@@ -240,15 +240,23 @@ start_postmaster(ClusterInfo *cluster, bool throw_error)
version_opts = "-c synchronous_standby_names='' --xid_warn_limit=10000000";
else
version_opts = "-c gp_num_contents_in_cluster=1";
char *mode_opts = "";
int gp_dbid;
int gp_content_id;
if (user_opts.segment_mode == DISPATCHER)
mode_opts = "-c gp_dbid=1 -c gp_contentid=-1 ";
{
gp_dbid = 1;
gp_content_id = -1;
}
else
mode_opts = "-c gp_dbid=1 -c gp_contentid=0 ";
{
gp_dbid = cluster->gp_dbid;
gp_content_id = 0;
}
snprintf(cmd, sizeof(cmd),
"\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d -c gp_role=utility %s%s %s%s %s %s\" start",
"\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d -c gp_role=utility %s%s %s%s %s --gp_dbid=%d --gp_contentid=%d \" start",
cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
(cluster->controldata.cat_ver >=
BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? " -b" :
......@@ -256,7 +264,7 @@ start_postmaster(ClusterInfo *cluster, bool throw_error)
(cluster == &new_cluster) ?
" -c synchronous_commit=off -c fsync=off -c full_page_writes=off" : "",
cluster->pgopts ? cluster->pgopts : "", socket_string, version_opts,
mode_opts);
gp_dbid, gp_content_id);
/*
* Don't throw an error right away, let connecting throw the error because
* it might supply a reason for the failure.
......
......@@ -12,11 +12,11 @@
#include "pg_upgrade.h"
#include <sys/types.h>
#include "old_tablespace_file_contents.h"
static void get_tablespace_paths(void);
static void set_tablespace_directory_suffix(ClusterInfo *cluster);
void
init_tablespaces(void)
{
......@@ -31,6 +31,46 @@ init_tablespaces(void)
"using tablespaces.\n");
}
static void
populate_os_info_with_file_contents(OldTablespaceFileContents *contents)
{
os_info.num_old_tablespaces = OldTablespaceFileContents_TotalNumberOfTablespaces(contents);
os_info.old_tablespaces = OldTablespaceFileContents_GetArrayOfTablespacePaths(contents);
}
static void
verify_old_tablespace_paths(void)
{
for (int tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
{
struct stat statBuf;
/*
* Check that the tablespace path exists and is a directory.
* Effectively, this is checking only for tables/indexes in
* non-existent tablespace directories. Databases located in
* non-existent tablespaces already throw a backend error.
* Non-existent tablespace directories can occur when a data directory
* that contains user tablespaces is moved as part of pg_upgrade
* preparation and the symbolic links are not updated.
*/
if (stat(os_info.old_tablespaces[tblnum], &statBuf) != 0)
{
if (errno == ENOENT)
report_status(PG_FATAL,
"tablespace directory \"%s\" does not exist\n",
os_info.old_tablespaces[tblnum]);
else
report_status(PG_FATAL,
"cannot stat() tablespace directory \"%s\": %s\n",
os_info.old_tablespaces[tblnum], getErrorText());
}
if (!S_ISDIR(statBuf.st_mode))
report_status(PG_FATAL,
"tablespace path \"%s\" is not a directory\n",
os_info.old_tablespaces[tblnum]);
}
}
/*
* get_tablespace_paths()
......@@ -41,6 +81,12 @@ init_tablespaces(void)
static void
get_tablespace_paths(void)
{
if (!is_old_tablespaces_file_empty(old_cluster.old_tablespace_file_contents)) {
populate_os_info_with_file_contents(old_cluster.old_tablespace_file_contents);
verify_old_tablespace_paths();
return;
}
PGconn *conn = connectToServer(&old_cluster, "template1");
PGresult *res;
int tblnum;
......@@ -70,37 +116,13 @@ get_tablespace_paths(void)
i_spclocation = PQfnumber(res, "spclocation");
for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
{
struct stat statBuf;
os_info.old_tablespaces[tblnum] = pg_strdup(
PQgetvalue(res, tblnum, i_spclocation));
/*
* Check that the tablespace path exists and is a directory.
* Effectively, this is checking only for tables/indexes in
* non-existent tablespace directories. Databases located in
* non-existent tablespaces already throw a backend error.
* Non-existent tablespace directories can occur when a data directory
* that contains user tablespaces is moved as part of pg_upgrade
* preparation and the symbolic links are not updated.
*/
if (stat(os_info.old_tablespaces[tblnum], &statBuf) != 0)
{
if (errno == ENOENT)
report_status(PG_FATAL,
"tablespace directory \"%s\" does not exist\n",
os_info.old_tablespaces[tblnum]);
else
report_status(PG_FATAL,
"cannot stat() tablespace directory \"%s\": %s\n",
os_info.old_tablespaces[tblnum], getErrorText());
}
if (!S_ISDIR(statBuf.st_mode))
report_status(PG_FATAL,
"tablespace path \"%s\" is not a directory\n",
os_info.old_tablespaces[tblnum]);
}
/*
* gpdb: verification logic has been extracted from the above loop for reuse
*/
verify_old_tablespace_paths();
PQclear(res);
......@@ -109,10 +131,17 @@ get_tablespace_paths(void)
return;
}
static void
set_tablespace_directory_suffix(ClusterInfo *cluster)
{
/*
* GPDB 6 introduced a new layout for tablespaces
*/
if (is_gpdb6(cluster)) {
populate_gpdb6_cluster_tablespace_suffix(cluster);
return;
}
if (GET_MAJOR_VERSION(cluster->major_version) <= 804)
cluster->tablespace_suffix = pg_strdup("");
else
......
/*-------------------------------------------------------------------------
*
* tablespace_gp.c
*
* Greenplum specific functions for preparing pg_upgrade to perform an upgrade
* of Greenplum's tablespaces.
*
* Copyright (c) 2019-Present Pivotal Software, Inc.
*
*/
#include "pg_upgrade.h"
static char *
get_generated_old_tablespaces_file_path(void)
{
char current_working_directory[MAXPGPATH];
char *result = getcwd(current_working_directory, sizeof(current_working_directory));
if (result == NULL)
pg_fatal("could not determine current working directory");
return psprintf("%s/%s", current_working_directory, OLD_TABLESPACES_FILE);
}
static inline bool
is_gpdb_version_with_filespaces(ClusterInfo *cluster)
{
return GET_MAJOR_VERSION(cluster->major_version) < 904;
}
static void
dump_old_tablespaces(ClusterInfo *oldCluster, char *generated_old_tablespaces_file_path)
{
if (!is_gpdb_version_with_filespaces(oldCluster))
return;
prep_status("Creating a dump of all tablespace metadata.");
PGconn *connection = connectToServer(oldCluster, "template1");
PGresult *result = executeQueryOrDie(connection, "copy ("
" select fsedbid, pg_tablespace.oid, spcname, fselocation "
" from pg_filespace_entry "
" inner join pg_tablespace on fsefsoid = spcfsoid "
" where spcname not in ("
" 'pg_default', 'pg_global') "
") to '%s' WITH CSV", generated_old_tablespaces_file_path);
PQclear(result);
PQfinish(connection);
check_ok();
}
void
generate_old_tablespaces_file(ClusterInfo *oldCluster)
{
char *generated_old_tablespaces_file_path = get_generated_old_tablespaces_file_path();
dump_old_tablespaces(oldCluster, generated_old_tablespaces_file_path);
populate_old_cluster_with_old_tablespaces(oldCluster, generated_old_tablespaces_file_path);
pfree(generated_old_tablespaces_file_path);
}
void
populate_old_cluster_with_old_tablespaces(ClusterInfo *oldCluster, const char *const file_path)
{
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents(
file_path);
oldCluster->old_tablespace_file_contents = filter_old_tablespace_file_for_dbid(
contents,
oldCluster->gp_dbid);
clear_old_tablespace_file_contents(contents);
}
void
populate_gpdb6_cluster_tablespace_suffix(ClusterInfo *cluster)
{
cluster->tablespace_suffix = psprintf("/%d/GPDB_6_%d",
cluster->gp_dbid,
cluster->controldata.cat_ver);
}
......@@ -16,4 +16,5 @@
/*.sh
/scripts/gpdb5-cluster
/scripts/gpdb6-cluster
\ No newline at end of file
/scripts/gpdb6-cluster
/scripts/pg-upgrade-copy-from-master
......@@ -11,15 +11,19 @@ OBJS = bdd-library/bdd.o \
$(scripts_objs) \
$(utilities_objs) \
$(scenario_objs) \
greenplum_five_to_greenplum_six_upgrade_test_suite.o
greenplum_five_to_greenplum_six_upgrade_test_suite.o \
tablespace_gp_test.o
EXS = scripts/gpdb6-cluster scripts/gpdb5-cluster
TARGETS = greenplum_five_to_greenplum_six_upgrade_test_suite
EXS = scripts/gpdb6-cluster \
scripts/gpdb5-cluster
TARGETS = greenplum_five_to_greenplum_six_upgrade_test_suite \
tablespace_gp_test
include $(top_srcdir)/src/Makefile.global
include $(top_srcdir)/src/Makefile.mock
all: scripts/gpdb5-cluster scripts/gpdb6-cluster
all: scripts/gpdb5-cluster scripts/gpdb6-cluster scripts/pg-upgrade-copy-from-master
#
# Scripts
......@@ -30,6 +34,16 @@ scripts/gpdb5-cluster: scripts/gpdb5-cluster.o utilities/gpdb5-cluster.o
scripts/gpdb6-cluster: scripts/gpdb6-cluster.o utilities/gpdb6-cluster.o
override LDFLAGS += -lasan $(libpq_pgport)
override CPPFLAGS += -I $(pg_upgrade_directory) -I$(libpq_srcdir)
scripts/pg-upgrade-copy-from-master.o: override CPPFLAGS += -I $(pg_upgrade_directory)
scripts/pg-upgrade-copy-from-master: scripts/pg-upgrade-copy-from-master.o \
utilities/pg-upgrade-copy.o \
$(pg_upgrade_directory)/old_tablespace_file_contents.o \
$(pg_upgrade_directory)/old_tablespace_file_parser.o
#
# Libraries
#
......@@ -49,12 +63,24 @@ $(utilities_objs) \
test_dependencies = bdd-library/bdd.o \
$(utilities_objs) \
$(scenario_objs) \
$(CMOCKERY_OBJS)
$(CMOCKERY_OBJS) \
$(pg_upgrade_directory)/old_tablespace_file_contents.o \
$(pg_upgrade_directory)/old_tablespace_file_parser.o
debugging_flags = -Og -g -fsanitize=address -Wextra -Wpedantic -pedantic-errors -Werror
debugging_flags = -Og -g
compile_test = $(CC) $(CFLAGS) $(debugging_flags) $^ $(libpq_pgport) $(LDFLAGS) -o $@
greenplum_five_to_greenplum_six_upgrade_test_suite.t: greenplum_five_to_greenplum_six_upgrade_test_suite.o $(test_dependencies)
$(CC) $(CFLAGS) $(debugging_flags) $^ $(libpq_pgport) $(LDFLAGS) -o $@
$(compile_test)
tablespace_gp_test.t: tablespace_gp_test.o $(test_dependencies) \
$(pg_upgrade_directory)/tablespace_gp.o \
$(pg_upgrade_directory)/util.o \
$(pg_upgrade_directory)/server.o \
$(pg_upgrade_directory)/exec.o \
$(pg_upgrade_directory)/reporting.o
$(compile_test)
clean:
rm -f $(OBJS) $(EXS)
......@@ -3,6 +3,7 @@
#include <setjmp.h>
#include "cmockery.h"
#include "old_tablespace_file_parser.h"
#include "scenarios/partitioned_ao_table.h"
#include "scenarios/partitioned_heap_table.h"
......@@ -17,11 +18,12 @@
#include "scenarios/pl_function.h"
#include "scenarios/user_defined_types.h"
#include "scenarios/external_tables.h"
#include "scenarios/filespaces_to_tablespaces.h"
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/row-assertions.h"
......@@ -44,12 +46,33 @@ teardown(void **state)
stopGpdbSixCluster();
}
void
OldTablespaceFileParser_invalid_access_error_for_field(int invalid_row_index, int invalid_field_index)
{
printf("attempted to access invalid field: {row_index=%d, field_index=%d}",
invalid_row_index,
invalid_field_index);
exit(1);
}
void
OldTablespaceFileParser_invalid_access_error_for_row(int invalid_row_index)
{
printf("attempted to access invalid row: {row_index=%d}",
invalid_row_index);
exit(1);
}
int
main(int argc, char *argv[])
{
cmockery_parse_arguments(argc, argv);
const UnitTest tests[] = {
unit_test_setup_teardown(test_a_filespace_can_be_upgraded_into_new_tablespaces, setup, teardown),
unit_test_setup_teardown(test_a_readable_external_table_can_be_upgraded, setup, teardown),
unit_test_setup_teardown(test_a_partition_table_with_default_partition_after_split_can_be_upgraded, setup, teardown),
unit_test_setup_teardown(test_a_partition_table_with_newly_added_range_partition_can_be_upgraded, setup, teardown),
......
......@@ -10,7 +10,7 @@
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
......
......@@ -10,7 +10,7 @@
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
......
......@@ -5,7 +5,7 @@
#include "cmockery.h"
#include "data_checksum_mismatch.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/test-helpers.h"
#include "bdd-library/bdd.h"
......
......@@ -6,7 +6,7 @@
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
......
......@@ -5,7 +5,7 @@
#include "cmockery.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/bdd-helpers.h"
......
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <string.h>
#include "cmockery.h"
#include "libpq-fe.h"
#include "stdbool.h"
#include "stdlib.h"
#include "sys/stat.h"
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/bdd-helpers.h"
#include "utilities/row-assertions.h"
#include "filespaces_to_tablespaces.h"
static void
aFilespaceExistsInTheFiveClusterWithATableAndData(void)
{
startGpdbFiveCluster();
PGconn *connection5 = connectToFive();
PGresult *result5;
/*
* Create filespace directories
*/
system("rm -rf /tmp/gpdb-filespaces");
system("mkdir /tmp/gpdb-filespaces");
/*
* Create filespace and tablespace within the filespace.
* Note that supplying identical location dirs for the primary and mirror
* in a primary-mirror pair requires a multi-node test setup.
* These locations are ignored in the filespace->tablespace upgrade as the
* primary locations are used to generate the necessary DDL and tablespace
* map. Thus, we supply dummy directories here just to make the syntax
* check happy.
*/
result5 = executeQuery(connection5, "CREATE FILESPACE some_filespace ( \n"
"1: '/tmp/gpdb-filespaces/fsseg-1/', \n"
"2: '/tmp/gpdb-filespaces/fsseg0/', \n"
"3: '/tmp/gpdb-filespaces/fsseg1/', \n"
"4: '/tmp/gpdb-filespaces/fsseg2/', \n"
"5: '/tmp/gpdb-filespaces/fsdummy1/', \n"
"6: '/tmp/gpdb-filespaces/fsdummy2/', \n"
"7: '/tmp/gpdb-filespaces/fsdummy3/', \n"
"8: '/tmp/gpdb-filespaces/fsdummy4/' );");
PQclear(result5);
result5 = executeQuery(connection5, "CREATE TABLESPACE some_tablespace FILESPACE some_filespace;");
PQclear(executeQuery(connection5, "CREATE SCHEMA five_to_six_upgrade;"));
PQclear(executeQuery(connection5, "set search_path to five_to_six_upgrade;"));
result5 = executeQuery(connection5, "CREATE TABLE users (id integer, name text) TABLESPACE some_tablespace;");
result5 = executeQuery(connection5, "insert into users VALUES (1, 'Joe');");
result5 = executeQuery(connection5, "insert into users VALUES (2, 'Janet');");
result5 = executeQuery(connection5, "insert into users VALUES (3, 'James');");
PQclear(result5);
PQfinish(connection5);
}
static void
anAdministratorPerformsAnUpgradeWithATablespaceMappingFile(void)
{
performUpgradeWithTablespaces("./old_tablespaces.txt");
}
typedef struct UserData
{
int id;
char *name;
} User;
static Rows *
extract_rows(PGresult *result)
{
int number_of_rows = PQntuples(result);
Rows *rows = calloc(1, sizeof(Rows));
int id_column_index = PQfnumber(result, "id");
int name_column_index = PQfnumber(result, "name");
for (int i = 0; i < number_of_rows; i++)
{
User *user = calloc(1, sizeof(User));
user->id = atoi(PQgetvalue(result, i, id_column_index));
user->name = PQgetvalue(result, i, name_column_index);
rows->rows[i] = user;
}
rows->size = number_of_rows;
return rows;
}
static Rows *
queryForRows(char *queryString)
{
PGconn *connection = connectToSix();
PGresult *result = executeQuery(connection, queryString);
Rows *rows = extract_rows(result);
PQfinish(connection);
return rows;
}
static bool
users_match(void *expected, void *actual)
{
User *first_user = (User *) expected;
User *second_user = (User *) actual;
return strcmp(first_user->name, second_user->name) == 0 &&
first_user->id == second_user->id;
}
static void match_failed_for_user(void *expected_row)
{
User *expected_user = (User*) expected_row;
printf("==============> expected {.id=%d, .name=%s} to be in actual rows\n",
expected_user->id,
expected_user->name);
}
static void
aTablespaceShouldHaveBeenCreatedOnSixCluster(void)
{
startGpdbSixCluster();
matcher = users_match;
match_failed = match_failed_for_user;
Rows *rows = queryForRows("select * from five_to_six_upgrade.users;");
User joe = {.id = 1, .name = "Joe"};
User janet = {.id = 2, .name = "Janet"};
User james = {.id = 3, .name = "James"};
assert_rows(rows, (Rows) {
.size = 3,
.rows = {&joe, &janet, &james}
});
stopGpdbSixCluster();
}
static void
expectTablespaceDirectoryToExist(char *directory_path)
{
struct stat fileInformation;
int success = stat(directory_path, &fileInformation) == 0;
if (!success)
fail_msg("expected the tablespace directory \"%s\" to exist, but does not.", directory_path);
assert_true(success);
}
static void
theTablespacesInTheNewClusterShouldBeCreatedInTheSameLocationAsTheOldClustersTablespaces(void)
{
expectTablespaceDirectoryToExist("/tmp/gpdb-filespaces/fsseg-1/1");
expectTablespaceDirectoryToExist("/tmp/gpdb-filespaces/fsseg0/2");
expectTablespaceDirectoryToExist("/tmp/gpdb-filespaces/fsseg1/3");
expectTablespaceDirectoryToExist("/tmp/gpdb-filespaces/fsseg2/4");
}
void
test_a_filespace_can_be_upgraded_into_new_tablespaces(void **state)
{
given(withinGpdbFiveCluster(aFilespaceExistsInTheFiveClusterWithATableAndData));
when(anAdministratorPerformsAnUpgradeWithATablespaceMappingFile);
then(withinGpdbSixCluster(aTablespaceShouldHaveBeenCreatedOnSixCluster));
and(theTablespacesInTheNewClusterShouldBeCreatedInTheSameLocationAsTheOldClustersTablespaces);
}
#ifndef GPDB6_FILESPACES_TO_TABLESPACES_H
#define GPDB6_FILESPACES_TO_TABLESPACES_H
void
test_a_filespace_can_be_upgraded_into_new_tablespaces(void **state);
#endif //GPDB6_FILESPACES_TO_TABLESPACES_H
......@@ -12,7 +12,7 @@
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/bdd-helpers.h"
......
......@@ -4,7 +4,7 @@
#include "cmockery.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/bdd-helpers.h"
......
......@@ -8,7 +8,7 @@
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/bdd-helpers.h"
......
......@@ -8,7 +8,7 @@
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
......
......@@ -9,7 +9,7 @@
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
......
......@@ -11,7 +11,7 @@
#include "utilities/gpdb6-cluster.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "pl_function.h"
......
......@@ -11,7 +11,7 @@
#include "utilities/bdd-helpers.h"
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/row-assertions.h"
......
......@@ -9,7 +9,7 @@
#include "utilities/bdd-helpers.h"
#include "utilities/query-helpers.h"
#include "utilities/test-helpers.h"
#include "utilities/upgrade-helpers.h"
#include "utilities/test-upgrade-helpers.h"
#include "user_defined_types.h"
......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <getopt.h>
#include "postgres_fe.h"
#include "utilities/pg-upgrade-copy.h"
#include "old_tablespace_file_parser.h"
static void
print_usage_header(char *message)
{
printf("\n%s\n", message);
}
static void
print_usage_detail(char *message)
{
printf(" %s\n", message);
}
static void
print_usage(void)
{
print_usage_header("usage: ./pg-upgrade-copy-from-master --[prepare|enable]");
print_usage_detail("--prepare : perform copy steps while preserving necessary configuration files");
print_usage_detail("--enable : place backed up configuration files in production location");
print_usage_detail("");
print_usage_header("not intended for production use. used in pre-production clusters only.");
print_usage_detail("");
print_usage_header("required options:");
print_usage_detail("--master-host-username=[USERNAME] : username to be used by rsync to copy files from master");
print_usage_detail("--master-hostname=[HOSTNAME] : hostname to be used by rsync to copy files from master");
print_usage_detail("--master-data-directory=[PATH] : full path to the master's data directory");
print_usage_detail("--old-master-gp-dbid=[INTEGER] : greenplum dbid used by the old master");
print_usage_detail("--new-master-gp-dbid=[INTEGER] : greenplum dbid used by the new master");
print_usage_detail("--new-segment-path=[PATH] : full path to the segment's data directory");
print_usage_detail("--new-gp-dbid=[INTEGER] : greenplum dbid used by the new segment");
print_usage_detail("--old-tablespace-mapping-file=[PATH] : path to the old tablespaces file generated by the upgrade of master");
}
typedef enum Command
{
Command_Prepare,
Command_Enable,
Command_NotSet
} Command;
static struct option long_options[] = {
{"prepare", no_argument, NULL, 'p'},
{"enable", no_argument, NULL, 'e'},
{"master-host-username", required_argument, NULL, 'u'},
{"master-hostname", required_argument, NULL, 'h'},
{"master-data-directory", required_argument, NULL, 'd'},
{"old-master-gp-dbid", required_argument, NULL, 'o'},
{"new-master-gp-dbid", required_argument, NULL, 'n'},
{"new-segment-path", required_argument, NULL, 's'},
{"new-gp-dbid", required_argument, NULL, 'g'},
{"old-tablespace-mapping-file-path", required_argument, NULL, 't'},
};
typedef struct Options {
char *master_host_username;
char *master_hostname;
char *master_data_directory;
int old_master_gp_dbid;
int new_master_gp_dbid;
char *new_segment_path;
int new_gp_dbid;
char *old_tablespace_mapping_file_path;
} Options;
void
OldTablespaceFileParser_invalid_access_error_for_field(int invalid_row_index, int invalid_field_index)
{
printf("attempted to access invalid field: {row_index=%d, field_index=%d}",
invalid_row_index,
invalid_field_index);
exit(1);
}
void
OldTablespaceFileParser_invalid_access_error_for_row(int invalid_row_index)
{
printf("attempted to access invalid row: {row_index=%d}",
invalid_row_index);
exit(1);
}
int
main(int argc, char *argv[])
{
int option;
int optindex = 0;
char *string_option_not_set = "not set";
int int_option_not_set = -1;
Command command = Command_NotSet;
Options options;
options.master_host_username = string_option_not_set;
options.master_hostname = string_option_not_set;
options.master_data_directory = string_option_not_set;
options.old_master_gp_dbid = int_option_not_set;
options.new_master_gp_dbid = int_option_not_set;
options.new_segment_path = string_option_not_set;
options.old_tablespace_mapping_file_path = string_option_not_set;
options.new_gp_dbid = int_option_not_set;
while ((option = getopt_long(argc, argv, "p:e",
long_options, &optindex)) != -1)
{
switch (option)
{
case 'p':
command = Command_Prepare;
break;
case 'e':
command = Command_Enable;
break;
case 'u':
options.master_host_username = pg_strdup(optarg);
break;
case 'h':
options.master_hostname = pg_strdup(optarg);
break;
case 'd':
options.master_data_directory = pg_strdup(optarg);
break;
case 'o':
options.old_master_gp_dbid = atoi(optarg);
break;
case 'n':
options.new_master_gp_dbid = atoi(optarg);
break;
case 's':
options.new_segment_path = pg_strdup(optarg);
break;
case 'g':
options.new_gp_dbid = atoi(optarg);
break;
case 't':
options.old_tablespace_mapping_file_path = pg_strdup(optarg);
break;
default:
printf("unknown option given.");
print_usage();
exit(1);
}
};
if (
command == Command_NotSet ||
strcmp(options.master_host_username, string_option_not_set) == 0 ||
strcmp(options.master_hostname, string_option_not_set) == 0 ||
strcmp(options.master_data_directory, string_option_not_set) == 0 ||
options.old_master_gp_dbid == int_option_not_set ||
options.new_master_gp_dbid == int_option_not_set ||
strcmp(options.new_segment_path, string_option_not_set) == 0 ||
options.new_gp_dbid == int_option_not_set ||
strcmp(options.old_tablespace_mapping_file_path, string_option_not_set) == 0
)
{
print_usage();
exit(1);
}
PgUpgradeCopyOptions *copy_options = make_copy_options(
options.master_host_username,
options.master_hostname,
options.master_data_directory,
options.old_master_gp_dbid,
options.new_master_gp_dbid,
options.new_segment_path,
options.new_gp_dbid,
options.old_tablespace_mapping_file_path);
if (command == Command_Enable)
enable_segment_after_upgrade(copy_options);
else if (command == Command_Prepare)
prepare_segment_for_upgrade(copy_options);
exit(0);
}
\ No newline at end of file
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdbool.h>
/*
* External dependencies
*/
#include "cmockery.h"
/*
* Production dependencies
*/
#include "pg_upgrade.h"
#include "old_tablespace_file_parser.h"
#include "old_tablespace_file_contents.h"
/*
* Test dependencies
*/
#include "utilities/gpdb5-cluster.h"
#include "utilities/gpdb6-cluster.h"
#include "utilities/test-helpers.h"
#include "utilities/query-helpers.h"
ClusterInfo old_cluster;
ClusterInfo new_cluster;
OSInfo os_info;
UserOpts user_opts;
void
OldTablespaceFileParser_invalid_access_error_for_field(int row_index, int field_index)
{
}
void
OldTablespaceFileParser_invalid_access_error_for_row(int row_index)
{
}
static void
test_populates_old_tablespace_file_contents_to_have_zero_records_for_gpdb6_cluster(void **state)
{
ClusterInfo cluster;
cluster.port = GPDB_SIX_PORT;
cluster.major_version = 90400; /* a GPDB 6 cluster */
os_info.user = getenv("USER");
cluster.old_tablespace_file_contents = NULL;
generate_old_tablespaces_file(&cluster);
assert_false(cluster.old_tablespace_file_contents == NULL);
assert_int_equal(
OldTablespaceFileContents_TotalNumberOfTablespaces(cluster.old_tablespace_file_contents),
0);
}
static void
test_filespaces_on_a_gpdb_five_cluster_are_loaded_as_old_tablespace_file_contents(void **state)
{
system("rm -rf /tmp/tablespace-gp-test");
system("mkdir /tmp/tablespace-gp-test");
PGconn *connection = connectToFive();
PGresult *result5 = executeQuery(connection, "CREATE FILESPACE my_fast_locations ( \n"
"1: '/tmp/tablespace-gp-test/fsseg-1/', \n"
"2: '/tmp/tablespace-gp-test/fsseg0/', \n"
"3: '/tmp/tablespace-gp-test/fsseg1/', \n"
"4: '/tmp/tablespace-gp-test/fsseg2/', \n"
"5: '/tmp/tablespace-gp-test/fsdummy1/', \n"
"6: '/tmp/tablespace-gp-test/fsdummy2/', \n"
"7: '/tmp/tablespace-gp-test/fsdummy3/', \n"
"8: '/tmp/tablespace-gp-test/fsdummy4/' );");
PQclear(result5);
result5 = executeQuery(connection, "CREATE TABLESPACE my_fast_tablespace FILESPACE my_fast_locations;");
PQfinish(connection);
ClusterInfo cluster;
cluster.port = GPDB_FIVE_PORT;
cluster.major_version = 10000; /* less than gpdb 6 */
cluster.gp_dbid = 2;
os_info.user = getenv("USER");
cluster.old_tablespace_file_contents = NULL;
generate_old_tablespaces_file(&cluster);
assert_false(cluster.old_tablespace_file_contents == NULL);
assert_int_equal(
OldTablespaceFileContents_TotalNumberOfTablespaces(cluster.old_tablespace_file_contents),
1);
char **results = OldTablespaceFileContents_GetArrayOfTablespacePaths(
cluster.old_tablespace_file_contents);
assert_string_equal(
results[0],
"/tmp/tablespace-gp-test/fsseg0");
}
static void
setup_gpdb6(void **state)
{
resetGpdbSixDataDirectories();
startGpdbSixCluster();
}
static void
teardown_gpdb6(void **state)
{
stopGpdbSixCluster();
resetGpdbSixDataDirectories();
}
static void
setup_gpdb5(void **state)
{
resetGpdbFiveDataDirectories();
startGpdbFiveCluster();
}
static void
teardown_gpdb5(void **state)
{
stopGpdbFiveCluster();
resetGpdbFiveDataDirectories();
}
int
main(int argc, char *argv[])
{
cmockery_parse_arguments(argc, argv);
const UnitTest tests[] = {
unit_test_setup_teardown(test_populates_old_tablespace_file_contents_to_have_zero_records_for_gpdb6_cluster, setup_gpdb6, teardown_gpdb6),
unit_test_setup_teardown(test_filespaces_on_a_gpdb_five_cluster_are_loaded_as_old_tablespace_file_contents, setup_gpdb5, teardown_gpdb5),
};
return run_tests(tests);
}
#include "postgres_fe.h"
/*
* implements:
*/
#include "cluster-upgrade.h"
struct PgUpgradeOptionsData
{
int old_gp_dbid;
int new_gp_dbid;
char *old_segment_path;
char *new_segment_path;
char *old_bin_dir;
char *new_bin_dir;
char *mode; /* dispatcher or segment */
char *old_tablespace_mapping_file_path;
bool has_tablespaces;
};
PgUpgradeOptions *
make_pg_upgrade_options(
char *old_segment_path,
char *new_segment_path,
int old_gp_dbid,
int new_gp_dbid,
bool is_dispatcher,
char *old_tablespace_mapping_file_path,
char *old_bin_dir,
char *new_bin_dir)
{
char *mode = "segment";
if (is_dispatcher)
mode = "dispatcher";
PgUpgradeOptions *options = palloc0(sizeof(PgUpgradeOptions));
options->old_gp_dbid = old_gp_dbid;
options->new_gp_dbid = new_gp_dbid;
options->old_segment_path = old_segment_path;
options->new_segment_path = new_segment_path;
options->old_bin_dir = old_bin_dir;
options->new_bin_dir = new_bin_dir;
options->mode = mode;
options->old_tablespace_mapping_file_path = old_tablespace_mapping_file_path;
options->has_tablespaces = old_tablespace_mapping_file_path != NULL;
return options;
}
static char *
base_upgrade_executable_string(PgUpgradeOptions *options)
{
char *tablespace_mapping_option = "";
if (options->old_tablespace_mapping_file_path)
tablespace_mapping_option = psprintf("--old-tablespaces-file=%s", options->old_tablespace_mapping_file_path);
return psprintf(
"%s/pg_upgrade "
"--link "
"--old-bindir=%s "
"--new-bindir=%s "
"--old-datadir=%s "
"--new-datadir=%s "
"--old-gp-dbid=%d "
"--new-gp-dbid=%d "
"--mode=%s "
"%s ",
options->new_bin_dir,
options->old_bin_dir,
options->new_bin_dir,
options->old_segment_path,
options->new_segment_path,
options->old_gp_dbid,
options->new_gp_dbid,
options->mode,
tablespace_mapping_option);
}
void
perform_upgrade(PgUpgradeOptions *options)
{
system(base_upgrade_executable_string(options));
}
FILE *
perform_upgrade_check(PgUpgradeOptions *options)
{
char *command = psprintf(
"%s "
"--check ",
base_upgrade_executable_string(options));
#ifndef WIN32
return popen(command, "r");
#endif
return NULL; /* else if */
}
typedef struct PgUpgradeOptionsData PgUpgradeOptions;
PgUpgradeOptions *make_pg_upgrade_options(
char *old_segment_path,
char *new_segment_path,
int old_gp_dbid,
int new_gp_dbid,
bool is_dispatcher,
char *old_tablespace_mapping_file_path,
char *old_bin_dir,
char *new_bin_dir);
void perform_upgrade(PgUpgradeOptions *options);
/*
* Returns file handler to standard out of pg_upgrade --check
*/
FILE *perform_upgrade_check(PgUpgradeOptions *options);
\ No newline at end of file
#define GPDB_FIVE_PORT 50000
void startGpdbFiveCluster(void);
void stopGpdbFiveCluster(void);
#define GPDB_SIX_PORT 60000
void startGpdbSixCluster(void);
void stopGpdbSixCluster(void);
#include "postgres_fe.h"
#include "old_tablespace_file_contents.h"
/*
* Implements
*/
#include "pg-upgrade-copy.h"
struct PgUpgradeCopyOptionsData {
char *master_host_username;
char *master_hostname;
char *master_data_directory_path;
char *new_segment_path;
int old_master_gp_dbid;
int new_master_gp_dbid;
int new_gp_dbid;
char *old_tablespace_mapping_file_path;
bool has_tablespaces;
};
static int number_of_config_files_to_preserve = 5;
static char *config_files_to_preserve[] = {
"internal.auto.conf",
"postgresql.conf",
"pg_hba.conf",
"postmaster.opts",
"postgresql.auto.conf"
};
static void
copy_configuration_file_to_directory(char *base_directory, char *file_name, char *destination_directory){
system(psprintf("cp %s/%s %s/", base_directory, file_name, destination_directory));
}
static void
restore_configuration_files(PgUpgradeCopyOptions *copy_options)
{
char *backup_configuration_directory = psprintf("%s/backup-configuration", copy_options->new_segment_path);
for (int i = 0; i < number_of_config_files_to_preserve; i++)
{
char *filename = config_files_to_preserve[i];
copy_configuration_file_to_directory(backup_configuration_directory, filename, copy_options->new_segment_path);
}
}
static void
copy_tablespace_from(
char *master_tablespace_location_directory,
char *segment_tablespace_location_directory,
PgUpgradeCopyOptions *copy_options)
{
system(psprintf(
"rsync -a --delete "
"%s@%s:%s/%d/ "
"%s/%d ",
copy_options->master_host_username,
copy_options->master_hostname,
master_tablespace_location_directory,
copy_options->new_master_gp_dbid,
segment_tablespace_location_directory,
copy_options->new_gp_dbid));
}
static void
copy_master_data_directory_into_segment_data_directory(PgUpgradeCopyOptions *options)
{
system(psprintf(
"rsync -a --delete --exclude='backup-configuration' "
"%s@%s:%s/ "
"%s ",
options->master_host_username,
options->master_hostname,
options->master_data_directory_path,
options->new_segment_path));
}
static void
backup_configuration_files(PgUpgradeCopyOptions *options)
{
char *backup_directory = psprintf("%s/backup-configuration", options->new_segment_path);
system(psprintf("mkdir -p %s", backup_directory));
for (int i = 0; i < number_of_config_files_to_preserve; i++)
{
char *filename = config_files_to_preserve[i];
copy_configuration_file_to_directory(
options->new_segment_path,
filename,
backup_directory);
}
}
static void
update_symlinks_for_tablespaces_from(char *segment_path, char *new_tablespace_path)
{
system(psprintf("find %s/pg_tblspc/* | xargs -I '{}' ln -sfn %s '{}'",
segment_path,
new_tablespace_path));
}
static void
copy_tablespaces_from_the_master(PgUpgradeCopyOptions *copy_options)
{
if (!copy_options->has_tablespaces) return;
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents(
copy_options->old_tablespace_mapping_file_path);
OldTablespaceFileContents *contents_for_segment = filter_old_tablespace_file_for_dbid(
contents, copy_options->new_gp_dbid);
OldTablespaceRecord **segment_records = OldTablespaceFileContents_GetTablespaceRecords(contents_for_segment);
for (int i = 0; i < OldTablespaceFileContents_TotalNumberOfTablespaces(contents_for_segment); i++)
{
OldTablespaceRecord *current_segment_record = segment_records[i];
OldTablespaceRecord *master_segment_record = OldTablespaceFileContents_GetTablespaceRecord(
contents,
copy_options->old_master_gp_dbid,
OldTablespaceRecord_GetTablespaceName(current_segment_record)
);
char *master_tablespace_location_directory = OldTablespaceRecord_GetDirectoryPath(master_segment_record);
char *segment_tablespace_location_directory = OldTablespaceRecord_GetDirectoryPath(current_segment_record);
copy_tablespace_from(
master_tablespace_location_directory,
segment_tablespace_location_directory,
copy_options);
char *segment_tablespace_location_directory_with_gp_dbid = psprintf("%s/%d",
segment_tablespace_location_directory,
copy_options->new_gp_dbid);
update_symlinks_for_tablespaces_from(
copy_options->new_segment_path,
segment_tablespace_location_directory_with_gp_dbid);
}
}
PgUpgradeCopyOptions *
make_copy_options(
char *master_host_username,
char *master_hostname,
char *master_data_directory,
int old_master_gp_dbid,
int new_master_gp_dbid,
char *new_segment_path,
int new_gp_dbid,
char *old_tablespace_mapping_file_path)
{
PgUpgradeCopyOptions *copy_options = palloc0(sizeof(PgUpgradeCopyOptions));
copy_options->master_host_username = master_host_username;
copy_options->master_hostname = master_hostname;
copy_options->master_data_directory_path = master_data_directory;
copy_options->new_segment_path = new_segment_path;
copy_options->old_master_gp_dbid = old_master_gp_dbid;
copy_options->new_master_gp_dbid = new_master_gp_dbid;
copy_options->new_gp_dbid = new_gp_dbid;
copy_options->old_tablespace_mapping_file_path = old_tablespace_mapping_file_path;
copy_options->has_tablespaces = old_tablespace_mapping_file_path != NULL;
return copy_options;
}
void
prepare_segment_for_upgrade(PgUpgradeCopyOptions *copy_options)
{
backup_configuration_files(copy_options);
copy_master_data_directory_into_segment_data_directory(copy_options);
copy_tablespaces_from_the_master(copy_options);
}
void
enable_segment_after_upgrade(PgUpgradeCopyOptions *copy_options)
{
restore_configuration_files(copy_options);
}
#ifndef PG_UPGRADE_COPY_H
#define PG_UPGRADE_COPY_H
typedef struct PgUpgradeCopyOptionsData PgUpgradeCopyOptions;
PgUpgradeCopyOptions *make_copy_options(
char *master_host_username,
char *master_hostname,
char *master_data_directory,
int old_master_gp_dbid,
int new_master_gp_dbid,
char *new_segment_path,
int new_gp_dbid,
char *old_tablespace_mapping_file_path);
void prepare_segment_for_upgrade(PgUpgradeCopyOptions *copy_options);
void enable_segment_after_upgrade(PgUpgradeCopyOptions *copy_options);
#endif /* PG_UPGRADE_COPY_H */
#include <stdlib.h>
#include <stdio.h>
#include "test-helpers.h"
#include "gpdb5-cluster.h"
#include "gpdb6-cluster.h"
#include "query-helpers.h"
#include "upgrade-helpers.h"
#include "pqexpbuffer.h"
#include "test-helpers.h"
void
resetGpdbFiveDataDirectories(void)
......@@ -23,11 +24,11 @@ resetGpdbSixDataDirectories(void)
PGconn *
connectToFive()
{
return connectTo(50000);
return connectTo(GPDB_FIVE_PORT);
}
PGconn *
connectToSix()
{
return connectTo(60000);
return connectTo(GPDB_SIX_PORT);
}
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmockery.h"
#include "postgres_fe.h"
/*
* implements:
*/
#include "test-upgrade-helpers.h"
#include "cluster-upgrade.h"
#include "pg-upgrade-copy.h"
#include "pqexpbuffer.h"
PQExpBufferData pg_upgrade_output;
int pg_upgrade_exit_status;
typedef struct SegmentConfiguration
{
char *old_data_directory;
char *new_data_directory;
char *segment_path;
int new_dbid;
int old_dbid;
} SegmentConfiguration;
void
performUpgrade(void)
{
performUpgradeWithTablespaces(NULL);
}
void
performUpgradeWithTablespaces(char *mappingFilePath)
{
char current_directory[1000];
char master_hostname[1000];
char *master_host_username = getenv("USER");
gethostname(master_hostname, sizeof(master_hostname));
getcwd(current_directory, sizeof(current_directory));
char *new_master_data_directory = psprintf("%s/gpdb6-data/qddir/demoDataDir-1", current_directory);
char *old_master_data_directory = psprintf("%s/gpdb5-data/qddir/demoDataDir-1", current_directory);
char *old_bin_dir = psprintf("%s/gpdb5/bin", current_directory);
char *new_bin_dir = psprintf("%s/gpdb6/bin", current_directory);
int old_master_gp_dbid = 1;
int new_master_gp_dbid = 1;
SegmentConfiguration master_segment = {
.old_dbid=1,
.new_dbid=1,
.old_data_directory=old_master_data_directory,
.new_data_directory=psprintf("%s/gpdb6-data/qddir/demoDataDir-1", current_directory)
};
int number_of_segments = 3;
SegmentConfiguration segment_configurations[] = {
{
.old_data_directory=psprintf("%s/gpdb5-data/dbfast1/demoDataDir0", current_directory),
.new_data_directory=psprintf("%s/gpdb6-data/dbfast1/demoDataDir0", current_directory),
.old_dbid=2,
.new_dbid=2
},
{
.old_data_directory=psprintf("%s/gpdb5-data/dbfast2/demoDataDir1", current_directory),
.new_data_directory=psprintf("%s/gpdb6-data/dbfast2/demoDataDir1", current_directory),
.old_dbid=3,
.new_dbid=3,
},
{
.old_data_directory=psprintf("%s/gpdb5-data/dbfast3/demoDataDir2", current_directory),
.new_data_directory=psprintf("%s/gpdb6-data/dbfast3/demoDataDir2", current_directory),
.old_dbid=4,
.new_dbid=4,
}
};
perform_upgrade(
make_pg_upgrade_options(
old_master_data_directory,
master_segment.new_data_directory,
master_segment.old_dbid,
master_segment.new_dbid,
true,
NULL,
old_bin_dir,
new_bin_dir));
for (int i = 0; i < number_of_segments; i++)
{
SegmentConfiguration segment = segment_configurations[i];
PgUpgradeOptions *segment_upgrade_options = make_pg_upgrade_options(
segment.old_data_directory,
segment.new_data_directory,
segment.old_dbid,
segment.new_dbid,
false,
mappingFilePath,
old_bin_dir,
new_bin_dir);
PgUpgradeCopyOptions *segment_copy_options = make_copy_options(
master_host_username,
master_hostname,
new_master_data_directory,
old_master_gp_dbid,
new_master_gp_dbid,
segment.new_data_directory,
segment.new_dbid,
mappingFilePath);
prepare_segment_for_upgrade(segment_copy_options);
perform_upgrade(segment_upgrade_options);
enable_segment_after_upgrade(segment_copy_options);
}
}
char *
upgradeCheckOutput(void)
{
return pg_upgrade_output.data;
}
int
upgradeCheckStatus(void)
{
return pg_upgrade_exit_status;
}
void
initializePgUpgradeStatus(void)
{
initPQExpBuffer(&pg_upgrade_output);
pg_upgrade_exit_status = 0;
}
void
resetPgUpgradeStatus(void)
{
termPQExpBuffer(&pg_upgrade_output);
}
void
performUpgradeCheck(void)
{
char buffer[2000];
char *old_master_data_directory_path = "./gpdb5-data/qddir/demoDataDir-1";
char *new_master_data_directory_path = "./gpdb6-data/qddir/demoDataDir-1";
int old_master_gp_dbid = 1;
int new_master_gp_dbid = 1;
FILE *output_file;
char *output;
int cmdstatus = 0;
PgUpgradeOptions *options = make_pg_upgrade_options(
old_master_data_directory_path,
new_master_data_directory_path,
old_master_gp_dbid,
new_master_gp_dbid,
true,
NULL,
"./gpdb5/bin",
"./gpdb6/bin"
);
output_file = perform_upgrade_check(options);
#ifndef WIN32
while ((output = fgets(buffer, sizeof(buffer), output_file)) != NULL)
appendPQExpBufferStr(&pg_upgrade_output, output);
cmdstatus = pclose(output_file);
pg_upgrade_exit_status = WEXITSTATUS(cmdstatus);
#endif
}
......@@ -3,9 +3,9 @@
#define PG_UPGRADE_INTEGRATION_TEST_UPGRADE_HELPERS
#include "postgres_fe.h"
#include "pqexpbuffer.h"
void performUpgrade(void);
void performUpgradeWithTablespaces(char *mappingFilePath);
void performUpgradeCheck(void);
void initializePgUpgradeStatus(void);
void resetPgUpgradeStatus(void);
......
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cmockery.h"
/*
* implements:
*/
#include "upgrade-helpers.h"
PQExpBufferData pg_upgrade_output;
int pg_upgrade_exit_status;
static void
copy_file_from_backup_to_datadir(char *filename, char *segment_path)
{
char buffer[2000];
sprintf(buffer,
"cp gpdb6-data-copy/%s/%s gpdb6-data/%s/%s",
segment_path, filename, segment_path, filename);
system(buffer);
}
static void
copy_configuration_files_from_backup_to_datadirs(char *segment_path)
{
char *files_to_copy[] = {
"internal.auto.conf",
"postgresql.conf",
"pg_hba.conf",
"postmaster.opts",
"postgresql.auto.conf"
};
for (int i = 0; i < 5; i++)
{
char *filename = files_to_copy[i];
copy_file_from_backup_to_datadir(filename, segment_path);
}
}
static void
execute_pg_upgrade_for_qd(char *segment_path)
{
char buffer[2000];
sprintf(buffer, ""
"./gpdb6/bin/pg_upgrade "
"--mode=dispatcher "
"--link "
"--old-bindir=./gpdb5/bin "
"--new-bindir=./gpdb6/bin "
"--old-datadir=./gpdb5-data/%s "
"--new-datadir=./gpdb6-data/%s "
,segment_path, segment_path);
system(buffer);
}
static void
execute_pg_upgrade_for_primary(char *segment_path)
{
char buffer[2000];
sprintf(buffer, ""
"./gpdb6/bin/pg_upgrade "
"--mode=segment "
"--link "
"--old-bindir=./gpdb5/bin "
"--new-bindir=./gpdb6/bin "
"--old-datadir=./gpdb5-data/%s "
"--new-datadir=./gpdb6-data/%s "
,segment_path, segment_path);
system(buffer);
}
static void
copy_master_data_directory_into_segment_data_directory(char *segment_path)
{
char buffer[2000];
char *master_data_directory_path = "qddir/demoDataDir-1";
sprintf(buffer,
"rsync -a --delete "
"./gpdb6-data/%s/ "
"./gpdb6-data/%s ",
master_data_directory_path,
segment_path);
system(buffer);
}
static void
upgradeSegment(char *segment_path)
{
copy_master_data_directory_into_segment_data_directory(segment_path);
execute_pg_upgrade_for_primary(segment_path);
copy_configuration_files_from_backup_to_datadirs(
segment_path);
}
static void
upgradeMaster(void)
{
char *master_data_directory_path = "qddir/demoDataDir-1";
execute_pg_upgrade_for_qd(master_data_directory_path);
copy_configuration_files_from_backup_to_datadirs(
master_data_directory_path);
}
static void
upgradeContentId0(void)
{
char *segment_path = "dbfast1/demoDataDir0";
upgradeSegment(segment_path);
}
static void
upgradeContentId1(void)
{
char *segment_path = "dbfast2/demoDataDir1";
upgradeSegment(segment_path);
}
static void
upgradeContentId2(void)
{
char *segment_path = "dbfast3/demoDataDir2";
upgradeSegment(segment_path);
}
void
performUpgrade(void)
{
upgradeMaster();
upgradeContentId0();
upgradeContentId1();
upgradeContentId2();
}
void
performUpgradeCheck(void)
{
char buffer[2000];
char *master_data_directory_path = "qddir/demoDataDir-1";
FILE *output_file;
char *output;
int cmdstatus = 0;
sprintf(buffer, ""
"./gpdb6/bin/pg_upgrade "
"--check "
"--old-bindir=./gpdb5/bin "
"--new-bindir=./gpdb6/bin "
"--old-datadir=./gpdb5-data/%s "
"--new-datadir=./gpdb6-data/%s ",
master_data_directory_path, master_data_directory_path);
#ifndef WIN32
output_file = popen(buffer, "r");
while ((output = fgets(buffer, sizeof(buffer), output_file)) != NULL)
appendPQExpBufferStr(&pg_upgrade_output, output);
cmdstatus = pclose(output_file);
pg_upgrade_exit_status = WEXITSTATUS(cmdstatus);
#endif
}
char *
upgradeCheckOutput(void)
{
return pg_upgrade_output.data;
}
int
upgradeCheckStatus(void)
{
return pg_upgrade_exit_status;
}
void
initializePgUpgradeStatus(void)
{
initPQExpBuffer(&pg_upgrade_output);
pg_upgrade_exit_status = 0;
}
void
resetPgUpgradeStatus(void)
{
termPQExpBuffer(&pg_upgrade_output);
}
/*.t
\ No newline at end of file
subdir=contrib/pg_upgrade/test/unit
top_srcdir=../../../..
top_builddir=../../../..
pg_upgrade_directory=../..
OBJS = tablespace_test.o old_tablespace_file_contents_test.o old_tablespace_file_parser_test.o
TARGETS = tablespace_test \
old_tablespace_file_contents_test \
old_tablespace_file_parser_test \
tablespace_gp_test
include $(top_srcdir)/src/Makefile.global
include $(top_srcdir)/src/Makefile.mock
override CPPFLAGS += -I$(pg_upgrade_directory) \
-I$(libpq_srcdir)
test_dependencies = $(CMOCKERY_OBJS)
debugging_flags = -Og -g -fsanitize=address -Wextra -pedantic-errors -Werror
compile_test = $(CC) $(CFLAGS) $(debugging_flags) $^ $(libpq_pgport) $(LDFLAGS) -o $@
tablespace_test.t: tablespace_test.o $(pg_upgrade_directory)/tablespace.o $(test_dependencies)
$(compile_test)
old_tablespace_file_contents_test.t: old_tablespace_file_contents_test.o $(pg_upgrade_directory)/old_tablespace_file_contents.o $(test_dependencies)
$(compile_test)
old_tablespace_file_parser_test.t: old_tablespace_file_parser_test.o $(pg_upgrade_directory)/old_tablespace_file_parser.o $(test_dependencies)
$(compile_test)
tablespace_gp_test.t: tablespace_gp_test.o $(pg_upgrade_directory)/tablespace_gp.o $(test_dependencies)
$(compile_test)
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cmockery.h"
#include "old_tablespace_file_contents.h"
#include "old_tablespace_file_parser.h"
struct OldTablespaceFileParser_DocumentData {};
int _faked_number_of_rows = -1;
char *fields[10][10];
char *
OldTablespaceFileParser_get_field_as_string(OldTablespaceFileParser_Document *document, int row_index, int field_index)
{
return fields[row_index][field_index];
}
int
OldTablespaceFileParser_get_field_as_int(OldTablespaceFileParser_Document *document, int row_index, int field_index)
{
return atoi(fields[row_index][field_index]);
}
Oid
OldTablespaceFileParser_get_field_as_oid(OldTablespaceFileParser_Document *document, int row_index, int field_index)
{
return (Oid) strtoul(fields[row_index][field_index], NULL, 10);
}
int
OldTablespaceFileParser_number_of_rows(OldTablespaceFileParser_Document *document)
{
return _faked_number_of_rows;
}
void
OldTablespaceFileParser_clear_document(OldTablespaceFileParser_Document *document)
{
for (int row_index = 0; row_index < 10; row_index++)
for (int column_index = 0; column_index < 10; column_index++)
pfree(fields[row_index][column_index]);
}
static void stub_number_of_rows(int new_number_of_rows)
{
_faked_number_of_rows = new_number_of_rows;
}
static void stub_field(int row_index, int field_index, char *value)
{
fields[row_index][field_index] = strdup(value);
}
OldTablespaceFileParser_Document *
OldTablespaceFileParser_parse_file(FILE *file)
{
OldTablespaceFileParser_Document *document = malloc(sizeof(OldTablespaceFileParser_Document));
return document;
}
static void setup(void **state)
{
_faked_number_of_rows = -1;
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
fields[i][j] = NULL;
}
static void teardown(void **state)
{
}
static void
test_it_finds_old_tablespaces_when_provided_as_a_file(void **state)
{
stub_number_of_rows(2);
stub_field(0, 0, "123");
stub_field(0, 1, "456");
stub_field(0, 2, "some_space_name");
stub_field(0, 3, "/some/directory/for/999");
stub_field(1, 0, "888");
stub_field(1, 1, "777");
stub_field(1, 2, "some_other_space_name");
stub_field(1, 3, "/some/other/directory/for/999");
char *path = "/tmp/some/path";
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents(path);
assert_int_equal(
OldTablespaceFileContents_TotalNumberOfTablespaces(contents),
2);
char **tablespaces = OldTablespaceFileContents_GetArrayOfTablespacePaths(contents);
assert_string_equal(tablespaces[0], "/some/directory/for/999");
assert_string_equal(tablespaces[1], "/some/other/directory/for/999");
}
static void
test_it_returns_zero_tablespaces_when_content_is_empty(void **state)
{
stub_number_of_rows(0);
char *path = "/tmp/some/path";
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents(path);
assert_int_equal(
OldTablespaceFileContents_TotalNumberOfTablespaces(contents),
0);
}
static void
test_it_can_filter_old_contents_by_dbid(void **state)
{
stub_number_of_rows(2);
stub_field(0, 0, "1");
stub_field(0, 1, "123");
stub_field(0, 2, "some_space_name");
stub_field(0, 3, "/some/directory/for/123");
stub_field(1, 0, "2");
stub_field(1, 1, "456");
stub_field(1, 2, "some_other_space_name");
stub_field(1, 3, "/some/other/directory/for/456");
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents("some path");
OldTablespaceFileContents *filteredContents = filter_old_tablespace_file_for_dbid(contents, 2);
assert_int_equal(1,
OldTablespaceFileContents_TotalNumberOfTablespaces(filteredContents));
char **tablespace_paths = OldTablespaceFileContents_GetArrayOfTablespacePaths(filteredContents);
assert_string_equal("/some/other/directory/for/456",
tablespace_paths[0]);
}
static void
test_it_can_return_the_path_of_a_tablespace_for_a_given_oid(void **state)
{
stub_number_of_rows(3);
stub_field(0, 0, "1");
stub_field(0, 1, "123");
stub_field(0, 2, "some_space_name");
stub_field(0, 3, "some path");
stub_field(1, 0, "1");
stub_field(1, 1, "456");
stub_field(1, 2, "some_space_name");
stub_field(1, 3, "some other path");
stub_field(2, 0, "2");
stub_field(2, 1, "123");
stub_field(2, 2, "some_space_name");
stub_field(2, 3, "some random path");
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents("/some/path");
char *found_path = "";
Oid current_oid = 123;
found_path = old_tablespace_file_get_tablespace_path_for_oid(contents, current_oid);
assert_int_not_equal((void *)found_path, NULL);
assert_string_equal("some path", found_path);
current_oid = 456;
found_path = old_tablespace_file_get_tablespace_path_for_oid(contents, current_oid);
assert_int_not_equal((void *)found_path, NULL);
assert_string_equal("some other path", found_path);
}
static void
test_it_can_get_segment_records_from_contents(void **state)
{
stub_number_of_rows(1);
stub_field(0, 0, "1");
stub_field(0, 1, "123");
stub_field(0, 2, "some_space_name");
stub_field(0, 3, "some path");
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents("/some/path");
OldTablespaceRecord **records = OldTablespaceFileContents_GetTablespaceRecords(contents);
assert_string_equal(OldTablespaceRecord_GetTablespaceName(records[0]), "some_space_name");
assert_string_equal(OldTablespaceRecord_GetDirectoryPath(records[0]), "some path");
}
static void
test_it_can_return_a_specific_tablespace_record_by_tablespace_name_and_dbid(void **state)
{
stub_number_of_rows(3);
stub_field(0, 0, "1");
stub_field(0, 1, "123");
stub_field(0, 2, "some_space_name");
stub_field(0, 3, "some path for 123");
stub_field(1, 0, "2");
stub_field(1, 1, "456");
stub_field(1, 2, "some_space_name");
stub_field(1, 3, "some path for 456");
stub_field(2, 0, "2");
stub_field(2, 1, "789");
stub_field(2, 2, "some_other_space_name");
stub_field(2, 3, "some path for 789");
OldTablespaceFileContents *contents = parse_old_tablespace_file_contents("/some/path");
OldTablespaceRecord *record = OldTablespaceFileContents_GetTablespaceRecord(contents,
2, "some_other_space_name");
assert_string_equal(OldTablespaceRecord_GetDirectoryPath(record), "some path for 789");
OldTablespaceRecord *missingRecord = OldTablespaceFileContents_GetTablespaceRecord(contents,
1, "some_other_space_name");
assert_true(missingRecord == NULL);
}
int
main(int argc, char *argv[])
{
cmockery_parse_arguments(argc, argv);
const UnitTest tests[] = {
unit_test_setup_teardown(test_it_finds_old_tablespaces_when_provided_as_a_file, setup, teardown),
unit_test_setup_teardown(test_it_returns_zero_tablespaces_when_content_is_empty, setup, teardown),
unit_test_setup_teardown(test_it_can_filter_old_contents_by_dbid, setup, teardown),
unit_test_setup_teardown(test_it_can_return_the_path_of_a_tablespace_for_a_given_oid, setup, teardown),
unit_test_setup_teardown(test_it_can_get_segment_records_from_contents, setup, teardown),
unit_test_setup_teardown(test_it_can_return_a_specific_tablespace_record_by_tablespace_name_and_dbid, setup, teardown),
};
return run_tests(tests);
}
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdbool.h>
#include "cmockery.h"
#include "old_tablespace_file_parser.h"
static int _invalid_access_to_row_called_with_row_index;
static int _invalid_access_to_field_called_with_row_index;
static int _invalid_access_to_field_called_with_field_index;
void
OldTablespaceFileParser_invalid_access_error_for_row(int row_index)
{
_invalid_access_to_row_called_with_row_index = row_index;
}
void
OldTablespaceFileParser_invalid_access_error_for_field(int row_index, int field_index)
{
_invalid_access_to_field_called_with_row_index = row_index;
_invalid_access_to_field_called_with_field_index = field_index;
}
static void
test_it_returns_number_of_rows(void **state)
{
FILE *file = tmpfile();
fputs("1,joe\n", file);
rewind(file);
OldTablespaceFileParser_Document *document = (OldTablespaceFileParser_Document*) OldTablespaceFileParser_parse_file(
file);
fclose(file);
int number_of_rows = OldTablespaceFileParser_number_of_rows(document);
OldTablespaceFileParser_clear_document(document);
assert_int_equal(number_of_rows, 1);
}
static void test_it_returns_zero_number_of_rows_for_empty_document(void **state)
{
FILE *file = tmpfile();
OldTablespaceFileParser_Document *document = (OldTablespaceFileParser_Document*) OldTablespaceFileParser_parse_file(
file);
fclose(file);
int number_of_rows = OldTablespaceFileParser_number_of_rows(document);
OldTablespaceFileParser_clear_document(document);
assert_int_equal(number_of_rows, 0);
}
static void test_it_returns_two_rows_for_document_with_two_lines(void **state)
{
FILE *file = tmpfile();
fputs("1,123\n", file);
fputs("2,456\n", file);
rewind(file);
OldTablespaceFileParser_Document *document = (OldTablespaceFileParser_Document*) OldTablespaceFileParser_parse_file(
file);
int number_of_rows = OldTablespaceFileParser_number_of_rows(document);
OldTablespaceFileParser_clear_document(document);
assert_int_equal(number_of_rows, 2);
}
static void test_the_document_returns_row_data(void **state)
{
FILE *file = tmpfile();
fputs("1,123\n", file);
fputs("2,456\n", file);
rewind(file);
OldTablespaceFileParser_Document *document = (OldTablespaceFileParser_Document*) OldTablespaceFileParser_parse_file(
file);
assert_string_equal(OldTablespaceFileParser_get_field_as_string(document,
0,
0), "1");
assert_string_equal(OldTablespaceFileParser_get_field_as_string(document,
0,
1), "123");
assert_string_equal(OldTablespaceFileParser_get_field_as_string(document,
1,
0), "2");
assert_string_equal(OldTablespaceFileParser_get_field_as_string(document,
1,
1), "456");
OldTablespaceFileParser_clear_document(document);
}
static void
test_the_document_returns_row_data_as_integers(void **state)
{
FILE *file = tmpfile();
fputs("1,123\n", file);
fputs("2,456\n", file);
rewind(file);
OldTablespaceFileParser_Document *document = (OldTablespaceFileParser_Document*) OldTablespaceFileParser_parse_file(
file);
assert_int_equal(OldTablespaceFileParser_get_field_as_int(document, 0, 0), 1);
assert_int_equal(OldTablespaceFileParser_get_field_as_int(document, 0, 1), 123);
assert_int_equal(OldTablespaceFileParser_get_field_as_int(document, 1, 0), 2);
assert_int_equal(OldTablespaceFileParser_get_field_as_int(document, 1, 1), 456);
OldTablespaceFileParser_clear_document(document);
}
static void
test_invalid_access_to_a_row_is_reported(void **state)
{
FILE *file = tmpfile();
fputs("1,123\n", file);
rewind(file);
OldTablespaceFileParser_Document *document = (OldTablespaceFileParser_Document*) OldTablespaceFileParser_parse_file(
file);
OldTablespaceFileParser_get_field_as_int(document, 1, 0);
assert_int_equal(_invalid_access_to_row_called_with_row_index, 1);
OldTablespaceFileParser_get_field_as_oid(document, 2, 0);
assert_int_equal(_invalid_access_to_row_called_with_row_index, 2);
}
static void
test_invalid_access_to_a_field_is_reported(void **state)
{
FILE *file = tmpfile();
fputs("1,123\n", file);
rewind(file);
OldTablespaceFileParser_Document *document = (OldTablespaceFileParser_Document*) OldTablespaceFileParser_parse_file(
file);
OldTablespaceFileParser_get_field_as_int(document, 0, 2);
assert_int_equal(_invalid_access_to_field_called_with_row_index, 0);
assert_int_equal(_invalid_access_to_field_called_with_field_index, 2);
OldTablespaceFileParser_get_field_as_oid(document, 0, 3);
assert_int_equal(_invalid_access_to_field_called_with_row_index, 0);
assert_int_equal(_invalid_access_to_field_called_with_field_index, 3);
}
static void
setup(void **state)
{
_invalid_access_to_row_called_with_row_index = -1;
_invalid_access_to_field_called_with_row_index = -1;
_invalid_access_to_field_called_with_field_index = -1;
}
static void
teardown(void **state)
{
}
int
main(int argc, char *argv[])
{
cmockery_parse_arguments(argc, argv);
const UnitTest tests[] = {
unit_test_setup_teardown(test_it_returns_number_of_rows, setup, teardown),
unit_test_setup_teardown(test_it_returns_zero_number_of_rows_for_empty_document, setup, teardown),
unit_test_setup_teardown(test_it_returns_two_rows_for_document_with_two_lines, setup, teardown),
unit_test_setup_teardown(test_the_document_returns_row_data, setup, teardown),
unit_test_setup_teardown(test_the_document_returns_row_data_as_integers, setup, teardown),
unit_test_setup_teardown(test_invalid_access_to_a_row_is_reported, setup, teardown),
unit_test_setup_teardown(test_invalid_access_to_a_field_is_reported, setup, teardown),
};
return run_tests(tests);
}
/*
* Dummy functions:
*
* used to provide completely invalid results, not necessary for tests
* to run successfully
*/
void
pg_fatal(const char *fmt, ...)
{
exit(0);
}
void
report_status(eLogType type, const char *fmt, ...)
{
}
PGconn *
connectToServer(ClusterInfo *cluster, const char *db_name)
{
return NULL;
}
PGresult *
executeQueryOrDie(PGconn *conn, const char *fmt, ...)
{
return NULL;
}
const char *
getErrorText(void)
{
return NULL;
}
void check_ok() {}
void prep_status(const char *fmt,...) {}
\ No newline at end of file
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdbool.h>
#include "cmockery.h"
#include "pg_upgrade.h"
#include "pg_upgrade_dummies.c"
/*
* Test dummies
*/
void clear_old_tablespace_file_contents(OldTablespaceFileContents *contents)
{
}
OldTablespaceFileContents *
filter_old_tablespace_file_for_dbid(OldTablespaceFileContents *contents, int gp_dbid)
{
return NULL;
}
OldTablespaceFileContents *
parse_old_tablespace_file_contents(const char *path)
{
return NULL;
}
/*
* Tests
*/
static void
test_it_populates_using_gpdb6_tablespace_layout(
void **state)
{
ClusterInfo clusterInfo;
strcpy(clusterInfo.major_version_str, "-SOME_MAJOR_VERSION_STRING-");
clusterInfo.controldata.cat_ver = 12345;
clusterInfo.gp_dbid = 999;
populate_gpdb6_cluster_tablespace_suffix(&clusterInfo);
assert_string_equal(clusterInfo.tablespace_suffix, "/999/GPDB_6_12345");
}
int
main(int argc, char *argv[])
{
cmockery_parse_arguments(argc, argv);
const UnitTest tests[] = {
unit_test(test_it_populates_using_gpdb6_tablespace_layout),
};
return run_tests(tests);
}
\ No newline at end of file
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdbool.h>
#include "cmockery.h"
#include "pg_upgrade.h"
#include "pg_upgrade_dummies.c"
/*
* Test state
*/
ClusterInfo new_cluster;
ClusterInfo old_cluster;
ClusterInfo *test_cluster;
OSInfo os_info;
OSInfo *test_os_info;
bool _is_old_tablespaces_file_empty;
bool _populate_gpdb6_cluster_tablespace_suffix_was_called;
char **_stubbed_tablespace_paths = NULL;
int _stubbed_number_of_tablespaces = 0;
char **
OldTablespaceFileContents_GetArrayOfTablespacePaths(OldTablespaceFileContents *contents){
return _stubbed_tablespace_paths;
}
static void stub_number_of_tablespaces(int stub_value)
{
_stubbed_number_of_tablespaces = stub_value;
}
static void stub_tablespace_paths(char **paths)
{
_stubbed_tablespace_paths = paths;
}
int
OldTablespaceFileContents_TotalNumberOfTablespaces(OldTablespaceFileContents *contents)
{
return _stubbed_number_of_tablespaces;
}
/*
* Stub functions:
*/
/*
* implements is_old_tablespaces_file_empty to return stubbed value
*/
bool
is_old_tablespaces_file_empty(OldTablespaceFileContents *contents)
{
return _is_old_tablespaces_file_empty;
}
void
populate_gpdb6_cluster_tablespace_suffix(ClusterInfo *cluster)
{
_populate_gpdb6_cluster_tablespace_suffix_was_called = true;
cluster->tablespace_suffix = "some-tablespace-suffix";
}
/*
* allows test to stub value for is_old_tablespaces_file_empty
*/
static void
stub_is_old_tablespaces_file_empty(bool value)
{
_is_old_tablespaces_file_empty = value;
}
/*
* Test hooks
*/
static void
setup(void **state)
{
test_cluster = malloc(sizeof(ClusterInfo));
test_os_info = malloc(sizeof(OSInfo));
old_cluster = *test_cluster;
os_info = *test_os_info;
old_cluster.old_tablespace_file_contents = NULL;
stub_is_old_tablespaces_file_empty(true);
_populate_gpdb6_cluster_tablespace_suffix_was_called = false;
}
static void
teardown(void **state)
{
free(test_cluster);
free(test_os_info);
}
/*
* Tests
*/
static void
test_when_postgres_version_8_4_tablespace_directory_suffix_remains_empty(void **state)
{
old_cluster.major_version = 80400;
init_tablespaces();
assert_string_equal(old_cluster.tablespace_suffix, "");
}
static void
test_when_postgres_version_is_before_8_4_tablespace_directory_suffix_remains_empty(
void **state)
{
old_cluster.major_version = 80300;
init_tablespaces();
assert_string_equal(old_cluster.tablespace_suffix, "");
}
static void
test_when_postgres_version_newer_than_8_4_tablespace_directory_suffix_contains_PG_version_and_catalog_version(
void **state)
{
old_cluster.major_version = 80500;
strcpy(old_cluster.major_version_str, "-SOME_MAJOR_VERSION_STRING-");
old_cluster.controldata.cat_ver = 12345;
init_tablespaces();
assert_string_equal(old_cluster.tablespace_suffix,
"/PG_-SOME_MAJOR_VERSION_STRING-_12345");
}
static void
test_when_postgres_version_matches_gpdb6_postgres_version_tablespace_directory_suffix_contains_GPDB6_tablespace_layout(
void **state)
{
old_cluster.major_version = 90400;
init_tablespaces();
assert_true(_populate_gpdb6_cluster_tablespace_suffix_was_called);
}
static void
test_it_finds_old_tablespaces_when_provided_as_a_file(void **state)
{
old_cluster.gp_dbid = 999;
old_cluster.major_version = 80400;
new_cluster.major_version = 90400;
stub_is_old_tablespaces_file_empty(false);
stub_number_of_tablespaces(2);
char *tablespace_paths[] = {
"/some/directory/for/999",
"/some/other/directory/for/999"
};
stub_tablespace_paths(tablespace_paths);
init_tablespaces();
assert_int_equal(os_info.num_old_tablespaces, 2);
assert_string_equal("/some/directory/for/999", os_info.old_tablespaces[0]);
assert_string_equal("/some/other/directory/for/999", os_info.old_tablespaces[1]);
}
int
main(int argc, char *argv[])
{
cmockery_parse_arguments(argc, argv);
const UnitTest tests[] = {
unit_test_setup_teardown(
test_it_finds_old_tablespaces_when_provided_as_a_file,
setup,
teardown),
unit_test_setup_teardown(
test_when_postgres_version_is_before_8_4_tablespace_directory_suffix_remains_empty,
setup,
teardown),
unit_test_setup_teardown(
test_when_postgres_version_8_4_tablespace_directory_suffix_remains_empty,
setup,
teardown),
unit_test_setup_teardown(
test_when_postgres_version_newer_than_8_4_tablespace_directory_suffix_contains_PG_version_and_catalog_version,
setup,
teardown),
unit_test_setup_teardown(
test_when_postgres_version_matches_gpdb6_postgres_version_tablespace_directory_suffix_contains_GPDB6_tablespace_layout,
setup,
teardown),
};
return run_tests(tests);
}
......@@ -172,7 +172,9 @@ upgrade_qd()
# Run pg_upgrade
pushd $1
time ${NEW_BINDIR}/pg_upgrade --mode=dispatcher --old-bindir=${OLD_BINDIR} --old-datadir=$2 --new-bindir=${NEW_BINDIR} --new-datadir=$3 ${PGUPGRADE_OPTS}
time ${NEW_BINDIR}/pg_upgrade --mode=dispatcher --old-bindir=${OLD_BINDIR} --old-datadir=$2 --new-bindir=${NEW_BINDIR} --new-datadir=$3 ${PGUPGRADE_OPTS} \
--old-gp-dbid="$4" --new-gp-dbid="$5"
if (( $? )) ; then
echo "ERROR: Failure encountered in upgrading qd node"
exit 1
......@@ -195,7 +197,9 @@ upgrade_segment()
# Run pg_upgrade
pushd $1
time ${NEW_BINDIR}/pg_upgrade --mode=segment --old-bindir=${OLD_BINDIR} --old-datadir=$2 --new-bindir=${NEW_BINDIR} --new-datadir=$3 ${PGUPGRADE_OPTS}
time ${NEW_BINDIR}/pg_upgrade --mode=segment --old-bindir=${OLD_BINDIR} --old-datadir=$2 --new-bindir=${NEW_BINDIR} --new-datadir=$3 ${PGUPGRADE_OPTS} \
--old-gp-dbid="$4" --new-gp-dbid="$5" --old-tablespaces-file="old_tablespaces.txt"
if (( $? )) ; then
echo "ERROR: Failure encountered in upgrading node"
exit 1
......@@ -466,7 +470,9 @@ main() {
local epoch_for_perf_start=`date +%s`
# Start by upgrading the master
upgrade_qd "${temp_root}/upgrade/qd" "${OLD_DATADIR}/qddir/demoDataDir-1/" "${NEW_DATADIR}/qddir/demoDataDir-1/"
local old_master_gp_dbid="1"
local new_master_gp_dbid="1"
upgrade_qd "${temp_root}/upgrade/qd" "${OLD_DATADIR}/qddir/demoDataDir-1/" "${NEW_DATADIR}/qddir/demoDataDir-1/" "$old_master_gp_dbid" "$new_master_gp_dbid"
print_delta_seconds $epoch_for_perf_start 'number_of_seconds_for_upgrade_qd'
# If this is a minimal smoketest to ensure that we are handling all objects
......@@ -500,12 +506,20 @@ main() {
# Upgrade the segment data files without dump/restore of the schema
local epoch_for_perf_QEstart=`date +%s`
upgrade_segment "${temp_root}/upgrade/dbfast$i" "${OLD_DATADIR}/dbfast$i/demoDataDir$j/" "${NEW_DATADIR}/dbfast$i/demoDataDir$j/"
local old_gp_dbid=$k
local new_gp_dbid=$k
upgrade_segment "${temp_root}/upgrade/dbfast$i" "${OLD_DATADIR}/dbfast$i/demoDataDir$j/" "${NEW_DATADIR}/dbfast$i/demoDataDir$j/" \
"$old_gp_dbid" "$new_gp_dbid"
print_delta_seconds $epoch_for_perf_QEstart 'number_of_seconds_for_upgrade_qe'
if (( $mirrors )) ; then
epoch_for_perf_QEMstart=`date +%s`
upgrade_segment "${temp_root}/upgrade/dbfast_mirror$i" "${OLD_DATADIR}/dbfast_mirror$i/demoDataDir$j/" "${NEW_DATADIR}/dbfast_mirror$i/demoDataDir$j/"
upgrade_segment "${temp_root}/upgrade/dbfast_mirror$i" "${OLD_DATADIR}/dbfast_mirror$i/demoDataDir$j/" "${NEW_DATADIR}/dbfast_mirror$i/demoDataDir$j/" \
"$old_gp_dbid" "$new_gp_dbid"
print_delta_seconds $epoch_for_perf_QEMstart 'number_of_seconds_for_upgrade_qdm'
fi
done
......
......@@ -1493,9 +1493,7 @@ dumpTablespaces(PGconn *conn)
"join (SELECT ts.oid AS oid, "
"ts.spcname AS spcname, "
"pg_catalog.Pg_get_userbyid(ts.spcowner) AS spcowner, "
"fs.fselocation "
"|| '/gp6/' "
"|| ts.oid :: text AS location, "
"fs.fselocation AS location, "
"ts.spcacl AS spcacl, "
"NULL AS spcoptions, "
"pg_catalog.Shobj_description(ts.oid, 'pg_tablespace'), "
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册