From 0340107179c024ade87e626e737ba4dba934f366 Mon Sep 17 00:00:00 2001
From: Danny Auble <da@llnl.gov>
Date: Thu, 30 Apr 2009 21:13:28 +0000
Subject: [PATCH] fix for reservations to create new entries in the database
 when something about nodes or cpus or flags change

---
 .../mysql/accounting_storage_mysql.c          | 12 ++--
 src/slurmctld/reservation.c                   | 49 ++++++++++-----
 src/slurmctld/slurmctld.h                     |  1 +
 src/sview/common.c                            | 63 ++++++++++++++++++-
 4 files changed, 104 insertions(+), 21 deletions(-)

diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
index ceb404d4ab6..633a4549a20 100644
--- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
+++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
@@ -2890,6 +2890,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" },
 		{ NULL, NULL}		
 	};
 
@@ -6225,7 +6226,7 @@ try_again:
 		resv->cpus = atoi(row[RESV_CPU]);
 
 		
-	if(resv->flags == (uint16_t)NO_VAL) 
+	if(resv->flags != (uint16_t)NO_VAL) 
 		set = 1;
 	else
 		resv->flags = atoi(row[RESV_FLAGS]);
@@ -6243,13 +6244,12 @@ try_again:
 
 	mysql_free_result(result);
 
-	_setup_resv_limits(resv, &cols, &vals, &extra);
 	/* use start below instead of resv->time_start_prev
 	 * just incase we have a different one from being out
 	 * of sync
 	 */
-
-	if((start < now) || !set) {
+	if((start > now) || !set) {
+		_setup_resv_limits(resv, &cols, &vals, &extra);
 		/* we haven't started the reservation yet, or
 		   we are changing the associations or end
 		   time which we can just update it */
@@ -6260,6 +6260,10 @@ try_again:
 				       start,
 				       resv->cluster);
 	} else {
+		/* since we change the start time here to now we can't
+		   run the setup before here */
+/* 		resv->time_start = now; */
+		_setup_resv_limits(resv, &cols, &vals, &extra);
 		/* time_start is already done above and we
 		 * changed something that is in need on a new
 		 * entry. */
diff --git a/src/slurmctld/reservation.c b/src/slurmctld/reservation.c
index 5c662664f05..558526c3ab1 100644
--- a/src/slurmctld/reservation.c
+++ b/src/slurmctld/reservation.c
@@ -157,6 +157,7 @@ static slurmctld_resv_t *_copy_resv(slurmctld_resv_t *resv_orig_ptr)
 	resv_copy_ptr->part_ptr = resv_orig_ptr->part_ptr;
 	resv_copy_ptr->resv_id = resv_orig_ptr->resv_id;
 	resv_copy_ptr->start_time = resv_orig_ptr->start_time;
+	resv_copy_ptr->start_time_first = resv_orig_ptr->start_time_first;
 	resv_copy_ptr->start_time_prev = resv_orig_ptr->start_time_prev;
 	resv_copy_ptr->users = xstrdup(resv_orig_ptr->users);
 	resv_copy_ptr->user_cnt = resv_orig_ptr->user_cnt;
@@ -481,8 +482,6 @@ static int _post_resv_update(slurmctld_resv_t *resv_ptr,
 	resv.cluster = slurmctld_cluster_name;
 	resv.id = resv_ptr->resv_id;
 	resv.time_end = resv_ptr->end_time;
-	resv.time_start = resv_ptr->start_time;
-	resv.time_start_prev = resv_ptr->start_time_prev;
 	
 	if(!old_resv_ptr) {
 		resv.assocs = resv_ptr->assoc_list;
@@ -490,9 +489,11 @@ static int _post_resv_update(slurmctld_resv_t *resv_ptr,
 		resv.flags = resv_ptr->flags;
 		resv.nodes = resv_ptr->node_list;
 	} else {
+		time_t now = time(NULL);
+		
 		if(old_resv_ptr->assoc_list && resv_ptr->assoc_list) {
 			if(strcmp(old_resv_ptr->assoc_list,
-				  resv_ptr->assoc_list))
+				  resv_ptr->assoc_list)) 
 				resv.assocs = resv_ptr->assoc_list;
 		} else if(resv_ptr->assoc_list)
 			resv.assocs = resv_ptr->assoc_list;
@@ -513,7 +514,23 @@ static int _post_resv_update(slurmctld_resv_t *resv_ptr,
 				resv.nodes = resv_ptr->node_list;
 		} else if(resv_ptr->node_list) 
 			resv.nodes = resv_ptr->node_list;
+		
+		/* Here if the reservation has started already we need
+		   to mark a new start time for it if certain
+		   variables are needed in accounting.  Right now if
+		   the flags, nodes, or cpu count changes we need a
+		   new start time of now. */
+		if((resv_ptr->start_time < now)
+		   && (resv.nodes 
+		       || (resv.flags != (uint16_t)NO_VAL)
+		       || (resv.cpus != (uint32_t)NO_VAL))) {
+			resv_ptr->start_time_prev = resv_ptr->start_time;
+			resv_ptr->start_time = now;
+		}
 	}
+	/* now set the (maybe new) start_times */
+	resv.time_start = resv_ptr->start_time;
+	resv.time_start_prev = resv_ptr->start_time_prev;
 
 	if(resv.nodes && resv_ptr->node_bitmap) 
 		resv.node_inx = bit_fmt(temp_bit, sizeof(temp_bit),
@@ -929,7 +946,7 @@ static void _pack_resv(slurmctld_resv_t *resv_ptr, Buf buffer,
 	pack32(resv_ptr->node_cnt,	buffer);
 	packstr(resv_ptr->node_list,	buffer);
 	packstr(resv_ptr->partition,	buffer);
-	pack_time(resv_ptr->start_time,	buffer);
+	pack_time(resv_ptr->start_time_first,	buffer);
 	pack16(resv_ptr->flags,		buffer);
 	packstr(resv_ptr->users,	buffer);
 
@@ -938,13 +955,9 @@ static void _pack_resv(slurmctld_resv_t *resv_ptr, Buf buffer,
 		pack32(resv_ptr->cpu_cnt,	buffer);
 		pack32(resv_ptr->resv_id,	buffer);
 		pack_time(resv_ptr->start_time_prev,	buffer);
+		pack_time(resv_ptr->start_time,	buffer);
 	} else {
-		time_t now = time(NULL);
-		/* only send the bitmap if it is valid now. */
-		if(resv_ptr->start_time > now || resv_ptr->end_time < now)
-			pack_bit_fmt(NULL, buffer);
-		else
-			pack_bit_fmt(resv_ptr->node_bitmap, buffer);
+		pack_bit_fmt(resv_ptr->node_bitmap, buffer);
 	}
 }
 
@@ -1051,9 +1064,9 @@ extern int create_resv(resv_desc_msg_t *resv_desc_ptr)
 			rc = ESLURM_INVALID_TIME_VALUE;
 			goto bad_parse;
 		}
-	} else
+	} else 
 		resv_desc_ptr->start_time = now;
