diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c index c1399c09b9..5c47e4463c 100644 --- a/src/bin/pg_upgrade/info.c +++ b/src/bin/pg_upgrade/info.c @@ -11,6 +11,8 @@ #include "access/transam.h" #include "catalog/pg_class_d.h" +#include "common/hashfn.h" +#include "common/logging.h" #include "pg_upgrade.h" static void create_rel_filename_map(const char *old_data, const char *new_data, @@ -26,6 +28,28 @@ static void free_rel_infos(RelInfoArr *rel_arr); static void print_db_infos(DbInfoArr *db_arr); static void print_rel_infos(RelInfoArr *rel_arr); +static uint32 hash_string_pointer(const char *s); +#define SH_PREFIX spacehash +#define SH_ELEMENT_TYPE space_entry_t +#define SH_KEY_TYPE const char * +#define SH_KEY name +#define SH_HASH_KEY(tb, key) hash_string_pointer(key) +#define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0) +#define SH_SCOPE extern +#define SH_RAW_ALLOCATOR pg_malloc0 +#define SH_DEFINE +#include "lib/simplehash.h" + +/* + * Helper function for spacehash hash table. + */ +static uint32 +hash_string_pointer(const char *s) +{ + unsigned char *ss = (unsigned char *) s; + + return hash_bytes(ss, strlen(s)); +} /* * gen_db_file_maps() @@ -402,11 +426,13 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo) i_relfilenumber, i_reltablespace; char query[QUERY_ALLOC]; - char *last_namespace = NULL, - *last_tablespace = NULL; query[0] = '\0'; /* initialize query string to empty */ + /* TODO: What is a good initial size? */ + dbinfo->db_namespaces = spacehash_create(16, NULL); + dbinfo->db_tablespaces = spacehash_create(16, NULL); + /* * Create a CTE that collects OIDs of regular user tables and matviews, * but excluding toast tables and indexes. We assume that relations with @@ -501,33 +527,29 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo) for (relnum = 0; relnum < ntups; relnum++) { RelInfo *curr = &relinfos[num_rels++]; + bool found; + space_entry_t *sp; curr->reloid = atooid(PQgetvalue(res, relnum, i_reloid)); curr->indtable = atooid(PQgetvalue(res, relnum, i_indtable)); curr->toastheap = atooid(PQgetvalue(res, relnum, i_toastheap)); nspname = PQgetvalue(res, relnum, i_nspname); - curr->nsp_alloc = false; /* * Many of the namespace and tablespace strings are identical, so we - * try to reuse the allocated string pointers where possible to reduce - * memory consumption. + * try to minimize allocated space by storing the names in a hash- + * table from which they can be referenced. */ - /* Can we reuse the previous string allocation? */ - if (last_namespace && strcmp(nspname, last_namespace) == 0) - curr->nspname = last_namespace; - else - { - last_namespace = curr->nspname = pg_strdup(nspname); - curr->nsp_alloc = true; - } + sp = spacehash_insert(dbinfo->db_namespaces, nspname, &found); + if (!found) + sp->name = pstrdup(nspname); + curr->nspname = sp->name; relname = PQgetvalue(res, relnum, i_relname); curr->relname = pg_strdup(relname); curr->relfilenumber = atooid(PQgetvalue(res, relnum, i_relfilenumber)); - curr->tblsp_alloc = false; /* Is the tablespace oid non-default? */ if (atooid(PQgetvalue(res, relnum, i_reltablespace)) != 0) @@ -538,14 +560,10 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo) */ tablespace = PQgetvalue(res, relnum, i_spclocation); - /* Can we reuse the previous string allocation? */ - if (last_tablespace && strcmp(tablespace, last_tablespace) == 0) - curr->tablespace = last_tablespace; - else - { - last_tablespace = curr->tablespace = pg_strdup(tablespace); - curr->tblsp_alloc = true; - } + sp = spacehash_insert(dbinfo->db_tablespaces, tablespace, &found); + if (!found) + sp->name = pstrdup(tablespace); + curr->tablespace = sp->name; } else /* A zero reltablespace oid indicates the database tablespace. */ @@ -569,6 +587,9 @@ free_db_and_rel_infos(DbInfoArr *db_arr) { free_rel_infos(&db_arr->dbs[dbnum].rel_arr); pg_free(db_arr->dbs[dbnum].db_name); + + spacehash_destroy(db_arr->dbs[dbnum].db_namespaces); + spacehash_destroy(db_arr->dbs[dbnum].db_tablespaces); } pg_free(db_arr->dbs); db_arr->dbs = NULL; @@ -582,13 +603,7 @@ free_rel_infos(RelInfoArr *rel_arr) int relnum; for (relnum = 0; relnum < rel_arr->nrels; relnum++) - { - if (rel_arr->rels[relnum].nsp_alloc) - pg_free(rel_arr->rels[relnum].nspname); pg_free(rel_arr->rels[relnum].relname); - if (rel_arr->rels[relnum].tblsp_alloc) - pg_free(rel_arr->rels[relnum].tablespace); - } pg_free(rel_arr->rels); rel_arr->nrels = 0; } diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 5f2a116f23..239c5c468a 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -133,15 +133,13 @@ extern char *output_files[]; typedef struct { /* Can't use NAMEDATALEN; not guaranteed to be same on client */ - char *nspname; /* namespace name */ + const char *nspname; /* namespace name */ char *relname; /* relation name */ Oid reloid; /* relation OID */ RelFileNumber relfilenumber; /* relation file number */ Oid indtable; /* if index, OID of its table, else 0 */ Oid toastheap; /* if toast table, OID of base table, else 0 */ - char *tablespace; /* tablespace path; "" for cluster default */ - bool nsp_alloc; /* should nspname be freed? */ - bool tblsp_alloc; /* should tablespace be freed? */ + const char *tablespace; /* tablespace path; "" for cluster default */ } RelInfo; typedef struct @@ -162,10 +160,29 @@ typedef struct Oid db_oid; RelFileNumber relfilenumber; /* the rest are used only for logging and error reporting */ - char *nspname; /* namespaces */ + const char *nspname; /* namespaces */ char *relname; } FileNameMap; +/* + * space_entry_t + * + * Hash table entries for recording namespace and tablespace names. + */ +typedef struct space_entry_t +{ + uint32 status; /* hash status */ + const char *name; +} space_entry_t; + +#define SH_PREFIX spacehash +#define SH_ELEMENT_TYPE space_entry_t +#define SH_KEY_TYPE const char * +#define SH_SCOPE extern +#define SH_RAW_ALLOCATOR pg_malloc0 +#define SH_DECLARE +#include "lib/simplehash.h" + /* * Structure to store database information */ @@ -181,6 +198,8 @@ typedef struct char *db_iculocale; int db_encoding; RelInfoArr rel_arr; /* array of all user relinfos */ + spacehash_hash *db_namespaces; /* hash of namespaces */ + spacehash_hash *db_tablespaces; /* hash of tablespaces */ } DbInfo; typedef struct