Просмотр исходного кода

Qnetd: ffsplit: Add no active clients heuristic

On 50:50 split, ffsplit algorithm now prefers partition with
higher number of active clients. Tie-breaker is used only if both
partitions have same number of active clients.

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 9 лет назад
Родитель
Сommit
3a2d48b774
1 измененных файлов с 83 добавлено и 33 удалено
  1. 83 33
      qdevices/qnetd-algo-ffsplit.c

+ 83 - 33
qdevices/qnetd-algo-ffsplit.c

@@ -275,61 +275,109 @@ qnetd_algo_ffsplit_is_membership_stable(const struct qnetd_client *client, int c
 	return (1);
 	return (1);
 }
 }
 
 
+static size_t
+qnetd_algo_ffsplit_no_active_clients_in_partition(const struct qnetd_client *client,
+    const struct node_list *membership_node_list)
+{
+	const struct node_list_entry *iter_node;
+	const struct qnetd_client *iter_client;
+	size_t res;
+
+	res = 0;
+
+	if (client == NULL || membership_node_list == NULL) {
+		return (0);
+	}
+
+	TAILQ_FOREACH(iter_node, membership_node_list, entries) {
+		iter_client = qnetd_cluster_find_client_by_node_id(client->cluster,
+		    iter_node->node_id);
+		if (iter_client != NULL) {
+			res++;
+		}
+	}
+
+	return (res);
+}
+
 /*
 /*
- * 0 - Not quarate
- * 1 - Quorate but not fulfilling tie breaker or quorate with more than 50%
- * 2 - Quorate and fulfilling tie breaker
+ * Compares two partitions. Return 1 if client1, config_node_list1, membership_node_list1 is
+ * "better" than client2, config_node_list2, membership_node_list2
  */
  */
-static unsigned int
-qnetd_algo_ffsplit_get_partition_score(const struct qnetd_client *client,
-    const struct node_list *config_node_list, const struct node_list *membership_node_list)
+static int
+qnetd_algo_ffsplit_partition_cmp(const struct qnetd_client *client1,
+    const struct node_list *config_node_list1, const struct node_list *membership_node_list1,
+    const struct qnetd_client *client2,
+    const struct node_list *config_node_list2, const struct node_list *membership_node_list2)
 {
 {
+	size_t part1_active_clients, part2_active_clients;
 
 
-	if (node_list_size(config_node_list) % 2 != 0) {
+	if (node_list_size(config_node_list1) % 2 != 0) {
 		/*
 		/*
 		 * Odd clusters never split into 50:50.
 		 * Odd clusters never split into 50:50.
 		 */
 		 */
-		if (node_list_size(membership_node_list) > node_list_size(config_node_list) / 2) {
+		if (node_list_size(membership_node_list1) > node_list_size(config_node_list1) / 2) {
 			return (1);
 			return (1);
 		} else {
 		} else {
 			return (0);
 			return (0);
 		}
 		}
 	} else {
 	} else {
-		if (node_list_size(membership_node_list) > node_list_size(config_node_list) / 2) {
+		if (node_list_size(membership_node_list1) > node_list_size(config_node_list1) / 2) {
 			return (1);
 			return (1);
-		} else if (node_list_size(membership_node_list) < node_list_size(config_node_list) / 2) {
+		} else if (node_list_size(membership_node_list1) < node_list_size(config_node_list1) / 2) {
 			return (0);
 			return (0);
+		}
+
+		/*
+		 * 50:50 split
+		 */
+
+		/*
+		 * Check how many active clients are in partitions
+		 */
+		part1_active_clients = qnetd_algo_ffsplit_no_active_clients_in_partition(
+		    client1, membership_node_list1);
+		part2_active_clients = qnetd_algo_ffsplit_no_active_clients_in_partition(
+		    client2, membership_node_list2);
+
+		if (part1_active_clients > part2_active_clients) {
+			return (1);
+		} else if (part1_active_clients < part2_active_clients) {
+			return (0);
+		}
+
+		/*
+		 * Number of active clients in both partitions equals. Use tie-breaker.
+		 */
+
+		if (qnetd_algo_ffsplit_is_prefered_partition(client1, config_node_list1,
+		    membership_node_list1)) {
+			return (1);
 		} else {
 		} else {
-			/*
-			 * 50:50 split
-			 */
-			if (qnetd_algo_ffsplit_is_prefered_partition(client, config_node_list,
-			    membership_node_list)) {
-				return (2);
-			} else {
-				return (1);
-			}
+			return (0);
 		}
 		}
 	}
 	}
 
 
-	qnetd_log(LOG_CRIT, "qnetd_algo_ffsplit_get_partition_score unhandled case");
+	qnetd_log(LOG_CRIT, "qnetd_algo_ffsplit_partition_cmp unhandled case");
 	exit(1);
 	exit(1);
-
-	return (-1);
+	/* NOTREACHED */
 }
 }
 
 
+/*
+ * Select best partition for given client->cluster.
+ * If there is no partition which could become quorate, NULL is returned
+ */
 static const struct node_list *
 static const struct node_list *
 qnetd_algo_ffsplit_select_partition(const struct qnetd_client *client, int client_leaving,
 qnetd_algo_ffsplit_select_partition(const struct qnetd_client *client, int client_leaving,
     const struct node_list *config_node_list, const struct node_list *membership_node_list)
     const struct node_list *config_node_list, const struct node_list *membership_node_list)
 {
 {
-	unsigned int highest_score, iter_score;
 	const struct qnetd_client *iter_client;
 	const struct qnetd_client *iter_client;
-	const struct node_list *result_node_list;
-	const struct node_list *iter_config_node_list;
-	const struct node_list *iter_membership_node_list;
+	const struct qnetd_client *best_client;
+	const struct node_list *best_config_node_list, *best_membership_node_list;
+	const struct node_list *iter_config_node_list, *iter_membership_node_list;
 
 
-	highest_score = 0;
-	result_node_list = NULL;
+	best_client = NULL;
+	best_config_node_list = best_membership_node_list = NULL;
 
 
 	/*
 	/*
 	 * Get highest score
 	 * Get highest score
@@ -347,14 +395,16 @@ qnetd_algo_ffsplit_select_partition(const struct qnetd_client *client, int clien
 			iter_membership_node_list = &iter_client->last_membership_node_list;
 			iter_membership_node_list = &iter_client->last_membership_node_list;
 		}
 		}
 
 
-		if ((iter_score = qnetd_algo_ffsplit_get_partition_score(iter_client, iter_config_node_list,
-		    iter_membership_node_list)) > highest_score) {
-			highest_score = iter_score;
-			result_node_list = iter_membership_node_list;
+		if (qnetd_algo_ffsplit_partition_cmp(iter_client, iter_config_node_list,
+		    iter_membership_node_list, best_client, best_config_node_list,
+		    best_membership_node_list) > 0) {
+			best_client = iter_client;
+			best_config_node_list = iter_config_node_list;
+			best_membership_node_list = iter_membership_node_list;
 		}
 		}
 	}
 	}
 
 
-	return (result_node_list);
+	return (best_membership_node_list);
 }
 }
 
 
 /*
 /*