From: Craig Ringer Date: Fri, 16 May 2014 07:55:05 +0000 (+0800) Subject: bdr: Use database oid, not database name, as key in bdr.bdr_nodes X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=a8ab1172cb70071a47cfa9bf74c42f93876146b9;p=users%2Fandresfreund%2Fpostgres.git bdr: Use database oid, not database name, as key in bdr.bdr_nodes The key for a bdr node is (sysid, timelineid, dboid) so using dbname in bdr.bdr_nodes is incorrect. --- diff --git a/contrib/bdr/bdr--0.5.sql b/contrib/bdr/bdr--0.5.sql index 03923f5617..52e42b41b0 100644 --- a/contrib/bdr/bdr--0.5.sql +++ b/contrib/bdr/bdr--0.5.sql @@ -294,22 +294,18 @@ COMMENT ON COLUMN bdr_conflict_history.conflict_resolution IS 'How the conflict COMMENT ON COLUMN bdr_conflict_history.error_message IS 'On apply error, the error message from ereport/elog. Other error fields match.'; -- The bdr_nodes table tracks members of a BDR group; it's only concerned with --- one database, so the local and foreign database names are implicit. All we --- care about is the sysid. +-- one bdr group so it only has to track enough to uniquely identify each member +-- node, which is the (sysid, timeline, dboid) tuple for that node. -- -- The sysid must be a numeric (or string) because PostgreSQL has no uint64 SQL -- type. -- --- In future we may support different local dbnames, so store the dbname too. --- It's even possible we might replicate from one local DB to another (though --- who knows why we'd want to) so the PK should be the (dbname, sysid) tuple. --- CREATE TABLE bdr_nodes ( node_sysid text not null, -- Really a uint64 but we have no type for that node_timeline oid not null, - node_dbname name not null, + node_dboid oid not null, -- This is an oid local to the node_sysid cluster node_status "char" not null, - primary key(node_sysid, node_timeline, node_dbname), + primary key(node_sysid, node_timeline, node_dboid), check (node_status in ('i', 'c', 'r')) ); REVOKE ALL ON TABLE bdr_nodes FROM PUBLIC; @@ -318,7 +314,7 @@ SELECT pg_catalog.pg_extension_config_dump('bdr_nodes', ''); COMMENT ON TABLE bdr_nodes IS 'All known nodes in this BDR group.'; COMMENT ON COLUMN bdr_nodes.node_sysid IS 'system_identifier from the control file of the node'; COMMENT ON COLUMN bdr_nodes.node_timeline IS 'timeline ID of this node'; -COMMENT ON COLUMN bdr_nodes.node_dbname IS 'local database name on the node'; +COMMENT ON COLUMN bdr_nodes.node_dboid IS 'local database oid on the cluster (node_sysid, node_timeline)'; COMMENT ON COLUMN bdr_nodes.node_status IS 'Readiness of the node: [i]nitializing, [c]atchup, [r]eady. Doesn''t indicate connected/disconnected.'; CREATE TABLE bdr_queued_commands ( diff --git a/contrib/bdr/bdr.h b/contrib/bdr/bdr.h index 6cd5b80b2c..c80c4c9c96 100644 --- a/contrib/bdr/bdr.h +++ b/contrib/bdr/bdr.h @@ -320,8 +320,8 @@ extern void init_bdr_commandfilter(void); extern void bdr_apply_main(Datum main_arg); /* manipulation of bdr catalogs */ -extern char bdr_nodes_get_local_status(uint64 sysid, TimeLineID tli, Name dbname); -extern void bdr_nodes_set_local_status(Name dbname, char status); +extern char bdr_nodes_get_local_status(uint64 sysid, TimeLineID tli, Oid dboid); +extern void bdr_nodes_set_local_status(char status); extern Oid GetSysCacheOidError(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4); diff --git a/contrib/bdr/bdr_catalogs.c b/contrib/bdr/bdr_catalogs.c index 232de10ae0..d7a6bf0dce 100644 --- a/contrib/bdr/bdr_catalogs.c +++ b/contrib/bdr/bdr_catalogs.c @@ -23,6 +23,8 @@ #include "catalog/pg_type.h" +#include "commands/dbcommands.h" + #include "executor/spi.h" #include "replication/replication_identifier.h" @@ -61,10 +63,10 @@ GetSysCacheOidError(int cacheId, * SPI must be initialized, and you must be in a running transaction. */ char -bdr_nodes_get_local_status(uint64 sysid, TimeLineID tli, Name dbname) +bdr_nodes_get_local_status(uint64 sysid, TimeLineID tli, Oid dboid) { int spi_ret; - Oid argtypes[] = { TEXTOID, OIDOID, NAMEOID }; + Oid argtypes[] = { TEXTOID, OIDOID, OIDOID }; Datum values[3]; bool isnull; char status; @@ -87,16 +89,16 @@ bdr_nodes_get_local_status(uint64 sysid, TimeLineID tli, Name dbname) if (schema_oid == InvalidOid) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("No bdr schema is present in database %s, cannot create a bdr_output slot", - NameStr(*dbname)), + get_database_name(MyDatabaseId)), errhint("There is no bdr.bdr_connections entry for this database on the target node or bdr is not in shared_preload_libraries"))); values[0] = CStringGetTextDatum(sysid_str); values[1] = ObjectIdGetDatum(tli); - values[2] = NameGetDatum(dbname); + values[2] = ObjectIdGetDatum(dboid); spi_ret = SPI_execute_with_args( "SELECT node_status FROM bdr.bdr_nodes " - "WHERE node_sysid = $1 AND node_timeline = $2 AND node_dbname = $3", + "WHERE node_sysid = $1 AND node_timeline = $2 AND node_dboid = $3", 3, argtypes, values, NULL, false, 1); if (spi_ret != SPI_OK_SELECT) @@ -115,8 +117,8 @@ bdr_nodes_get_local_status(uint64 sysid, TimeLineID tli, Name dbname) } /* - * Insert a row for the local node's (sysid,dbname) with the passed status into - * bdr.bdr_nodes. No existing row for this key may exist. + * Insert a row for the local node's (sysid,tlid,dboid) with the passed status + * into bdr.bdr_nodes. No existing row for this key may exist. * * Unlike bdr_set_remote_status, '\0' may not be passed to delete the row, and * no upsert is performed. This is a simple insert only. @@ -128,10 +130,10 @@ bdr_nodes_get_local_status(uint64 sysid, TimeLineID tli, Name dbname) * not bound to any remote node replication state. */ void -bdr_nodes_set_local_status(Name dbname, char status) +bdr_nodes_set_local_status(char status) { int spi_ret; - Oid argtypes[] = { CHAROID, TEXTOID, OIDOID, NAMEOID }; + Oid argtypes[] = { CHAROID, TEXTOID, OIDOID, OIDOID }; Datum values[4]; char sysid_str[33]; @@ -147,20 +149,20 @@ bdr_nodes_set_local_status(Name dbname, char status) values[0] = CharGetDatum(status); values[1] = CStringGetTextDatum(sysid_str); values[2] = ObjectIdGetDatum(ThisTimeLineID); - values[3] = NameGetDatum(dbname); + values[3] = ObjectIdGetDatum(MyDatabaseId); spi_ret = SPI_execute_with_args( "INSERT INTO bdr.bdr_nodes" - " (node_status, node_sysid, node_timeline, node_dbname)" + " (node_status, node_sysid, node_timeline, node_dboid)" " VALUES ($1, $2, $3, $4);", 4, argtypes, values, NULL, false, 0); if (spi_ret != SPI_OK_INSERT) elog(ERROR, "Unable to insert row (status=%c, node_sysid=" - UINT64_FORMAT ", node_timeline=%u, node_dbname=%s) " + UINT64_FORMAT ", node_timeline=%u, node_dboid=%u) " "into bdr.bdr_nodes: SPI error %d", status, GetSystemIdentifier(), ThisTimeLineID, - NameStr(*dbname), spi_ret); + MyDatabaseId, spi_ret); } /* diff --git a/contrib/bdr/bdr_init_replica.c b/contrib/bdr/bdr_init_replica.c index 6b94857173..305d406449 100644 --- a/contrib/bdr/bdr_init_replica.c +++ b/contrib/bdr/bdr_init_replica.c @@ -102,15 +102,16 @@ find_init_replica_worker(Name dbname) * If no row is found, '\0' is returned. */ static char -bdr_get_remote_status(PGconn *pgconn, Name dbname) +bdr_get_remote_status(PGconn *pgconn) { PGresult *res; char status; - Oid param_types[] = {TEXTOID, OIDOID, NAMEOID}; + Oid param_types[] = {TEXTOID, OIDOID, OIDOID}; const char *param_values[3]; /* Needs to fit max length of UINT64_FORMAT */ char sysid_str[33]; char tlid_str[33]; + char mydatabaseid_str[33]; snprintf(sysid_str, sizeof(sysid_str), UINT64_FORMAT, GetSystemIdentifier()); @@ -120,22 +121,24 @@ bdr_get_remote_status(PGconn *pgconn, Name dbname) ThisTimeLineID); tlid_str[sizeof(tlid_str)-1] = '\0'; + snprintf(mydatabaseid_str, sizeof(mydatabaseid_str), "%u", + MyDatabaseId); + mydatabaseid_str[sizeof(mydatabaseid_str)-1] = '\0'; + param_values[0] = sysid_str; param_values[1] = tlid_str; - param_values[2] = NameStr(*dbname); + param_values[2] = mydatabaseid_str; res = PQexecParams(pgconn, "SELECT node_status FROM bdr.bdr_nodes " "WHERE node_sysid = $1 AND node_timeline = $2 " - "AND node_dbname = $3 " + "AND node_dboid = $3 " "FOR UPDATE", 3, param_types, param_values, NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - elog(FATAL, "bdr %s: Failed to get remote status during bdr init: " - "state %s: %s\n", NameStr(*dbname), - PQresStatus(PQresultStatus(res)), - PQresultErrorMessage(res)); + elog(FATAL, "bdr: Failed to get remote status during bdr init: state %s: %s\n", + PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res)); } if (PQntuples(res) == 0) /* No row found on remote, we're starting from scratch */ @@ -162,8 +165,8 @@ bdr_get_remote_status(PGconn *pgconn, Name dbname) * a group of BDR nodes. */ static char -bdr_set_remote_status(PGconn *pgconn, Name dbname, - const char status, const char prev_status) +bdr_set_remote_status(PGconn *pgconn, const char status, + const char prev_status) { PGresult *res; char *status_str; @@ -171,6 +174,7 @@ bdr_set_remote_status(PGconn *pgconn, Name dbname, /* Needs to fit max length of UINT64_FORMAT */ char sysid_str[33]; char tlid_str[33]; + char mydatabaseid_str[33]; if (status == prev_status) /* No action required (we could check the remote, but meh) */ @@ -184,27 +188,30 @@ bdr_set_remote_status(PGconn *pgconn, Name dbname, ThisTimeLineID); tlid_str[sizeof(tlid_str)-1] = '\0'; + snprintf(mydatabaseid_str, sizeof(mydatabaseid_str), "%u", + MyDatabaseId); + mydatabaseid_str[sizeof(mydatabaseid_str)-1] = '\0'; + if (status == '\0') { - Oid param_types[] = {TEXTOID, OIDOID, NAMEOID}; + Oid param_types[] = {TEXTOID, OIDOID, OIDOID}; const char *param_values[3]; char new_status; param_values[0] = sysid_str; param_values[1] = tlid_str; - param_values[2] = NameStr(*dbname); + param_values[2] = mydatabaseid_str; res = PQexecParams(pgconn, "DELETE FROM bdr.bdr_nodes WHERE node_sysid = $1" - " AND node_timeline = $2 AND node_dbname = $3 " + " AND node_timeline = $2 AND node_dboid = $3 " "RETURNING node_status", 3, param_types, param_values, NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - elog(FATAL, "bdr %s: Failed to delete row from bdr_nodes: status %s: %s\n", - NameStr(*dbname), PQresStatus(PQresultStatus(res)), - PQresultErrorMessage(res)); + elog(FATAL, "bdr: Failed to delete row from bdr_nodes: status %s: %s\n", + PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res)); } if (PQntuples(res) == 0) { @@ -212,10 +219,9 @@ bdr_set_remote_status(PGconn *pgconn, Name dbname, * If prev_status was '\0' we wouldn't be here, so we should've * got a returned value. */ - elog(FATAL, "bdr %s: bdr.bdr_nodes row for sysid=" UINT64_FORMAT - ", tlid=%u, dbname='%s' missing, expected row with status=%c", - NameStr(*dbname), sysid, ThisTimeLineID, NameStr(*dbname), - (int)prev_status); + elog(FATAL, "bdr: bdr.bdr_nodes row for sysid=" UINT64_FORMAT + ", tlid=%u, dboid=%u missing, expected row with status=%c", + sysid, ThisTimeLineID, MyDatabaseId, (int)prev_status); } status_str = PQgetvalue(res, 0, 0); Assert(strlen(status_str) == 1); @@ -223,17 +229,17 @@ bdr_set_remote_status(PGconn *pgconn, Name dbname, if (new_status != prev_status) { - elog(FATAL, "bdr %s: bdr.bdr_nodes row for node_sysid=" UINT64_FORMAT - ", timeline=%u, dbname='%s' had status=%c, expected status=%c", - NameStr(*dbname), sysid, ThisTimeLineID, NameStr(*dbname), - (int) new_status, (int) prev_status); + elog(FATAL, "bdr: bdr.bdr_nodes row for node_sysid=" UINT64_FORMAT + ", timeline=%u, dboid=%u had status=%c, expected status=%c", + sysid, ThisTimeLineID, MyDatabaseId, (int) new_status, + (int) prev_status); } PQclear(res); } else { - Oid param_types[] = {CHAROID, TEXTOID, OIDOID, NAMEOID}; + Oid param_types[] = {CHAROID, TEXTOID, OIDOID, OIDOID}; const char *param_values[4]; char new_status; char status_str[2]; @@ -242,25 +248,24 @@ bdr_set_remote_status(PGconn *pgconn, Name dbname, param_values[0] = status_str; param_values[1] = sysid_str; param_values[2] = tlid_str; - param_values[3] = NameStr(*dbname); + param_values[3] = mydatabaseid_str; res = PQexecParams(pgconn, "UPDATE bdr.bdr_nodes " "SET node_status = $1 " "WHERE node_sysid = $2 AND node_timeline = $3 " - "AND node_dbname = $4 " + "AND node_dboid = $4 " "RETURNING (" " SELECT node_status FROM bdr.bdr_nodes " " WHERE node_sysid = $2 AND node_timeline = $3 " - " AND node_dbname = $4" + " AND node_dboid = $4" ")", 4, param_types, param_values, NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { elog(FATAL, - "bdr %s: Failed to update bdr.nodes row: status %s: %s\n", - NameStr(*dbname), + "bdr: Failed to update bdr.nodes row: status %s: %s\n", PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res)); } if (PQntuples(res) != 0) @@ -273,10 +278,10 @@ bdr_set_remote_status(PGconn *pgconn, Name dbname, if (new_status != prev_status) { elog(FATAL, - "bdr %s: bdr.bdr_nodes row for node_sysid=" UINT64_FORMAT - ", timeline=%u, dbname='%s' had status=%c, expected status=%c", - NameStr(*dbname), sysid, ThisTimeLineID, NameStr(*dbname), - (int)new_status, (int)prev_status); + "bdr: bdr.bdr_nodes row for node_sysid=" UINT64_FORMAT + ", timeline=%u, dboid=%u had status=%c, expected status=%c", + sysid, ThisTimeLineID, MyDatabaseId, (int)new_status, + (int)prev_status); } PQclear(res); @@ -288,15 +293,15 @@ bdr_set_remote_status(PGconn *pgconn, Name dbname, PQclear(res); res = PQexecParams(pgconn, "INSERT INTO bdr.bdr_nodes" - " (node_status, node_sysid, node_timeline, node_dbname)" + " (node_status, node_sysid, node_timeline, node_dboid)" " VALUES ($1, $2, $3, $4);", 4, param_types, param_values, NULL, NULL, 0); if (PQresultStatus(res) != PGRES_COMMAND_OK) { elog(FATAL, - "bdr %s: Failed to insert row into bdr.bdr_nodes: status %s: %s\n", - NameStr(*dbname), PQresStatus(PQresultStatus(res)), + "bdr: Failed to insert row into bdr.bdr_nodes: status %s: %s\n", + PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res)); } PQclear(res); @@ -714,7 +719,7 @@ bdr_init_replica(Name dbname) elog(ERROR, "SPI already connected; this shouldn't be possible"); status = bdr_nodes_get_local_status(GetSystemIdentifier(), ThisTimeLineID, - dbname); + MyDatabaseId); if (status == 'r') { /* Already in ready state, nothing more to do */ @@ -759,7 +764,7 @@ bdr_init_replica(Name dbname) * We still have to ensure that bdr.bdr_nodes.status is 'r' for this * node so that slot creation is permitted. */ - bdr_nodes_set_local_status(dbname, 'r'); + bdr_nodes_set_local_status('r'); } /* * We no longer require the transaction for SPI; further work gets done on @@ -798,7 +803,7 @@ bdr_init_replica(Name dbname) NameStr(*dbname)); /* Get the bdr.bdr_nodes status field for our node id from the remote */ - status = bdr_get_remote_status(nonrepl_init_conn, dbname); + status = bdr_get_remote_status(nonrepl_init_conn); switch (status) { case '\0': @@ -848,8 +853,7 @@ bdr_init_replica(Name dbname) elog(DEBUG2, "bdr %s: previous failed initalization detected, cleaning up", NameStr(*dbname)); bdr_drop_slot_and_replication_identifier(init_replica_config); - status = bdr_set_remote_status(nonrepl_init_conn, dbname, - '\0', status); + status = bdr_set_remote_status(nonrepl_init_conn, '\0', status); break; default: @@ -871,8 +875,7 @@ bdr_init_replica(Name dbname) * We're starting from scratch or have cleaned up a previous failed * attempt. */ - status = bdr_set_remote_status(nonrepl_init_conn, dbname, - 'i', status); + status = bdr_set_remote_status(nonrepl_init_conn, 'i', status); /* * A list of all connections to make slots for, as indexes into @@ -991,7 +994,7 @@ bdr_init_replica(Name dbname) PQfinish(init_repl_conn); pfree(init_snapshot); - status = bdr_set_remote_status(nonrepl_init_conn, dbname, 'c', status); + status = bdr_set_remote_status(nonrepl_init_conn, 'c', status); } Assert(status == 'c'); @@ -1002,7 +1005,7 @@ bdr_init_replica(Name dbname) bdr_catchup_to_lsn( init_replica_worker->worker_data.apply_worker.connection_config_idx, min_remote_lsn); - status = bdr_set_remote_status(nonrepl_init_conn, dbname, 'r', status); + status = bdr_set_remote_status(nonrepl_init_conn, 'r', status); elog(INFO, "bdr %s: catchup worker finished, ready for normal replication", NameStr(*dbname)); diff --git a/contrib/bdr/bdr_output.c b/contrib/bdr/bdr_output.c index 0639a70329..81a6dae79b 100644 --- a/contrib/bdr/bdr_output.c +++ b/contrib/bdr/bdr_output.c @@ -202,7 +202,7 @@ bdr_ensure_node_ready() if (spi_ret != SPI_OK_CONNECT) elog(ERROR, "Local SPI connect failed; shouldn't happen"); - status = bdr_nodes_get_local_status(sysid, ThisTimeLineID, &dbname); + status = bdr_nodes_get_local_status(sysid, ThisTimeLineID, MyDatabaseId); SPI_finish(); @@ -214,7 +214,7 @@ bdr_ensure_node_ready() { const char * const base_msg = "bdr.bdr_nodes entry for local node (sysid=" UINT64_FORMAT - ", dbname=%s): %s"; + ", timelineid=%u, dboid=%u): %s"; switch (status) { case 'r': @@ -231,11 +231,9 @@ bdr_ensure_node_ready() */ ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg(base_msg, sysid, NameStr(dbname), - "row missing, bdr not active on this " - "database or is initializing."), - errhint("Add bdr to shared_preload_libraries and " - "check logs for bdr startup errors."))); + errmsg(base_msg, sysid, ThisTimeLineID, MyDatabaseId, + "row missing, bdr not active on this database or is initializing."), + errhint("Add bdr to shared_preload_libraries and check logs for bdr startup errors."))); break; case 'c': /* @@ -251,12 +249,9 @@ bdr_ensure_node_ready() */ ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg(base_msg, sysid, NameStr(dbname), "status='c'" - ", bdr still starting up: " - "catching up from remote node"), - errhint("Monitor pg_stat_replication on the " - "remote node, watch the logs and wait " - "until the node has caught up"))); + errmsg(base_msg, sysid, ThisTimeLineID, MyDatabaseId, + "status='c', bdr still starting up: catching up from remote node"), + errhint("Monitor pg_stat_replication on the remote node, watch the logs and wait until the node has caught up"))); break; case 'i': /* @@ -268,11 +263,9 @@ bdr_ensure_node_ready() */ ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg(base_msg, sysid, NameStr(dbname), - "status='i', bdr still starting up: applying " - "initial dump of remote node"), - errhint("Monitor pg_stat_activity and the logs, " - "wait until the node has caught up"))); + errmsg(base_msg, sysid, ThisTimeLineID, MyDatabaseId, + "status='i', bdr still starting up: applying initial dump of remote node"), + errhint("Monitor pg_stat_activity and the logs, wait until the node has caught up"))); break; default: elog(ERROR, "Unhandled case status=%c", status);