From 2c99bb99bc57d728fe93c17d0378fd13bcf69dd8 Mon Sep 17 00:00:00 2001
From: Danny Auble <da@llnl.gov>
Date: Fri, 1 May 2009 19:14:09 +0000
Subject: [PATCH] added support for classification in a cluster.  This doesn't
 work with sacctmgr yet.  it should be easy to add

---
 src/common/parse_spec.c                       | 37 +++--------
 src/common/slurm_accounting_storage.c         | 63 +++++++++++++++++++
 src/common/slurm_accounting_storage.h         | 17 ++++-
 .../mysql/accounting_storage_mysql.c          | 35 ++++++++---
 4 files changed, 114 insertions(+), 38 deletions(-)

diff --git a/src/common/parse_spec.c b/src/common/parse_spec.c
index 5989b01adfb..e559d39f7bb 100644
--- a/src/common/parse_spec.c
+++ b/src/common/parse_spec.c
@@ -41,6 +41,10 @@
 #  include "config.h"
 #endif
 
+#ifndef   _GNU_SOURCE
+#  define _GNU_SOURCE
+#endif
+
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -60,7 +64,6 @@
 static int   _load_long (long *destination, char *keyword, char *in_line) ;
 static int   _load_integer (int *destination, char *keyword, char *in_line) ;
 static int   _load_float (float *destination, char *keyword, char *in_line) ;
-static char *_strcasestr(char *haystack, char *needle);
 
 /* 
  * slurm_parser - parse the supplied specification into keyword/value pairs
@@ -137,7 +140,7 @@ _load_float (float *destination, char *keyword, char *in_line)
 	char *str_ptr1, *str_ptr2, *str_ptr3;
 	int i, str_len1, str_len2;
 
-	str_ptr1 = (char *) _strcasestr (in_line, keyword);
+	str_ptr1 = (char *) strcasestr (in_line, keyword);
 	if (str_ptr1 != NULL) {
 		str_len1 = strlen (keyword);
 		strcpy (scratch, str_ptr1 + str_len1);
@@ -175,7 +178,7 @@ _load_integer (int *destination, char *keyword, char *in_line)
 	char *str_ptr1, *str_ptr2, *str_ptr3;
 	int i, str_len1, str_len2;
 
-	str_ptr1 = (char *) _strcasestr (in_line, keyword);
+	str_ptr1 = (char *) strcasestr (in_line, keyword);
 	if (str_ptr1 != NULL) {
 		str_len1 = strlen (keyword);
 		strcpy (scratch, str_ptr1 + str_len1);
@@ -232,7 +235,7 @@ _load_long (long *destination, char *keyword, char *in_line)
 	char *str_ptr1, *str_ptr2, *str_ptr3;
 	int i, str_len1, str_len2;
 
-	str_ptr1 = (char *) _strcasestr (in_line, keyword);
+	str_ptr1 = (char *) strcasestr (in_line, keyword);
 	if (str_ptr1 != NULL) {
 		str_len1 = strlen (keyword);
 		strcpy (scratch, str_ptr1 + str_len1);
@@ -290,7 +293,7 @@ load_string  (char **destination, char *keyword, char *in_line)
 	char *str_ptr1, *str_ptr2, *str_ptr3;
 	int i, str_len1, str_len2;
 
-	str_ptr1 = (char *) _strcasestr (in_line, keyword);
+	str_ptr1 = (char *) strcasestr (in_line, keyword);
 	if (str_ptr1 != NULL) {
 		int quoted = 0;
 		str_len1 = strlen (keyword);
@@ -316,27 +319,3 @@ load_string  (char **destination, char *keyword, char *in_line)
 	}
 	return 0;
 }
-
-/* case insensitve version of strstr() */
-static char *
-_strcasestr(char *haystack, char *needle)
-{
-	int hay_inx,  hay_size  = strlen(haystack);
-	int need_inx, need_size = strlen(needle);
-	char *hay_ptr = haystack;
-
-	for (hay_inx=0; hay_inx<hay_size; hay_inx++) {
-		for (need_inx=0; need_inx<need_size; need_inx++) {
-			if (tolower((int) hay_ptr[need_inx]) != 
-			    tolower((int) needle [need_inx]))
-				break;		/* mis-match */
-		}
-
-		if (need_inx == need_size)	/* it matched */
-			return hay_ptr;
-		else				/* keep looking */
-			hay_ptr++;
-	}
-
-	return NULL;	/* no match anywhere in string */
-}
diff --git a/src/common/slurm_accounting_storage.c b/src/common/slurm_accounting_storage.c
index ff8c7c8f940..c31aab541ea 100644
--- a/src/common/slurm_accounting_storage.c
+++ b/src/common/slurm_accounting_storage.c
@@ -43,7 +43,12 @@
 #  include "config.h"
 #endif
 
