#define MAX_TRIES_FOR_NID 200
static Datum generate_node_id(const char *node_name);
+static void count_coords_datanodes(Relation rel, int *num_coord, int *num_dns);
/*
* GUC parameters.
if (*node_type == PGXC_NODE_DATANODE && NumDataNodes >= MaxDataNodes)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("Too many datanodes, current value of max_data_nodes is %d",
+ errmsg("Too many datanodes, current value of max_datanodes is %d",
MaxDataNodes)));
#endif
return 1;
}
+/*
+ * Count the number of coordinators and datanodes configured so far.
+ */
+static void
+count_coords_datanodes(Relation rel, int *num_coord, int *num_dns)
+{
+ int coordCount = 0, dnCount = 0;
+ HeapScanDesc scan;
+ HeapTuple tuple;
+
+ scan = heap_beginscan(rel, SnapshotSelf, 0, NULL);
+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+ {
+ Form_pgxc_node nodeForm = (Form_pgxc_node) GETSTRUCT(tuple);
+
+ /* Take definition for given node type */
+ switch (nodeForm->node_type)
+ {
+ case PGXC_NODE_COORDINATOR:
+ coordCount++;
+ break;
+ case PGXC_NODE_DATANODE:
+ dnCount++;
+ break;
+ default:
+ break;
+ }
+ }
+ heap_endscan(scan);
+
+ *num_coord = coordCount;
+ *num_dns = dnCount;
+}
/*
* PgxcNodeListAndCount
bool is_primary = false;
bool is_preferred = false;
Datum node_id;
+ int coordCount = 0, dnCount = 0;
/* Only a DB administrator can add nodes */
if (!superuser())
* There could be a relation race here if a similar Oid
* being created before the heap is inserted.
*/
- pgxcnodesrel = heap_open(PgxcNodeRelationId, RowExclusiveLock);
+ pgxcnodesrel = heap_open(PgxcNodeRelationId, AccessExclusiveLock);
+
+ /*
+ * Get the count of datanodes and coordinators added so far and make sure
+ * we're not exceeding the configured limits
+ *
+ * XXX This is not full proof because someone may first set
+ * max_coordinators or max_datanodes to a high value, add nodes and then
+ * lower the value again.
+ */
+ count_coords_datanodes(pgxcnodesrel, &coordCount, &dnCount);
+
+ if ((node_type == PGXC_NODE_DATANODE && dnCount >= MaxDataNodes) ||
+ (node_type == PGXC_NODE_COORDINATOR && coordCount >= MaxCoords))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+ errmsg("cannot add more than %d %s",
+ node_type == PGXC_NODE_COORDINATOR ?
+ MaxCoords : MaxDataNodes,
+ node_type == PGXC_NODE_COORDINATOR ?
+ "coordinators" : "datanodes"),
+ errhint("increase the value of %s GUC and restart the cluster",
+ node_type == PGXC_NODE_COORDINATOR ?
+ "max_coordinators" : "max_datanodes"
+ )));
+
+ }
/* Build entry tuple */
values[Anum_pgxc_node_name - 1] = DirectFunctionCall1(namein, CStringGetDatum(node_name));
CatalogUpdateIndexes(pgxcnodesrel, htup);
- heap_close(pgxcnodesrel, RowExclusiveLock);
+ heap_close(pgxcnodesrel, AccessExclusiveLock);
}
/*
bool new_record_nulls[Natts_pgxc_node];
bool new_record_repl[Natts_pgxc_node];
uint32 node_id;
+ int coordCount = 0, dnCount = 0;
/* Only a DB administrator can alter cluster nodes */
if (!superuser())
errmsg("must be superuser to change cluster nodes")));
/* Look at the node tuple, and take exclusive lock on it */
- rel = heap_open(PgxcNodeRelationId, RowExclusiveLock);
+ rel = heap_open(PgxcNodeRelationId, AccessExclusiveLock);
/* Check that node exists */
if (!OidIsValid(nodeOid))
errmsg("PGXC node %s: two nodes cannot be primary",
node_name)));
+ /*
+ * Get the count of datanodes and coordinators added so far and make sure
+ * we're not exceeding the configured limits
+ */
+ count_coords_datanodes(rel, &coordCount, &dnCount);
+
+ if ((node_type == PGXC_NODE_DATANODE && dnCount >= MaxDataNodes) ||
+ (node_type == PGXC_NODE_COORDINATOR && coordCount >= MaxCoords))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+ errmsg("cannot add more than %d %s",
+ node_type == PGXC_NODE_COORDINATOR ?
+ MaxCoords : MaxDataNodes,
+ node_type == PGXC_NODE_COORDINATOR ?
+ "coordinators" : "datanodes"),
+ errhint("increase the value of %s GUC and restart the cluster",
+ node_type == PGXC_NODE_COORDINATOR ?
+ "max_coordinators" : "max_datanodes"
+ )));
+
+ }
+
/* Update values for catalog entry */
MemSet(new_record, 0, sizeof(new_record));
MemSet(new_record_nulls, false, sizeof(new_record_nulls));