Browse Source

H2O: Fix several minor issues (#2746)

* Reduce the peak memory usage caused by reusing JSON generators
in the multiple queries and database updates tests by not allocating
the generators in advance, but only when necessary.
* Make some additions to the server shutdown code that have been
missed when simultaneous support for HTTP and HTTPS has been
implemented.
* Set the Web server back in the framework metadata - the H2O project
the framework depends on provides two ways to use the Web server. One
of them is to run a standalone server (and use FastCGI, etc.), and
the other is to link to it as a library in the framework process.
Even though the implementation uses the second approach, IMHO setting
H2O as the Web server in the framework metadata is still the correct
thing to do because libh2o is used unmodified, and is pretty much
equivalent to running the standalone server (except for some details
around threads and sockets). The latter has much more functionality
as well, but it is not relevant to the benchmarks.
Anton Kirilov 8 years ago
parent
commit
5f9da52a1c

+ 1 - 1
frameworks/C/h2o/benchmark_config.json

@@ -18,7 +18,7 @@
       "flavor": "None",
       "orm": "Raw",
       "platform": "None",
-      "webserver": "None",
+      "webserver": "H2O",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "H2O",

+ 6 - 0
frameworks/C/h2o/src/event_loop.c

@@ -175,6 +175,9 @@ static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_
 	                                                                         h2o_receiver,
 	                                                                         receiver);
 
+	if (global_thread_data->ctx->event_loop.h2o_https_socket)
+		h2o_socket_read_stop(global_thread_data->ctx->event_loop.h2o_https_socket);
+
 	h2o_socket_read_stop(global_thread_data->ctx->event_loop.h2o_socket);
 }
 
@@ -190,6 +193,9 @@ static void shutdown_server(h2o_socket_t *listener, const char *err)
 		ctx->global_data->shutdown = true;
 		h2o_socket_read_stop(ctx->event_loop.h2o_socket);
 
+		if (ctx->event_loop.h2o_https_socket)
+			h2o_socket_read_stop(ctx->event_loop.h2o_https_socket);
+
 		for (size_t i = ctx->config->thread_num - 1; i > 0; i--)
 			h2o_multithread_send_message(&ctx->global_thread_data[i].h2o_receiver, NULL);
 	}

+ 32 - 40
frameworks/C/h2o/src/world.c

@@ -68,13 +68,14 @@ typedef struct {
 } single_query_ctx_t;
 
 struct multiple_query_ctx_t {
-	json_generator_t *gen; // also an error flag
+	json_generator_t *gen;
 	h2o_req_t *req;
 	query_param_t *query_param;
 	size_t num_query;
 	size_t num_query_in_progress;
 	size_t num_result;
 	bool do_update;
+	bool error;
 	query_result_t res[];
 };
 
@@ -184,18 +185,13 @@ static int do_multiple_queries(bool do_update, h2o_req_t *req)
 
 			if (execute_query(ctx, &query_ctx->query_param[i].param)) {
 				query_ctx->num_query_in_progress = i;
+				query_ctx->error = true;
 				send_service_unavailable_error(DB_REQ_ERROR, req);
 				return 0;
 			}
 
 			h2o_mem_addref_shared(query_ctx);
 		}
-
-		// Create a JSON generator while the queries are processed.
-		query_ctx->gen = get_json_generator(&ctx->json_generator, &ctx->json_generator_num);
-
-		if (!query_ctx->gen)
-			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	}
 	else
 		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
@@ -312,16 +308,8 @@ static void on_multiple_query_error(db_query_param_t *param, const char *error_s
 	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 
-	if (query_ctx->gen) {
-		thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
-		                                                      event_loop.h2o_ctx,
-		                                                      query_ctx->req->conn->ctx);
-
-		free_json_generator(query_ctx->gen,
-		                    &ctx->json_generator,
-		                    &ctx->json_generator_num,
-		                    ctx->config->max_json_generator);
-		query_ctx->gen = NULL;
+	if (!query_ctx->error) {
+		query_ctx->error = true;
 		send_error(BAD_GATEWAY, error_string, query_ctx->req);
 	}
 
@@ -334,7 +322,7 @@ static result_return_t on_multiple_query_result(db_query_param_t *param, PGresul
 	query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 
-	if (query_ctx->gen && PQresultStatus(result) == PGRES_TUPLES_OK) {
+	if (!query_ctx->error && PQresultStatus(result) == PGRES_TUPLES_OK) {
 		thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
 		                                                      event_loop.h2o_ctx,
 		                                                      query_ctx->req->conn->ctx);
@@ -356,27 +344,29 @@ static result_return_t on_multiple_query_result(db_query_param_t *param, PGresul
 				return DONE;
 			}
 
-			free_json_generator(query_ctx->gen,
-			                    &ctx->json_generator,
-			                    &ctx->json_generator_num,
-			                    ctx->config->max_json_generator);
-			query_ctx->gen = NULL;
+			query_ctx->error = true;
 			send_service_unavailable_error(DB_REQ_ERROR, query_ctx->req);
 		}
 		else if (query_ctx->num_result == query_ctx->num_query) {
 			if (query_ctx->do_update)
 				do_updates(query_ctx);
-			else
-				serialize_items(query_ctx->res,
-				                query_ctx->num_result,
-				                &query_ctx->gen,
-				                query_ctx->req);
+			else {
+				query_ctx->gen = get_json_generator(&ctx->json_generator, &ctx->json_generator_num);
+
+				if (query_ctx->gen)
+					serialize_items(query_ctx->res,
+					                query_ctx->num_result,
+					                &query_ctx->gen,
+					                query_ctx->req);
+				else
+					send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, query_ctx->req);
+			}
 		}
 
 		h2o_mem_release_shared(query_ctx);
 	}
 	else {
-		if (query_ctx->gen)
+		if (!query_ctx->error)
 			LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result));
 
 		on_multiple_query_error(param, DB_ERROR);
@@ -391,16 +381,8 @@ static void on_multiple_query_timeout(db_query_param_t *param)
 	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 
-	if (query_ctx->gen) {
-		thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
-		                                                      event_loop.h2o_ctx,
-		                                                      query_ctx->req->conn->ctx);
-
-		free_json_generator(query_ctx->gen,
-		                    &ctx->json_generator,
-		                    &ctx->json_generator_num,
-		                    ctx->config->max_json_generator);
-		query_ctx->gen = NULL;
+	if (!query_ctx->error) {
+		query_ctx->error = true;
 		send_error(GATEWAY_TIMEOUT, DB_TIMEOUT_ERROR, query_ctx->req);
 	}
 
@@ -472,8 +454,18 @@ static result_return_t on_update_result(db_query_param_t *param, PGresult *resul
 	multiple_query_ctx_t * const query_ctx = query_param->ctx;
 
 	if (PQresultStatus(result) == PGRES_COMMAND_OK) {
+		thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
+		                                                      event_loop.h2o_ctx,
+		                                                      query_ctx->req->conn->ctx);
+
 		query_ctx->num_query_in_progress--;
-		serialize_items(query_ctx->res, query_ctx->num_result, &query_ctx->gen, query_ctx->req);
+		query_ctx->gen = get_json_generator(&ctx->json_generator, &ctx->json_generator_num);
+
+		if (query_ctx->gen)
+			serialize_items(query_ctx->res, query_ctx->num_result, &query_ctx->gen, query_ctx->req);
+		else
+			send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, query_ctx->req);
+
 		h2o_mem_release_shared(query_ctx);
 	}
 	else {