-	
+
 	if (resv_desc_ptr->end_time != (time_t) NO_VAL) {
 		if (resv_desc_ptr->end_time < (now - 60)) {
 			info("Reservation requestion has invalid end time");
@@ -1172,6 +1185,7 @@ extern int create_resv(resv_desc_msg_t *resv_desc_ptr)
 	resv_desc_ptr->partition = NULL;	/* Nothing left to free */
 	resv_ptr->part_ptr	= part_ptr;
 	resv_ptr->start_time	= resv_desc_ptr->start_time;
+	resv_ptr->start_time_first = resv_ptr->start_time;
 	resv_ptr->start_time_prev = resv_ptr->start_time;
 	resv_ptr->flags		= resv_desc_ptr->flags;
 	resv_ptr->users		= resv_desc_ptr->users;
@@ -1322,7 +1336,7 @@ extern int update_resv(resv_desc_msg_t *resv_desc_ptr)
 		resv_ptr->end_time = resv_desc_ptr->end_time;
 	}
 	if (resv_desc_ptr->duration != NO_VAL) {
-		resv_ptr->end_time = resv_ptr->start_time + 
+		resv_ptr->end_time = resv_ptr->start_time_first + 
 				     (resv_desc_ptr->duration * 60);
 	}
 	if (resv_ptr->start_time >= resv_ptr->end_time) {
@@ -1887,7 +1901,7 @@ extern int load_all_resv_state(int recover)
 				       &uint32_tmp,	buffer);
 		safe_unpackstr_xmalloc(&resv_ptr->partition,
 				       &uint32_tmp, 	buffer);
-		safe_unpack_time(&resv_ptr->start_time,	buffer);
+		safe_unpack_time(&resv_ptr->start_time_first,	buffer);
 		safe_unpack16(&resv_ptr->flags,		buffer);
 		safe_unpackstr_xmalloc(&resv_ptr->users,&uint32_tmp, buffer);
 
@@ -1897,6 +1911,7 @@ extern int load_all_resv_state(int recover)
 		safe_unpack32(&resv_ptr->cpu_cnt,	buffer);
 		safe_unpack32(&resv_ptr->resv_id,	buffer);
 		safe_unpack_time(&resv_ptr->start_time_prev, buffer);
+		safe_unpack_time(&resv_ptr->start_time, buffer);
 
 		list_append(resv_list, resv_ptr);
 		info("Recovered state of reservation %s", resv_ptr->name);
@@ -2391,8 +2406,9 @@ extern void fini_job_resv_check(void)
 		    (resv_ptr->flags & RESERVE_FLAG_DAILY)) {
 			verbose("Advance reservation %s one day",
 			resv_ptr->name);
-			resv_ptr->start_time_prev = resv_ptr->start_time;
 			resv_ptr->start_time += 24 * 60 * 60;
+			resv_ptr->start_time_prev = resv_ptr->start_time;
+			resv_ptr->start_time_first = resv_ptr->start_time;
 			resv_ptr->end_time   += 24 * 60 * 60;
 			_post_resv_update(resv_ptr, NULL);
 			last_resv_update = now;
@@ -2403,8 +2419,9 @@ extern void fini_job_resv_check(void)
 		    (resv_ptr->flags & RESERVE_FLAG_WEEKLY)) {
 			verbose("Advance reservation %s one week",
 				resv_ptr->name);
-			resv_ptr->start_time_prev = resv_ptr->start_time;
 			resv_ptr->start_time += 7 * 24 * 60 * 60;
+			resv_ptr->start_time_prev = resv_ptr->start_time;
+			resv_ptr->start_time_first = resv_ptr->start_time;
 			resv_ptr->end_time   += 7 * 24 * 60 * 60;
 			_post_resv_update(resv_ptr, NULL);
 			last_resv_update = now;
diff --git a/src/slurmctld/slurmctld.h b/src/slurmctld/slurmctld.h
index ef96cef664d..c39b9796f4b 100644
--- a/src/slurmctld/slurmctld.h
+++ b/src/slurmctld/slurmctld.h
@@ -349,6 +349,7 @@ typedef struct slurmctld_resv {
 	struct part_record *part_ptr;	/* pointer to partition used	*/
 	uint32_t resv_id;	/* unique reservation ID, internal use	*/
 	time_t start_time;	/* start time of reservation		*/
+	time_t start_time_first;/* when the reservation first started	*/
 	time_t start_time_prev;	/* If start time was changed this is
 				 * the pervious start time.  Needed
 				 * for accounting */
diff --git a/src/sview/common.c b/src/sview/common.c
index c30902a39d0..f6b6ea6efb6 100644
--- a/src/sview/common.c
+++ b/src/sview/common.c
@@ -166,6 +166,56 @@ cleanup:
 	return ret;
 }
 
+static int _sort_iter_compare_func_bp_list(GtkTreeModel *model,
+					   GtkTreeIter  *a,
+					   GtkTreeIter  *b,
+					   gpointer      userdata)
+{
+	int sortcol = GPOINTER_TO_INT(userdata);
+	int ret = 0;
+	int len1 = 0, len2 = 0;
+	gchar *name1 = NULL, *name2 = NULL;
+	
+	gtk_tree_model_get(model, a, sortcol, &name1, -1);
+	gtk_tree_model_get(model, b, sortcol, &name2, -1);
+	
+	if (name1 == NULL || name2 == NULL) {
+		if (name1 == NULL && name2 == NULL)
+			goto cleanup; /* both equal => ret = 0 */
+		
+		ret = (name1 == NULL) ? -1 : 1;
+	} else {
+		/* sort like a human would 
+		   meaning snowflake2 would be greater than
+		   snowflake12 */
+		len1 = strlen(name1);
+		len2 = strlen(name2);
+		while((ret < len1) && (!g_ascii_isdigit(name1[ret]))) 
+			ret++;
+		if(ret < len1) {
+			if(!g_ascii_strncasecmp(name1, name2, ret)) {
+				if(len1 > len2)
+					ret = 1;
+				else if(len1 < len2)
+					ret = -1;
+				else {
+					ret = g_ascii_strcasecmp(name1, name2);
+				}
+			} else {
+				ret = g_ascii_strcasecmp(name1, name2);
+			}
+			
+		} else {
+			ret = g_ascii_strcasecmp(name1, name2);
+		}
+	}
+cleanup:
+	g_free(name1);
+	g_free(name2);
+	
+	return ret;
+}
+
 static void _editing_started(GtkCellRenderer *cell,
 			     GtkCellEditable *editable,
 			     const gchar     *path,
@@ -621,7 +671,9 @@ extern GtkTreeStore *create_treestore(GtkTreeView *tree_view,
 			
 			break;
 		case G_TYPE_STRING:
-			if(!strcasecmp(display_data[i].name, "Nodes")) {
+			if(!strcasecmp(display_data[i].name, "Nodes")
+			   || !strcasecmp(display_data[i].name, "Real Memory")
+			   || !strcasecmp(display_data[i].name, "Tmp Disk")) {
 				gtk_tree_sortable_set_sort_func(
 					GTK_TREE_SORTABLE(treestore), 
 					display_data[i].id, 
@@ -629,6 +681,15 @@ extern GtkTreeStore *create_treestore(GtkTreeView *tree_view,
 					GINT_TO_POINTER(display_data[i].id), 
 					NULL); 
 				break;
+			} else if(!strcasecmp(display_data[i].name,
+					      "BP List")) {
+				gtk_tree_sortable_set_sort_func(
+					GTK_TREE_SORTABLE(treestore), 
+					display_data[i].id, 
+					_sort_iter_compare_func_bp_list,
+					GINT_TO_POINTER(display_data[i].id), 
+					NULL); 
+				break;
 			} else {
 				gtk_tree_sortable_set_sort_func(
 					GTK_TREE_SORTABLE(treestore), 
-- 
GitLab