+#ifndef   _GNU_SOURCE
+#  define _GNU_SOURCE
+#endif
+
 #include <pthread.h>
+#include <string.h>
 
 #include "src/common/list.h"
 #include "src/common/slurm_accounting_storage.h"
@@ -1600,6 +1605,7 @@ extern void pack_acct_cluster_rec(void *in, uint16_t rpc_version, Buf buffer)
 	if(rpc_version >= 5) {
 		if(!object) {
 			pack32(NO_VAL, buffer);
+			pack16(0, buffer);
 			packnull(buffer);
 			pack32(0, buffer);
 			pack32(0, buffer);
@@ -1628,6 +1634,7 @@ extern void pack_acct_cluster_rec(void *in, uint16_t rpc_version, Buf buffer)
 		}
 		count = NO_VAL;
 
+		pack16(object->classification, buffer);
 		packstr(object->control_host, buffer);
 		pack32(object->control_port, buffer);
 		pack32(object->cpu_count, buffer);
@@ -1757,6 +1764,7 @@ extern int unpack_acct_cluster_rec(void **object, uint16_t rpc_version,
 			}
 		}
 
+		safe_unpack16(&object_ptr->classification, buffer);
 		safe_unpackstr_xmalloc(&object_ptr->control_host,
 				       &uint32_tmp, buffer);
 		safe_unpack32(&object_ptr->control_port, buffer);
