Browse Source

H2O: Extract a generic version of the fortunes sorting algorithm (#4695)

Anton Kirilov 6 years ago
parent
commit
49dea56870

+ 6 - 6
frameworks/C/h2o/src/database.c

@@ -32,12 +32,6 @@
 #define IS_RESETTING 1
 #define IS_WRITING 2
 
-typedef struct {
-	list_t l;
-	const char *name;
-	const char *query;
-} prepared_statement_t;
-
 typedef struct {
 	list_t l;
 	PGconn *conn;
@@ -49,6 +43,12 @@ typedef struct {
 	h2o_timeout_entry_t h2o_timeout_entry;
 } db_conn_t;
 
+typedef struct {
+	list_t l;
+	const char *name;
+	const char *query;
+} prepared_statement_t;
+
 static int do_database_write(db_conn_t *db_conn);
 static int do_execute_query(db_conn_t *db_conn, bool direct_notification);
 static void error_notification(thread_context_t *ctx, bool timeout, const char *error_string);

+ 1 - 81
frameworks/C/h2o/src/handlers/fortune.c

@@ -88,8 +88,6 @@ static void cleanup_request(void *data);
 static int compare_fortunes(const list_t *x, const list_t *y);
 static void complete_fortunes(struct st_h2o_generator_t *self, h2o_req_t *req);
 static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req);
-static list_t *get_sorted_sublist(list_t *head);
-static list_t *merge_lists(list_t *head1, list_t *head2);
 static void on_fortune_error(db_query_param_t *param, const char *error_string);
 static result_return_t on_fortune_result(db_query_param_t *param, PGresult *result);
 static uintmax_t on_fortune_section(mustache_api_t *api,
@@ -109,7 +107,6 @@ static uintmax_t read_template(mustache_api_t *api,
                                void *userdata,
                                char *buffer,
                                uintmax_t buffer_size);
-static list_t *sort_fortunes(list_t *head);
 static void template_error(mustache_api_t *api,
                            void *userdata,
                            uintmax_t lineno,
@@ -229,52 +226,6 @@ static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
 	return 0;
 }
 
-static list_t *get_sorted_sublist(list_t *head)
-{
-	list_t *tail = head;
-
-	if (head) {
-		head = head->next;
-
-		while (head && compare_fortunes(tail, head) <= 0) {
-			tail = head;
-			head = head->next;
-		}
-	}
-
-	return tail;
-}
-
-static list_t *merge_lists(list_t *head1, list_t *head2)
-{
-	list_t *ret = NULL;
-	list_t **current = &ret;
-
-	while (1) {
-		if (!head1) {
-			*current = head2;
-			break;
-		}
-		else if (!head2) {
-			*current = head1;
-			break;
-		}
-		// Checking for equality makes this algorithm a stable sort.
-		else if (compare_fortunes(head1, head2) <= 0) {
-			*current = head1;
-			current = &head1->next;
-			head1 = head1->next;
-		}
-		else {
-			*current = head2;
-			current = &head2->next;
-			head2 = head2->next;
-		}
-	}
-
-	return ret;
-}
-
 static void on_fortune_error(db_query_param_t *param, const char *error_string)
 {
 	fortune_ctx_t * const fortune_ctx = H2O_STRUCT_FROM_MEMBER(fortune_ctx_t, param, param);
@@ -335,7 +286,7 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 		memset(iovec_list, 0, offsetof(iovec_list_t, iov));
 		iovec_list->max_iovcnt = iovcnt;
 		fortune_ctx->iovec_list_iter = iovec_list;
-		fortune_ctx->result = sort_fortunes(fortune_ctx->result);
+		fortune_ctx->result = sort_list(fortune_ctx->result, compare_fortunes);
 
 		if (mustache_render(&api,
 		                    fortune_ctx,
@@ -463,37 +414,6 @@ static uintmax_t read_template(mustache_api_t *api,
 	return fread(buffer, sizeof(*buffer), buffer_size, template_input->input);
 }
 
-// merge sort
-static list_t *sort_fortunes(list_t *head)
-{
-	list_t **new_head;
-
-	do {
-		new_head = &head;
-
-		for (list_t *iter = head; iter;) {
-			list_t * const tail1 = get_sorted_sublist(iter);
-			list_t * const head2 = tail1->next;
-
-			if (!head2) {
-				*new_head = iter;
-				break;
-			}
-
-			list_t * const tail2 = get_sorted_sublist(head2);
-			list_t * const head1 = iter;
-
-			iter = tail2->next;
-			tail1->next = NULL;
-			tail2->next = NULL;
-			*new_head = merge_lists(head1, head2);
-			new_head = tail1->next ? &tail2->next : &tail1->next;
-		}
-	} while (new_head != &head);
-
-	return head;
-}
-
 static void template_error(mustache_api_t *api,
                            void *userdata,
                            uintmax_t lineno,

+ 84 - 0
frameworks/C/h2o/src/utility.c

@@ -35,6 +35,59 @@
 
 #define DEFAULT_CACHE_LINE_SIZE 128
 
+static list_t *get_sorted_sublist(list_t *head, int (*compare)(const list_t *, const list_t *));
+static list_t *merge_lists(list_t *head1,
+                           list_t *head2,
+                           int (*compare)(const list_t *, const list_t *));
+
+static list_t *get_sorted_sublist(list_t *head, int (*compare)(const list_t *, const list_t *))
+{
+	list_t *tail = head;
+
+	if (head) {
+		head = head->next;
+
+		while (head && compare(tail, head) <= 0) {
+			tail = head;
+			head = head->next;
+		}
+	}
+
+	return tail;
+}
+
+static list_t *merge_lists(list_t *head1,
+                           list_t *head2,
+                           int (*compare)(const list_t *, const list_t *))
+{
+	list_t *ret = NULL;
+	list_t **current = &ret;
+
+	while (1) {
+		if (!head1) {
+			*current = head2;
+			break;
+		}
+		else if (!head2) {
+			*current = head1;
+			break;
+		}
+		// Checking for equality makes this algorithm a stable sort.
+		else if (compare(head1, head2) <= 0) {
+			*current = head1;
+			current = &head1->next;
+			head1 = head1->next;
+		}
+		else {
+			*current = head2;
+			current = &head2->next;
+			head2 = head2->next;
+		}
+	}
+
+	return ret;
+}
+
 void free_json_generator(json_generator_t *gen, list_t **pool, size_t *gen_num, size_t max_gen)
 {
 	if (gen) {
@@ -175,6 +228,37 @@ bool is_power_of_2(size_t x)
 	return !!x & !(x & (x - 1));
 }
 
+// merge sort
+list_t *sort_list(list_t *head, int (*compare)(const list_t *, const list_t *))
+{
+	list_t **new_head;
+
+	do {
+		new_head = &head;
+
+		for (list_t *iter = head; iter;) {
+			list_t * const tail1 = get_sorted_sublist(iter, compare);
+			list_t * const head2 = tail1->next;
+
+			if (!head2) {
+				*new_head = iter;
+				break;
+			}
+
+			list_t * const tail2 = get_sorted_sublist(head2, compare);
+			list_t * const head1 = iter;
+
+			iter = tail2->next;
+			tail1->next = NULL;
+			tail2->next = NULL;
+			*new_head = merge_lists(head1, head2, compare);
+			new_head = tail1->next ? &tail2->next : &tail1->next;
+		}
+	} while (new_head != &head);
+
+	return head;
+}
+
 size_t round_up_to_power_of_2(size_t x)
 {
 	static_assert(sizeof(size_t) == sizeof(unsigned long),

+ 2 - 0
frameworks/C/h2o/src/utility.h

@@ -49,6 +49,8 @@ json_generator_t *get_json_generator(list_t **pool, size_t *gen_num);
 size_t get_maximum_cache_line_size(void);
 uint32_t get_random_number(uint32_t max_rand, unsigned int *seed);
 bool is_power_of_2(size_t x);
+// stable sort
+list_t *sort_list(list_t *head, int (*compare)(const list_t *, const list_t *));
 size_t round_up_to_power_of_2(size_t x);
 
 #endif // UTILITY_H_