@@ -3419,6 +3427,7 @@ extern void pack_acct_cluster_cond(void *in, uint16_t rpc_version, Buf buffer)
 
 	if(rpc_version >= 5) {
 		if(!object) {
+			pack16(0, buffer);
 			pack32(NO_VAL, buffer);
 			pack_time(0, buffer);
 			pack_time(0, buffer);
@@ -3426,6 +3435,8 @@ extern void pack_acct_cluster_cond(void *in, uint16_t rpc_version, Buf buffer)
 			pack16(0, buffer);
 			return;
 		}
+
+		pack16(object->classification, buffer);
 		
 		if(object->cluster_list)
 			count = list_count(object->cluster_list);
@@ -3490,6 +3501,7 @@ extern int unpack_acct_cluster_cond(void **object, uint16_t rpc_version,
 	*object = object_ptr;
 
 	if(rpc_version >= 5) {
+		safe_unpack16(&object_ptr->classification, buffer);
 		safe_unpack32(&count, buffer);
 		if(count && count != NO_VAL) {
 			object_ptr->cluster_list =
@@ -7211,6 +7223,57 @@ extern char *get_qos_complete_str(List qos_list, List num_qos_list)
 	return print_this;
 }
 
+extern char *get_classification_str(uint16_t class)
+{
+	bool classified = class & ACCT_CLASSIFIED_FLAG;
+	acct_classification_type_t type = class & ACCT_CLASS_BASE;
+
+	switch(type) {
+	case ACCT_CLASS_CAPACITY:
+		if(classified)
+			return "*Capacity";
+		else
+			return "Capacity";
+		break;
+	case ACCT_CLASS_CAPABILITY:
+		if(classified)
+			return "*Capability";
+		else
+			return "Capability";
+		break;
+	case ACCT_CLASS_CAPAPACITY:
+		if(classified)
+			return "*Capapacity";
+		else
+			return "Capapacity";
+		break;
+	default:
+		if(classified)
+			return "*Unknown";
+		else
+			return "Unknown";
+		break;
+	}
+}
+
+extern uint16_t str_2_classification(char *class)
+{
+	uint16_t type = 0;
+	if(!class)
+		return type;
+
+	if(strcasestr(class, "capac"))
+		type = ACCT_CLASS_CAPACITY;
+	else if(strcasestr(class, "capab"))
+		type = ACCT_CLASS_CAPABILITY;
+	else if(strcasestr(class, "capap"))
+		type = ACCT_CLASS_CAPAPACITY;
+	
+	if(strcasestr(class, "class")) 
+		type |= ACCT_CLASSIFIED_FLAG;
+
+	return type;
+}
 
 extern void log_assoc_rec(acct_association_rec_t *assoc_ptr, List qos_list)
 {
diff --git a/src/common/slurm_accounting_storage.h b/src/common/slurm_accounting_storage.h
index 75df53de3f7..09a49134921 100644
--- a/src/common/slurm_accounting_storage.h
+++ b/src/common/slurm_accounting_storage.h
@@ -72,6 +72,17 @@ typedef enum {
 	ACCT_MODIFY_WCKEY,
 } acct_update_type_t;
 
+typedef enum {
+	ACCT_CLASS_NONE, /* no class given */
+	ACCT_CLASS_CAPABILITY, /* capability cluster */
+	ACCT_CLASS_CAPACITY, /* capacity cluster */
+	ACCT_CLASS_CAPAPACITY, /* a cluster that is both capability
+				* and capacity */
+} acct_classification_type_t;
+
+#define ACCT_CLASSIFIED_FLAG 0x0100
+#define ACCT_CLASS_BASE      0x00ff
+
 /* Association conditions used for queries of the database */
 typedef struct {
 	List acct_list;		/* list of char * */
@@ -228,6 +239,7 @@ typedef struct acct_association_rec {
 } acct_association_rec_t;
 
 typedef struct {
+	uint16_t classification; /* how this machine is classified */
 	List cluster_list; /* list of char * */
 	time_t usage_end; 
 	time_t usage_start; 
@@ -237,13 +249,13 @@ typedef struct {
 
 typedef struct {
 	List accounting_list; /* list of cluster_accounting_rec_t *'s */
+	uint16_t classification; /* how this machine is classified */
 	char *control_host;
 	uint32_t control_port;
 	uint32_t cpu_count;
 	char *name;
 	char *nodes;
 	acct_association_rec_t *root_assoc; /* root association for cluster */
-
 	uint16_t rpc_version; /* version of rpc this cluter is running */
 } acct_cluster_rec_t;
 
@@ -658,6 +670,9 @@ extern char *get_tree_acct_name(char *name, char *parent, List tree_list);
 
 extern char *get_qos_complete_str(List qos_list, List num_qos_list);
 
+extern char *get_classification_str(uint16_t class);
+extern uint16_t str_2_classification(char *class);
+
 extern void log_assoc_rec(acct_association_rec_t *assoc_ptr, List qos_list);
 
 extern int slurm_acct_storage_init(char *loc); /* load the plugin */
diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
index c9b6f9f8c46..daa0dada86b 100644
--- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
+++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
@@ -2887,7 +2887,7 @@ static int _mysql_acct_check_tables(MYSQL *db_conn)
 		{ "control_host", "tinytext not null default ''" },
 		{ "control_port", "mediumint not null default 0" },
 		{ "rpc_version", "mediumint not null default 0" },
-		{ "classification", "tinyint unsigned default 0" },
+		{ "classification", "smallint unsigned default 0" },
 		{ NULL, NULL}		
 	};
 
@@ -3983,21 +3983,23 @@ extern int acct_storage_p_add_clusters(mysql_conn_t *mysql_conn, uint32_t uid,
 			continue;
 		}
 
-		xstrcat(cols, "creation_time, mod_time, acct, cluster");
+		xstrcat(cols, "creation_time, mod_time, acct, "
+			"cluster, classification");
 		xstrfmtcat(vals, "%d, %d, 'root', \"%s\"",
-			   now, now, object->name);
+			   now, now, object->name, object->classification);
 		xstrfmtcat(extra, ", mod_time=%d", now);
 		if(object->root_assoc)
 			_setup_association_limits(object->root_assoc, &cols, 
 						  &vals, &extra,
 						  QOS_LEVEL_SET, 1);
 		xstrfmtcat(query, 
-			   "insert into %s (creation_time, mod_time, name) "
-			   "values (%d, %d, \"%s\") "
+			   "insert into %s (creation_time, mod_time, "
+			   "name, classification) "
+			   "values (%d, %d, \"%s\", %u) "
 			   "on duplicate key update deleted=0, mod_time=%d, "
 			   "control_host='', control_port=0;",
 			   cluster_table, 
-			   now, now, object->name,
+			   now, now, object->name, object->classification,
 			   now);
 		debug3("%d(%d) query\n%s",
 		       mysql_conn->conn, __LINE__, query);
@@ -5130,6 +5132,7 @@ extern List acct_storage_p_modify_clusters(mysql_conn_t *mysql_conn,
 	int set = 0;
 	MYSQL_RES *result = NULL;
 	MYSQL_ROW row;
+	bool clust_reg = false;
 
 	/* If you need to alter the default values of the cluster use
 	 * modify_associations since this is used only for registering
@@ -5160,20 +5163,33 @@ extern List acct_storage_p_modify_clusters(mysql_conn_t *mysql_conn,
 		xstrcat(extra, ")");
 	}
 
+	if(cluster_cond->classification) {
+		xstrfmtcat(extra, " && (classification & %u)",
+			   cluster_cond->classification);
+	}
+
 	set = 0;
 	if(cluster->control_host) {
 		xstrfmtcat(vals, ", control_host='%s'", cluster->control_host);
 		set++;
+		clust_reg = true;
 	}
 
 	if(cluster->control_port) {
 		xstrfmtcat(vals, ", control_port=%u", cluster->control_port);
 		set++;
+		clust_reg = true;
 	}
 
 	if(cluster->rpc_version) {
 		xstrfmtcat(vals, ", rpc_version=%u", cluster->rpc_version);
 		set++;
+		clust_reg = true;
+	}
+
+	if(cluster->classification) {
+		xstrfmtcat(vals, ", classification=%u", 
+			   cluster->classification);
 	}
 
 	if(!vals) {
@@ -5181,7 +5197,7 @@ extern List acct_storage_p_modify_clusters(mysql_conn_t *mysql_conn,
 		errno = SLURM_NO_CHANGE_IN_DATA;
 		error("Nothing to change");
 		return NULL;
-	} else if(set != 3) {
+	} else if(clust_reg && (set != 3)) {
 		xfree(vals);
 		xfree(extra);
 		errno = EFAULT;
@@ -5215,7 +5231,7 @@ extern List acct_storage_p_modify_clusters(mysql_conn_t *mysql_conn,
 		object = xstrdup(row[0]);
 
 		/* check to see if this is the first time to register */
-		if(row[1][0] == '0')
+		if(clust_reg && (row[1][0] == '0'))
 			set = 0;
 
 		list_append(ret_list, object);
@@ -7945,12 +7961,14 @@ extern List acct_storage_p_get_clusters(mysql_conn_t *mysql_conn, uid_t uid,
 	/* if this changes you will need to edit the corresponding enum */
 	char *cluster_req_inx[] = {
 		"name",
+		"classification",
 		"control_host",
 		"control_port",
 		"rpc_version",
 	};
 	enum {
 		CLUSTER_REQ_NAME,
+		CLUSTER_REQ_CLASS,
 		CLUSTER_REQ_CH,
 		CLUSTER_REQ_CP,
 		CLUSTER_REQ_VERSION,
@@ -8040,6 +8058,7 @@ empty:
 				cluster_cond->usage_end);
 		}
 
+		cluster->classification = atoi(row[CLUSTER_REQ_CLASS]);
 		cluster->control_host = xstrdup(row[CLUSTER_REQ_CH]);
 		cluster->control_port = atoi(row[CLUSTER_REQ_CP]);
 		cluster->rpc_version = atoi(row[CLUSTER_REQ_VERSION]);
-- 
GitLab