Browse Source

H2O: Further code clean-up (#4680)

* H2O: Further code clean-up

The purpose of this commit is to introduce a clear separation
between generic code and the test implementations.

* H2O: Move the test implementations to a separate directory
Anton Kirilov 6 years ago
parent
commit
a8432f24e8

+ 1 - 1
frameworks/C/h2o/CMakeLists.txt

@@ -13,7 +13,7 @@ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
 set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3")
 set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3")
 add_definitions(-DH2O_USE_LIBUV=0)
 add_definitions(-DH2O_USE_LIBUV=0)
 include_directories(src ${H2O_INCLUDE} ${MUSTACHE_C_INCLUDE} ${YAJL_INCLUDE})
 include_directories(src ${H2O_INCLUDE} ${MUSTACHE_C_INCLUDE} ${YAJL_INCLUDE})
-file(GLOB SOURCES "src/*.c")
+file(GLOB_RECURSE SOURCES "src/*.c")
 add_executable(${PROJECT_NAME} ${SOURCES})
 add_executable(${PROJECT_NAME} ${SOURCES})
 target_link_libraries(${PROJECT_NAME} ${COMMON_OPTIONS})
 target_link_libraries(${PROJECT_NAME} ${COMMON_OPTIONS})
 target_link_libraries(${PROJECT_NAME} ${H2O_LIB} ssl crypto numa pq z ${MUSTACHE_C_LIB} ${YAJL_LIB})
 target_link_libraries(${PROJECT_NAME} ${H2O_LIB} ssl crypto numa pq z ${MUSTACHE_C_LIB} ${YAJL_LIB})

+ 55 - 35
frameworks/C/h2o/src/database.c

@@ -28,18 +28,23 @@
 #include "error.h"
 #include "error.h"
 #include "list.h"
 #include "list.h"
 #include "thread.h"
 #include "thread.h"
-#include "utility.h"
 
 
 #define IS_RESETTING 1
 #define IS_RESETTING 1
 #define IS_WRITING 2
 #define IS_WRITING 2
 
 
+typedef struct {
+	list_t l;
+	const char *name;
+	const char *query;
+} prepared_statement_t;
+
 typedef struct {
 typedef struct {
 	list_t l;
 	list_t l;
 	PGconn *conn;
 	PGconn *conn;
 	thread_context_t *ctx;
 	thread_context_t *ctx;
 	db_query_param_t *param;
 	db_query_param_t *param;
+	list_t *prepared_statement;
 	h2o_socket_t *sock;
 	h2o_socket_t *sock;
-	size_t prep_stmt_idx;
 	uint_fast32_t flags;
 	uint_fast32_t flags;
 	h2o_timeout_entry_t h2o_timeout_entry;
 	h2o_timeout_entry_t h2o_timeout_entry;
 } db_conn_t;
 } db_conn_t;
@@ -57,14 +62,6 @@ static void poll_database_connection(h2o_socket_t *db_sock, const char *err);
 static void process_query(db_conn_t *db_conn);
 static void process_query(db_conn_t *db_conn);
 static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn);
 static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn);
 
 
-static const struct {
-	const char *name;
-	const char *query;
-} prepared_statement[] = {
-	{FORTUNE_TABLE_NAME, "SELECT * FROM " FORTUNE_TABLE_NAME ";"},
-	{WORLD_TABLE_NAME, "SELECT * FROM " WORLD_TABLE_NAME " WHERE " ID_FIELD_NAME " = $1::integer;"},
-};
-
 static int do_database_write(db_conn_t *db_conn)
 static int do_database_write(db_conn_t *db_conn)
 {
 {
 	assert(db_conn->param);
 	assert(db_conn->param);
@@ -182,7 +179,7 @@ static void on_database_connect_timeout(h2o_timeout_entry_t *entry)
 
 
 static void on_database_error(db_conn_t *db_conn, const char *error_string)
 static void on_database_error(db_conn_t *db_conn, const char *error_string)
 {
 {
-	if (db_conn->prep_stmt_idx < ARRAY_SIZE(prepared_statement))
+	if (db_conn->prepared_statement)
 		on_database_connect_error(db_conn, false, error_string);
 		on_database_connect_error(db_conn, false, error_string);
 	else {
 	else {
 		if (db_conn->param) {
 		if (db_conn->param) {
@@ -282,22 +279,18 @@ static void on_database_write_ready(h2o_socket_t *db_sock, const char *err)
 		on_database_error(db_conn, DB_ERROR);
 		on_database_error(db_conn, DB_ERROR);
 	}
 	}
 	else {
 	else {
-		if (db_conn->prep_stmt_idx) {
-			const int send_status = PQflush(db_conn->conn);
+		const int send_status = PQflush(db_conn->conn);
 
 
-			if (!send_status) {
-				if (db_conn->flags & IS_WRITING && db_conn->param)
-					do_database_write(db_conn);
-			}
-			else if (send_status < 0) {
-				LIBRARY_ERROR("PQflush", PQerrorMessage(db_conn->conn));
-				on_database_error(db_conn, DB_ERROR);
-			}
-			else
-				h2o_socket_notify_write(db_conn->sock, on_database_write_ready);
+		if (!send_status) {
+			if (db_conn->flags & IS_WRITING && db_conn->param)
+				do_database_write(db_conn);
+		}
+		else if (send_status < 0) {
+			LIBRARY_ERROR("PQflush", PQerrorMessage(db_conn->conn));
+			on_database_error(db_conn, DB_ERROR);
 		}
 		}
 		else
 		else
-			poll_database_connection(db_conn->sock, NULL);
+			h2o_socket_notify_write(db_conn->sock, on_database_write_ready);
 	}
 	}
 }
 }
 
 
@@ -315,8 +308,9 @@ static void poll_database_connection(h2o_socket_t *db_sock, const char *err)
 		switch (status) {
 		switch (status) {
 			case PGRES_POLLING_WRITING:
 			case PGRES_POLLING_WRITING:
 				if (!h2o_socket_is_writing(db_conn->sock))
 				if (!h2o_socket_is_writing(db_conn->sock))
-					h2o_socket_notify_write(db_conn->sock, on_database_write_ready);
+					h2o_socket_notify_write(db_conn->sock, poll_database_connection);
 
 
+				h2o_socket_read_stop(db_conn->sock);
 				return;
 				return;
 			case PGRES_POLLING_OK:
 			case PGRES_POLLING_OK:
 				if (PQsetnonblocking(db_conn->conn, 1)) {
 				if (PQsetnonblocking(db_conn->conn, 1)) {
@@ -329,6 +323,7 @@ static void poll_database_connection(h2o_socket_t *db_sock, const char *err)
 				process_query(db_conn);
 				process_query(db_conn);
 				return;
 				return;
 			case PGRES_POLLING_READING:
 			case PGRES_POLLING_READING:
+				h2o_socket_read_start(db_conn->sock, poll_database_connection);
 				return;
 				return;
 			default:
 			default:
 				ERROR(PQerrorMessage(db_conn->conn));
 				ERROR(PQerrorMessage(db_conn->conn));
@@ -340,13 +335,13 @@ static void poll_database_connection(h2o_socket_t *db_sock, const char *err)
 
 
 static void process_query(db_conn_t *db_conn)
 static void process_query(db_conn_t *db_conn)
 {
 {
-	if (db_conn->prep_stmt_idx < ARRAY_SIZE(prepared_statement)) {
-		if (PQsendPrepare(db_conn->conn,
-		                  prepared_statement[db_conn->prep_stmt_idx].name,
-		                  prepared_statement[db_conn->prep_stmt_idx].query,
-		                  0,
-		                  NULL)) {
-			db_conn->prep_stmt_idx++;
+	if (db_conn->prepared_statement) {
+		const prepared_statement_t * const p = H2O_STRUCT_FROM_MEMBER(prepared_statement_t,
+		                                                              l,
+		                                                              db_conn->prepared_statement);
+
+		if (PQsendPrepare(db_conn->conn, p->name, p->query, 0, NULL)) {
+			db_conn->prepared_statement = p->l.next;
 			db_conn->h2o_timeout_entry.cb = on_database_connect_timeout;
 			db_conn->h2o_timeout_entry.cb = on_database_connect_timeout;
 			h2o_timeout_link(db_conn->ctx->event_loop.h2o_ctx.loop,
 			h2o_timeout_link(db_conn->ctx->event_loop.h2o_ctx.loop,
 			                 &db_conn->ctx->db_state.h2o_timeout,
 			                 &db_conn->ctx->db_state.h2o_timeout,
@@ -383,7 +378,6 @@ static void process_query(db_conn_t *db_conn)
 static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 {
 {
 	if (db_conn) {
 	if (db_conn) {
-		db_conn->prep_stmt_idx = 0;
 		db_conn->flags = IS_RESETTING;
 		db_conn->flags = IS_RESETTING;
 		h2o_timeout_unlink(&db_conn->h2o_timeout_entry);
 		h2o_timeout_unlink(&db_conn->h2o_timeout_entry);
 		h2o_socket_read_stop(db_conn->sock);
 		h2o_socket_read_stop(db_conn->sock);
@@ -441,11 +435,11 @@ static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
 		db_conn->sock->data = db_conn;
 		db_conn->sock->data = db_conn;
 		db_conn->ctx = ctx;
 		db_conn->ctx = ctx;
 		db_conn->h2o_timeout_entry.cb = on_database_connect_timeout;
 		db_conn->h2o_timeout_entry.cb = on_database_connect_timeout;
+		db_conn->prepared_statement = ctx->global_data->prepared_statements;
 		h2o_timeout_link(ctx->event_loop.h2o_ctx.loop,
 		h2o_timeout_link(ctx->event_loop.h2o_ctx.loop,
 		                 &ctx->db_state.h2o_timeout,
 		                 &ctx->db_state.h2o_timeout,
 		                 &db_conn->h2o_timeout_entry);
 		                 &db_conn->h2o_timeout_entry);
-		h2o_socket_read_start(db_conn->sock, poll_database_connection);
-		h2o_socket_notify_write(db_conn->sock, on_database_write_ready);
+		h2o_socket_notify_write(db_conn->sock, poll_database_connection);
 		return;
 		return;
 	}
 	}
 
 
@@ -461,6 +455,19 @@ error:
 	error_notification(ctx, false, DB_ERROR);
 	error_notification(ctx, false, DB_ERROR);
 }
 }
 
 
+void add_prepared_statement(const char *name, const char *query, list_t **prepared_statements)
+{
+	prepared_statement_t * const p = calloc(1, sizeof(*p));
+
+	if (!p)
+		abort();
+
+	p->l.next = *prepared_statements;
+	p->name = name;
+	p->query = query;
+	*prepared_statements = &p->l;
+}
+
 int execute_query(thread_context_t *ctx, db_query_param_t *param)
 int execute_query(thread_context_t *ctx, db_query_param_t *param)
 {
 {
 	int ret = EXIT_FAILURE;
 	int ret = EXIT_FAILURE;
@@ -515,3 +522,16 @@ void initialize_database_state(h2o_loop_t *loop, db_state_t *db_state)
 	db_state->queries.tail = &db_state->queries.head;
 	db_state->queries.tail = &db_state->queries.head;
 	h2o_timeout_init(loop, &db_state->h2o_timeout, H2O_DEFAULT_HTTP1_REQ_TIMEOUT);
 	h2o_timeout_init(loop, &db_state->h2o_timeout, H2O_DEFAULT_HTTP1_REQ_TIMEOUT);
 }
 }
+
+void remove_prepared_statements(list_t *prepared_statements)
+{
+	if (prepared_statements)
+		do {
+			prepared_statement_t * const p = H2O_STRUCT_FROM_MEMBER(prepared_statement_t,
+			                                                        l,
+			                                                        prepared_statements);
+
+			prepared_statements = prepared_statements->next;
+			free(p);
+		} while (prepared_statements);
+}

+ 3 - 18
frameworks/C/h2o/src/database.h

@@ -26,31 +26,14 @@
 #include <stdint.h>
 #include <stdint.h>
 #include <postgresql/libpq-fe.h>
 #include <postgresql/libpq-fe.h>
 
 
+#include "global_data.h"
 #include "list.h"
 #include "list.h"
-#include "utility.h"
 
 
 #define DB_ERROR "database error\n"
 #define DB_ERROR "database error\n"
 #define DB_REQ_ERROR "too many concurrent database requests\n"
 #define DB_REQ_ERROR "too many concurrent database requests\n"
 #define DB_TIMEOUT_ERROR "database timeout\n"
 #define DB_TIMEOUT_ERROR "database timeout\n"
-#define FORTUNE_TABLE_NAME "Fortune"
-#define ID_FIELD_NAME "id"
 #define IS_PREPARED 1
 #define IS_PREPARED 1
 #define IS_SINGLE_ROW 2
 #define IS_SINGLE_ROW 2
-#define MAX_ID 10000
-#define MESSAGE_FIELD_NAME "message"
-#define WORLD_TABLE_NAME "World"
-
-#define UPDATE_QUERY_BEGIN \
-	"UPDATE " WORLD_TABLE_NAME " SET randomNumber = v.randomNumber " \
-	"FROM (VALUES(%" PRIu32 ", %" PRIu32 ")"
-
-#define UPDATE_QUERY_ELEM ", (%" PRIu32 ", %" PRIu32 ")"
-#define UPDATE_QUERY_END ") AS v (id, randomNumber) WHERE " WORLD_TABLE_NAME ".id = v.id;"
-
-#define MAX_UPDATE_QUERY_LEN(n) \
-	(sizeof(UPDATE_QUERY_BEGIN) + sizeof(UPDATE_QUERY_END) - sizeof(UPDATE_QUERY_ELEM) + \
-	 (n) * (sizeof(UPDATE_QUERY_ELEM) - 1 + \
-	        2 * (sizeof(MKSTR(MAX_ID)) - 1) - 2 * (sizeof(PRIu32) - 1) - 2))
 
 
 typedef enum {
 typedef enum {
 	SUCCESS,
 	SUCCESS,
@@ -90,8 +73,10 @@ typedef struct {
 	h2o_timeout_t h2o_timeout;
 	h2o_timeout_t h2o_timeout;
 } db_state_t;
 } db_state_t;
 
 
+void add_prepared_statement(const char *name, const char *query, list_t **prepared_statements);
 int execute_query(thread_context_t *ctx, db_query_param_t *param);
 int execute_query(thread_context_t *ctx, db_query_param_t *param);
 void free_database_state(h2o_loop_t *loop, db_state_t *db_state);
 void free_database_state(h2o_loop_t *loop, db_state_t *db_state);
 void initialize_database_state(h2o_loop_t *loop, db_state_t *db_state);
 void initialize_database_state(h2o_loop_t *loop, db_state_t *db_state);
+void remove_prepared_statements(list_t *prepared_statements);
 
 
 #endif // DATABASE_H_
 #endif // DATABASE_H_

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

@@ -37,6 +37,7 @@
 
 
 #include "error.h"
 #include "error.h"
 #include "event_loop.h"
 #include "event_loop.h"
+#include "global_data.h"
 #include "thread.h"
 #include "thread.h"
 #include "utility.h"
 #include "utility.h"
 
 

+ 1 - 1
frameworks/C/h2o/src/event_loop.h

@@ -24,7 +24,7 @@
 #include <h2o.h>
 #include <h2o.h>
 #include <stdbool.h>
 #include <stdbool.h>
 
 
-#include "utility.h"
+#include "global_data.h"
 
 
 typedef struct thread_context_t thread_context_t;
 typedef struct thread_context_t thread_context_t;
 
 

+ 66 - 0
frameworks/C/h2o/src/global_data.h

@@ -0,0 +1,66 @@
+/*
+ Copyright (c) 2019 Anton Valentinov Kirilov
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+ associated documentation files (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef GLOBAL_DATA_H_
+
+#define GLOBAL_DATA_H_
+
+#include <h2o.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <h2o/cache.h>
+#include <openssl/ssl.h>
+
+#include "cache.h"
+#include "list.h"
+#include "handlers/request_handler_data.h"
+
+typedef struct global_thread_data_t global_thread_data_t;
+
+typedef struct {
+	const char *bind_address;
+	const char *cert;
+	const char *db_host;
+	const char *key;
+	const char *log;
+	const char *root;
+	const char *template_path;
+	size_t max_accept;
+	size_t max_db_conn_num;
+	size_t max_json_generator;
+	size_t max_query_num;
+	size_t thread_num;
+	uint16_t https_port;
+	uint16_t port;
+} config_t;
+
+typedef struct {
+	h2o_logger_t *file_logger;
+	global_thread_data_t *global_thread_data;
+	list_t *prepared_statements;
+	h2o_socket_t *signals;
+	SSL_CTX *ssl_ctx;
+	size_t memory_alignment;
+	int signal_fd;
+	bool shutdown;
+	h2o_globalconf_t h2o_config;
+	request_handler_data_t request_handler_data;
+} global_data_t;
+
+#endif // GLOBAL_DATA_H_

+ 183 - 31
frameworks/C/h2o/src/fortune.c → frameworks/C/h2o/src/handlers/fortune.c

@@ -19,25 +19,39 @@
 
 
 #include <assert.h>
 #include <assert.h>
 #include <ctype.h>
 #include <ctype.h>
+#include <errno.h>
 #include <h2o.h>
 #include <h2o.h>
 #include <mustache.h>
 #include <mustache.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <postgresql/libpq-fe.h>
 #include <postgresql/libpq-fe.h>
+#include <string.h>
 
 
 #include "database.h"
 #include "database.h"
 #include "error.h"
 #include "error.h"
 #include "fortune.h"
 #include "fortune.h"
+#include "global_data.h"
 #include "list.h"
 #include "list.h"
 #include "request_handler.h"
 #include "request_handler.h"
 #include "thread.h"
 #include "thread.h"
 #include "utility.h"
 #include "utility.h"
 
 
+#define ID_FIELD_NAME "id"
+#define FORTUNE_TABLE_NAME "Fortune"
 #define MAX_IOVEC 64
 #define MAX_IOVEC 64
+#define MESSAGE_FIELD_NAME "message"
 #define NEW_FORTUNE_ID "0"
 #define NEW_FORTUNE_ID "0"
 #define NEW_FORTUNE_MESSAGE "Additional fortune added at request time."
 #define NEW_FORTUNE_MESSAGE "Additional fortune added at request time."
+#define TEMPLATE_PATH_SUFFIX "/fortunes.mustache"
+
+typedef struct {
+	list_t l;
+	h2o_iovec_t id;
+	h2o_iovec_t message;
+} fortune_t;
 
 
 typedef struct {
 typedef struct {
 	list_t l;
 	list_t l;
@@ -60,6 +74,11 @@ typedef struct {
 	h2o_generator_t generator;
 	h2o_generator_t generator;
 } fortune_ctx_t;
 } fortune_ctx_t;
 
 
+typedef struct {
+	FILE *input;
+	const char *name;
+} template_input_t;
+
 static uintmax_t add_iovec(mustache_api_t *api,
 static uintmax_t add_iovec(mustache_api_t *api,
                            void *userdata,
                            void *userdata,
                            const char *buffer,
                            const char *buffer,
@@ -68,6 +87,7 @@ static void cleanup_fortunes(fortune_ctx_t *fortune_ctx);
 static void cleanup_request(void *data);
 static void cleanup_request(void *data);
 static int compare_fortunes(const list_t *x, const list_t *y);
 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 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 *get_sorted_sublist(list_t *head);
 static list_t *merge_lists(list_t *head1, list_t *head2);
 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 void on_fortune_error(db_query_param_t *param, const char *error_string);
@@ -79,7 +99,21 @@ static void on_fortune_timeout(db_query_param_t *param);
 static uintmax_t on_fortune_variable(mustache_api_t *api,
 static uintmax_t on_fortune_variable(mustache_api_t *api,
                                      void *userdata,
                                      void *userdata,
                                      mustache_token_variable_t *token);
                                      mustache_token_variable_t *token);
+static uintmax_t prerender_section(mustache_api_t *api,
+                                   void *userdata,
+                                   mustache_token_section_t *token);
+static uintmax_t prerender_variable(mustache_api_t *api,
+                                    void *userdata,
+                                    mustache_token_variable_t *token);
+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 list_t *sort_fortunes(list_t *head);
+static void template_error(mustache_api_t *api,
+                           void *userdata,
+                           uintmax_t lineno,
+                           const char *error);
 
 
 static uintmax_t add_iovec(mustache_api_t *api,
 static uintmax_t add_iovec(mustache_api_t *api,
                            void *userdata,
                            void *userdata,
@@ -155,6 +189,46 @@ static void complete_fortunes(struct st_h2o_generator_t *self, h2o_req_t *req)
 	h2o_send(req, iovec_list->iov, iovec_list->iovcnt, state);
 	h2o_send(req, iovec_list->iov, iovec_list->iovcnt, state);
 }
 }
 
 
+static int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
+{
+	IGNORE_FUNCTION_PARAMETER(self);
+
+	thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
+	                                                      event_loop.h2o_ctx,
+	                                                      req->conn->ctx);
+	fortune_ctx_t * const fortune_ctx = calloc(1, sizeof(*fortune_ctx));
+
+	if (fortune_ctx) {
+		fortune_t * const fortune = h2o_mem_alloc_pool(&req->pool, sizeof(*fortune));
+		fortune_ctx_t ** const p = h2o_mem_alloc_shared(&req->pool, sizeof(*p), cleanup_request);
+
+		*p = fortune_ctx;
+		memset(fortune, 0, sizeof(*fortune));
+		fortune->id.base = NEW_FORTUNE_ID;
+		fortune->id.len = sizeof(NEW_FORTUNE_ID) - 1;
+		fortune->message.base = NEW_FORTUNE_MESSAGE;
+		fortune->message.len = sizeof(NEW_FORTUNE_MESSAGE) - 1;
+		fortune_ctx->generator.proceed = complete_fortunes;
+		fortune_ctx->num_result = 1;
+		fortune_ctx->param.command = FORTUNE_TABLE_NAME;
+		fortune_ctx->param.on_error = on_fortune_error;
+		fortune_ctx->param.on_result = on_fortune_result;
+		fortune_ctx->param.on_timeout = on_fortune_timeout;
+		fortune_ctx->param.flags = IS_PREPARED;
+		fortune_ctx->req = req;
+		fortune_ctx->result = &fortune->l;
+
+		if (execute_query(ctx, &fortune_ctx->param)) {
+			fortune_ctx->cleanup = true;
+			send_service_unavailable_error(DB_REQ_ERROR, req);
+		}
+	}
+	else
+		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
+
+	return 0;
+}
+
 static list_t *get_sorted_sublist(list_t *head)
 static list_t *get_sorted_sublist(list_t *head)
 {
 {
 	list_t *tail = head;
 	list_t *tail = head;
@@ -263,7 +337,9 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
 		fortune_ctx->iovec_list_iter = iovec_list;
 		fortune_ctx->iovec_list_iter = iovec_list;
 		fortune_ctx->result = sort_fortunes(fortune_ctx->result);
 		fortune_ctx->result = sort_fortunes(fortune_ctx->result);
 
 
-		if (mustache_render(&api, fortune_ctx, ctx->global_data->fortunes_template)) {
+		if (mustache_render(&api,
+		                    fortune_ctx,
+		                    ctx->global_data->request_handler_data.fortunes_template)) {
 			fortune_ctx->iovec_list = iovec_list->l.next;
 			fortune_ctx->iovec_list = iovec_list->l.next;
 			set_default_response_param(HTML, fortune_ctx->content_length, fortune_ctx->req);
 			set_default_response_param(HTML, fortune_ctx->content_length, fortune_ctx->req);
 			h2o_start_response(fortune_ctx->req, &fortune_ctx->generator);
 			h2o_start_response(fortune_ctx->req, &fortune_ctx->generator);
@@ -334,6 +410,59 @@ static uintmax_t on_fortune_variable(mustache_api_t *api,
 	return add_iovec(api, fortune_ctx, iovec->base, iovec->len);
 	return add_iovec(api, fortune_ctx, iovec->base, iovec->len);
 }
 }
 
 
+static uintmax_t prerender_section(mustache_api_t *api,
+                                   void *userdata,
+                                   mustache_token_section_t *token)
+{
+	bool * const in_section = userdata;
+	uintmax_t ret = 0;
+
+	if (!*in_section && !strcmp(token->name, FORTUNE_TABLE_NAME)) {
+		*in_section = true;
+		ret = mustache_prerender(api, userdata, token->section);
+		*in_section = false;
+	}
+
+	return ret;
+}
+
+static uintmax_t prerender_variable(mustache_api_t *api,
+                                    void *userdata,
+                                    mustache_token_variable_t *token)
+{
+	IGNORE_FUNCTION_PARAMETER(api);
+
+	bool * const in_section = userdata;
+	uintmax_t ret = 0;
+
+	if (*in_section) {
+		if (token->text_length == sizeof(ID_FIELD_NAME) - 1 &&
+		    !memcmp(token->text, ID_FIELD_NAME, sizeof(ID_FIELD_NAME) - 1)) {
+			token->userdata = (void *) offsetof(fortune_t, id);
+			ret = 1;
+		}
+		else if (token->text_length == sizeof(MESSAGE_FIELD_NAME) - 1 &&
+		         !memcmp(token->text, MESSAGE_FIELD_NAME, sizeof(MESSAGE_FIELD_NAME) - 1)) {
+			token->userdata = (void *) offsetof(fortune_t, message);
+			ret = 1;
+		}
+	}
+
+	return ret;
+}
+
+static uintmax_t read_template(mustache_api_t *api,
+                               void *userdata,
+                               char *buffer,
+                               uintmax_t buffer_size)
+{
+	IGNORE_FUNCTION_PARAMETER(api);
+
+	const template_input_t * const template_input = userdata;
+
+	return fread(buffer, sizeof(*buffer), buffer_size, template_input->input);
+}
+
 // merge sort
 // merge sort
 static list_t *sort_fortunes(list_t *head)
 static list_t *sort_fortunes(list_t *head)
 {
 {
@@ -365,42 +494,65 @@ static list_t *sort_fortunes(list_t *head)
 	return head;
 	return head;
 }
 }
 
 
-int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
+static void template_error(mustache_api_t *api,
+                           void *userdata,
+                           uintmax_t lineno,
+                           const char *error)
 {
 {
-	IGNORE_FUNCTION_PARAMETER(self);
+	IGNORE_FUNCTION_PARAMETER(api);
 
 
-	thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
-	                                                      event_loop.h2o_ctx,
-	                                                      req->conn->ctx);
-	fortune_ctx_t * const fortune_ctx = calloc(1, sizeof(*fortune_ctx));
+	const template_input_t * const template_input = userdata;
 
 
-	if (fortune_ctx) {
-		fortune_t * const fortune = h2o_mem_alloc_pool(&req->pool, sizeof(*fortune));
-		fortune_ctx_t ** const p = h2o_mem_alloc_shared(&req->pool, sizeof(*p), cleanup_request);
+	print_error(template_input->name, lineno, "mustache_compile", error);
+}
 
 
-		*p = fortune_ctx;
-		memset(fortune, 0, sizeof(*fortune));
-		fortune->id.base = NEW_FORTUNE_ID;
-		fortune->id.len = sizeof(NEW_FORTUNE_ID) - 1;
-		fortune->message.base = NEW_FORTUNE_MESSAGE;
-		fortune->message.len = sizeof(NEW_FORTUNE_MESSAGE) - 1;
-		fortune_ctx->generator.proceed = complete_fortunes;
-		fortune_ctx->num_result = 1;
-		fortune_ctx->param.command = FORTUNE_TABLE_NAME;
-		fortune_ctx->param.on_error = on_fortune_error;
-		fortune_ctx->param.on_result = on_fortune_result;
-		fortune_ctx->param.on_timeout = on_fortune_timeout;
-		fortune_ctx->param.flags = IS_PREPARED;
-		fortune_ctx->req = req;
-		fortune_ctx->result = &fortune->l;
+void cleanup_fortunes_handler(global_data_t *global_data)
+{
+	if (global_data->request_handler_data.fortunes_template) {
+		mustache_api_t api = {.freedata = NULL};
 
 
-		if (execute_query(ctx, &fortune_ctx->param)) {
-			fortune_ctx->cleanup = true;
-			send_service_unavailable_error(DB_REQ_ERROR, req);
+		mustache_free(&api, global_data->request_handler_data.fortunes_template);
+	}
+}
+
+void initialize_fortunes_handler(const config_t *config,
+                                 global_data_t *global_data,
+                                 h2o_hostconf_t *hostconf,
+                                 h2o_access_log_filehandle_t *log_handle)
+{
+	mustache_template_t *template = NULL;
+	const size_t template_path_prefix_len = strlen(config->template_path);
+	char path[template_path_prefix_len + sizeof(TEMPLATE_PATH_SUFFIX)];
+
+	memcpy(path, config->template_path, template_path_prefix_len);
+	memcpy(path + template_path_prefix_len, TEMPLATE_PATH_SUFFIX, sizeof(TEMPLATE_PATH_SUFFIX));
+
+	template_input_t template_input = {.input = fopen(path, "rb"), .name = path};
+
+	if (template_input.input) {
+		mustache_api_t api = {.error = template_error,
+		                      .read = read_template,
+		                      .sectget = prerender_section,
+		                      .varget = prerender_variable};
+		bool in_section = false;
+
+		template = mustache_compile(&api, &template_input);
+
+		if (template && !mustache_prerender(&api, &in_section, template)) {
+			mustache_free(&api, template);
+			template = NULL;
 		}
 		}
+
+		fclose(template_input.input);
 	}
 	}
 	else
 	else
-		send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
-
-	return 0;
+		STANDARD_ERROR("fopen");
+
+	if (template) {
+		global_data->request_handler_data.fortunes_template = template;
+		add_prepared_statement(FORTUNE_TABLE_NAME,
+		                       "SELECT * FROM " FORTUNE_TABLE_NAME ";",
+		                       &global_data->prepared_statements);
+		register_request_handler("/fortunes", fortunes, hostconf, log_handle);
+	}
 }
 }

+ 6 - 8
frameworks/C/h2o/src/fortune.h → frameworks/C/h2o/src/handlers/fortune.h

@@ -23,14 +23,12 @@
 
 
 #include <h2o.h>
 #include <h2o.h>
 
 
-#include "list.h"
+#include "global_data.h"
 
 
-typedef struct {
-	list_t l;
-	h2o_iovec_t id;
-	h2o_iovec_t message;
-} fortune_t;
-
-int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req);
+void cleanup_fortunes_handler(global_data_t *global_data);
+void initialize_fortunes_handler(const config_t *config,
+                                 global_data_t *global_data,
+                                 h2o_hostconf_t *hostconf,
+                                 h2o_access_log_filehandle_t *log_handle);
 
 
 #endif // FORTUNE_H_
 #endif // FORTUNE_H_

+ 7 - 1
frameworks/C/h2o/src/json_serializer.c → frameworks/C/h2o/src/handlers/json_serializer.c

@@ -29,7 +29,7 @@
 #include "thread.h"
 #include "thread.h"
 #include "utility.h"
 #include "utility.h"
 
 
-int json_serializer(struct st_h2o_handler_t *self, h2o_req_t *req)
+static int json_serializer(struct st_h2o_handler_t *self, h2o_req_t *req)
 {
 {
 	IGNORE_FUNCTION_PARAMETER(self);
 	IGNORE_FUNCTION_PARAMETER(self);
 
 
@@ -66,3 +66,9 @@ error_yajl:
 	send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	return 0;
 	return 0;
 }
 }
+
+void initialize_json_serializer_handler(h2o_hostconf_t *hostconf,
+                                        h2o_access_log_filehandle_t *log_handle)
+{
+	register_request_handler("/json", json_serializer, hostconf, log_handle);
+}

+ 2 - 1
frameworks/C/h2o/src/json_serializer.h → frameworks/C/h2o/src/handlers/json_serializer.h

@@ -23,6 +23,7 @@
 
 
 #include <h2o.h>
 #include <h2o.h>
 
 
-int json_serializer(struct st_h2o_handler_t *self, h2o_req_t *req);
+void initialize_json_serializer_handler(h2o_hostconf_t *hostconf,
+                                        h2o_access_log_filehandle_t *log_handle);
 
 
 #endif // JSON_SERIALIZER_H_
 #endif // JSON_SERIALIZER_H_

+ 6 - 1
frameworks/C/h2o/src/plaintext.c → frameworks/C/h2o/src/handlers/plaintext.c

@@ -24,7 +24,7 @@
 #include "request_handler.h"
 #include "request_handler.h"
 #include "utility.h"
 #include "utility.h"
 
 
-int plaintext(struct st_h2o_handler_t *self, h2o_req_t *req)
+static int plaintext(struct st_h2o_handler_t *self, h2o_req_t *req)
 {
 {
 	IGNORE_FUNCTION_PARAMETER(self);
 	IGNORE_FUNCTION_PARAMETER(self);
 
 
@@ -37,3 +37,8 @@ int plaintext(struct st_h2o_handler_t *self, h2o_req_t *req)
 	h2o_send(req, &body, 1, H2O_SEND_STATE_FINAL);
 	h2o_send(req, &body, 1, H2O_SEND_STATE_FINAL);
 	return 0;
 	return 0;
 }
 }
+
+void initialize_plaintext_handler(h2o_hostconf_t *hostconf, h2o_access_log_filehandle_t *log_handle)
+{
+	register_request_handler("/plaintext", plaintext, hostconf, log_handle);
+}

+ 2 - 1
frameworks/C/h2o/src/plaintext.h → frameworks/C/h2o/src/handlers/plaintext.h

@@ -25,6 +25,7 @@
 
 
 #define HELLO_RESPONSE "Hello, World!"
 #define HELLO_RESPONSE "Hello, World!"
 
 
-int plaintext(struct st_h2o_handler_t *self, h2o_req_t *req);
+void initialize_plaintext_handler(h2o_hostconf_t *hostconf,
+                                  h2o_access_log_filehandle_t *log_handle);
 
 
 #endif // PLAINTEXT_H_
 #endif // PLAINTEXT_H_

+ 11 - 6
frameworks/C/h2o/src/template.h → frameworks/C/h2o/src/handlers/request_handler_data.h

@@ -1,5 +1,5 @@
 /*
 /*
- Copyright (c) 2016 Anton Valentinov Kirilov
+ Copyright (c) 2019 Anton Valentinov Kirilov
 
 
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  associated documentation files (the "Software"), to deal in the Software without restriction,
  associated documentation files (the "Software"), to deal in the Software without restriction,
@@ -17,12 +17,17 @@
  OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 */
 
 
-#ifndef TEMPLATE_H_
+#ifndef REQUEST_HANDLER_DATA_H_
 
 
-#define TEMPLATE_H_
+#define REQUEST_HANDLER_DATA_H_
 
 
-#include <mustache.h>
+#include "cache.h"
 
 
-mustache_template_t *get_fortunes_template(const char *path);
+struct mustache_token_t;
 
 
-#endif // TEMPLATE_H_
+typedef struct {
+	struct mustache_token_t *fortunes_template;
+	cache_t world_cache;
+} request_handler_data_t;
+
+#endif // REQUEST_HANDLER_DATA_H_

+ 69 - 16
frameworks/C/h2o/src/world.c → frameworks/C/h2o/src/handlers/world.c

@@ -39,14 +39,31 @@
 #include "utility.h"
 #include "utility.h"
 #include "world.h"
 #include "world.h"
 
 
+#define CACHE_CAPACITY 131072
+#define CACHE_DURATION 3600000
 #define DO_CLEANUP 4
 #define DO_CLEANUP 4
 #define DO_UPDATE 1
 #define DO_UPDATE 1
 #define ID_KEY "id"
 #define ID_KEY "id"
 #define IS_COMPLETED 8
 #define IS_COMPLETED 8
+#define MAX_ID 10000
 #define MAX_QUERIES 500
 #define MAX_QUERIES 500
 #define QUERIES_PARAMETER "queries="
 #define QUERIES_PARAMETER "queries="
 #define RANDOM_NUM_KEY "randomNumber"
 #define RANDOM_NUM_KEY "randomNumber"
+
+#define UPDATE_QUERY_BEGIN \
+	"UPDATE " WORLD_TABLE_NAME " SET randomNumber = v.randomNumber " \
+	"FROM (VALUES(%" PRIu32 ", %" PRIu32 ")"
+
+#define UPDATE_QUERY_ELEM ", (%" PRIu32 ", %" PRIu32 ")"
+#define UPDATE_QUERY_END ") AS v (id, randomNumber) WHERE " WORLD_TABLE_NAME ".id = v.id;"
+
+#define MAX_UPDATE_QUERY_LEN(n) \
+	(sizeof(UPDATE_QUERY_BEGIN) + sizeof(UPDATE_QUERY_END) - sizeof(UPDATE_QUERY_ELEM) + \
+	 (n) * (sizeof(UPDATE_QUERY_ELEM) - 1 + \
+	        2 * (sizeof(MKSTR(MAX_ID)) - 1) - 2 * (sizeof(PRIu32) - 1) - 2))
+
 #define USE_CACHE 2
 #define USE_CACHE 2
+#define WORLD_TABLE_NAME "World"
 
 
 typedef struct multiple_query_ctx_t multiple_query_ctx_t;
 typedef struct multiple_query_ctx_t multiple_query_ctx_t;
 typedef struct update_ctx_t update_ctx_t;
 typedef struct update_ctx_t update_ctx_t;
@@ -87,6 +104,7 @@ struct multiple_query_ctx_t {
 	query_result_t res[];
 	query_result_t res[];
 };
 };
 
 
+static int cached_queries(struct st_h2o_handler_t *self, h2o_req_t *req);
 static void cleanup_multiple_query(multiple_query_ctx_t *query_ctx);
 static void cleanup_multiple_query(multiple_query_ctx_t *query_ctx);
 static void cleanup_multiple_query_request(void *data);
 static void cleanup_multiple_query_request(void *data);
 static void cleanup_single_query(single_query_ctx_t *query_ctx);
 static void cleanup_single_query(single_query_ctx_t *query_ctx);
@@ -96,8 +114,10 @@ static void complete_multiple_query(multiple_query_ctx_t *query_ctx);
 static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req);
 static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req);
 static void do_updates(multiple_query_ctx_t *query_ctx);
 static void do_updates(multiple_query_ctx_t *query_ctx);
 static void fetch_from_cache(uint64_t now, cache_t *world_cache, multiple_query_ctx_t *query_ctx);
 static void fetch_from_cache(uint64_t now, cache_t *world_cache, multiple_query_ctx_t *query_ctx);
+static void free_world_cache_entry(h2o_iovec_t value);
 static size_t get_query_number(h2o_req_t *req);
 static size_t get_query_number(h2o_req_t *req);
 static void initialize_ids(size_t num_query, query_result_t *res, unsigned int *seed);
 static void initialize_ids(size_t num_query, query_result_t *res, unsigned int *seed);
+static int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req);
 static void on_multiple_query_error(db_query_param_t *param, const char *error_string);
 static void on_multiple_query_error(db_query_param_t *param, const char *error_string);
 static result_return_t on_multiple_query_result(db_query_param_t *param, PGresult *result);
 static result_return_t on_multiple_query_result(db_query_param_t *param, PGresult *result);
 static void on_multiple_query_timeout(db_query_param_t *param);
 static void on_multiple_query_timeout(db_query_param_t *param);
@@ -111,6 +131,15 @@ static void serialize_items(const query_result_t *res,
                             size_t num_result,
                             size_t num_result,
                             json_generator_t **gen,
                             json_generator_t **gen,
                             h2o_req_t *req);
                             h2o_req_t *req);
+static int single_query(struct st_h2o_handler_t *self, h2o_req_t *req);
+static int updates(struct st_h2o_handler_t *self, h2o_req_t *req);
+
+
+static int cached_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
+{
+	IGNORE_FUNCTION_PARAMETER(self);
+	return do_multiple_queries(false, true, req);
+}
 
 
 static void cleanup_multiple_query(multiple_query_ctx_t *query_ctx)
 static void cleanup_multiple_query(multiple_query_ctx_t *query_ctx)
 {
 {
@@ -229,7 +258,7 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req)
 		if (use_cache) {
 		if (use_cache) {
 			query_ctx->flags |= USE_CACHE;
 			query_ctx->flags |= USE_CACHE;
 			fetch_from_cache(h2o_now(ctx->event_loop.h2o_ctx.loop),
 			fetch_from_cache(h2o_now(ctx->event_loop.h2o_ctx.loop),
-			                 &ctx->global_data->world_cache,
+			                 &ctx->global_data->request_handler_data.world_cache,
 			                 query_ctx);
 			                 query_ctx);
 
 
 			if (query_ctx->num_result == query_ctx->num_query) {
 			if (query_ctx->num_result == query_ctx->num_query) {
@@ -356,6 +385,11 @@ static void fetch_from_cache(uint64_t now, cache_t *world_cache, multiple_query_
 	}
 	}
 }
 }
 
 
+static void free_world_cache_entry(h2o_iovec_t value)
+{
+	free(value.base);
+}
+
 static size_t get_query_number(h2o_req_t *req)
 static size_t get_query_number(h2o_req_t *req)
 {
 {
 	int num_query = 0;
 	int num_query = 0;
@@ -396,6 +430,12 @@ static void initialize_ids(size_t num_query, query_result_t *res, unsigned int *
 	}
 	}
 }
 }
 
 
+static int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
+{
+	IGNORE_FUNCTION_PARAMETER(self);
+	return do_multiple_queries(false, false, req);
+}
+
 static void on_multiple_query_error(db_query_param_t *param, const char *error_string)
 static void on_multiple_query_error(db_query_param_t *param, const char *error_string)
 {
 {
 	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
 	const query_param_t * const query_param = H2O_STRUCT_FROM_MEMBER(query_param_t, param, param);
@@ -438,7 +478,7 @@ static result_return_t on_multiple_query_result(db_query_param_t *param, PGresul
 				cache_set(h2o_now(query_ctx->ctx->event_loop.h2o_ctx.loop),
 				cache_set(h2o_now(query_ctx->ctx->event_loop.h2o_ctx.loop),
 				          key,
 				          key,
 				          value,
 				          value,
-				          &query_ctx->ctx->global_data->world_cache);
+				          &query_ctx->ctx->global_data->request_handler_data.world_cache);
 			}
 			}
 		}
 		}
 
 
@@ -666,19 +706,7 @@ error_yajl:
 	send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 	send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req);
 }
 }
 
 
-int cached_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
-{
-	IGNORE_FUNCTION_PARAMETER(self);
-	return do_multiple_queries(false, true, req);
-}
-
-int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req)
-{
-	IGNORE_FUNCTION_PARAMETER(self);
-	return do_multiple_queries(false, false, req);
-}
-
-int single_query(struct st_h2o_handler_t *self, h2o_req_t *req)
+static int single_query(struct st_h2o_handler_t *self, h2o_req_t *req)
 {
 {
 	IGNORE_FUNCTION_PARAMETER(self);
 	IGNORE_FUNCTION_PARAMETER(self);
 
 
@@ -720,8 +748,33 @@ int single_query(struct st_h2o_handler_t *self, h2o_req_t *req)
 	return 0;
 	return 0;
 }
 }
 
 
-int updates(struct st_h2o_handler_t *self, h2o_req_t *req)
+static int updates(struct st_h2o_handler_t *self, h2o_req_t *req)
 {
 {
 	IGNORE_FUNCTION_PARAMETER(self);
 	IGNORE_FUNCTION_PARAMETER(self);
 	return do_multiple_queries(true, false, req);
 	return do_multiple_queries(true, false, req);
 }
 }
+
+void cleanup_world_handlers(global_data_t *global_data)
+{
+	cache_destroy(&global_data->request_handler_data.world_cache);
+}
+
+void initialize_world_handlers(const config_t *config,
+                               global_data_t *global_data,
+                               h2o_hostconf_t *hostconf,
+                               h2o_access_log_filehandle_t *log_handle)
+{
+	add_prepared_statement(WORLD_TABLE_NAME,
+	                       "SELECT * FROM " WORLD_TABLE_NAME " WHERE id = $1::integer;",
+	                       &global_data->prepared_statements);
+	register_request_handler("/db", single_query, hostconf, log_handle);
+	register_request_handler("/queries", multiple_queries, hostconf, log_handle);
+	register_request_handler("/updates", updates, hostconf, log_handle);
+
+	if (!cache_create(config->thread_num,
+	                  CACHE_CAPACITY,
+	                  CACHE_DURATION,
+	                  free_world_cache_entry,
+	                  &global_data->request_handler_data.world_cache))
+		register_request_handler("/cached-worlds", cached_queries, hostconf, log_handle);
+}

+ 7 - 4
frameworks/C/h2o/src/world.h → frameworks/C/h2o/src/handlers/world.h

@@ -23,9 +23,12 @@
 
 
 #include <h2o.h>
 #include <h2o.h>
 
 
-int cached_queries(struct st_h2o_handler_t *self, h2o_req_t *req);
-int multiple_queries(struct st_h2o_handler_t *self, h2o_req_t *req);
-int single_query(struct st_h2o_handler_t *self, h2o_req_t *req);
-int updates(struct st_h2o_handler_t *self, h2o_req_t *req);
+#include "global_data.h"
+
+void cleanup_world_handlers(global_data_t *global_data);
+void initialize_world_handlers(const config_t *config,
+                               global_data_t *global_data,
+                               h2o_hostconf_t *hostconf,
+                               h2o_access_log_filehandle_t *log_handle);
 
 
 #endif // WORLD_H_
 #endif // WORLD_H_

+ 7 - 72
frameworks/C/h2o/src/main.c

@@ -19,7 +19,6 @@
 
 
 #include <errno.h>
 #include <errno.h>
 #include <h2o.h>
 #include <h2o.h>
-#include <mustache.h>
 #include <pthread.h>
 #include <pthread.h>
 #include <signal.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -31,29 +30,23 @@
 #include <sys/signalfd.h>
 #include <sys/signalfd.h>
 #include <sys/time.h>
 #include <sys/time.h>
 
 
-#include "cache.h"
 #include "error.h"
 #include "error.h"
 #include "event_loop.h"
 #include "event_loop.h"
+#include "global_data.h"
 #include "request_handler.h"
 #include "request_handler.h"
-#include "template.h"
 #include "thread.h"
 #include "thread.h"
 #include "tls.h"
 #include "tls.h"
 #include "utility.h"
 #include "utility.h"
 
 
-#define DEFAULT_CACHE_LINE_SIZE 128
-#define MS_IN_S 1000
 #define USAGE_MESSAGE \
 #define USAGE_MESSAGE \
 	"Usage:\n%s [-a <max connections accepted simultaneously>] [-b <bind address>] " \
 	"Usage:\n%s [-a <max connections accepted simultaneously>] [-b <bind address>] " \
-	"[-c <certificate file>] [-d <database connection string>] " \
-	"[-e <World cache duration in seconds>] [-f fortunes template file path] " \
+	"[-c <certificate file>] [-d <database connection string>] [-f template file path] " \
 	"[-j <max reused JSON generators>] [-k <private key file>] [-l <log path>] " \
 	"[-j <max reused JSON generators>] [-k <private key file>] [-l <log path>] " \
 	"[-m <max database connections per thread>] [-p <port>] " \
 	"[-m <max database connections per thread>] [-p <port>] " \
 	"[-q <max enqueued database queries per thread>] [-r <root directory>] " \
 	"[-q <max enqueued database queries per thread>] [-r <root directory>] " \
-	"[-s <HTTPS port>] [-t <thread number>] [-w <World cache capacity in bytes>]\n"
+	"[-s <HTTPS port>] [-t <thread number>]\n"
 
 
 static void free_global_data(global_data_t *global_data);
 static void free_global_data(global_data_t *global_data);
-static void free_world_cache_entry(h2o_iovec_t value);
-static size_t get_maximum_cache_line_size(void);
 static int initialize_global_data(const config_t *config, global_data_t *global_data);
 static int initialize_global_data(const config_t *config, global_data_t *global_data);
 static int parse_options(int argc, char *argv[], config_t *config);
 static int parse_options(int argc, char *argv[], config_t *config);
 static void set_default_options(config_t *config);
 static void set_default_options(config_t *config);
@@ -71,51 +64,14 @@ static void free_global_data(global_data_t *global_data)
 	if (global_data->file_logger)
 	if (global_data->file_logger)
 		global_data->file_logger->dispose(global_data->file_logger);
 		global_data->file_logger->dispose(global_data->file_logger);
 
 
-	if (global_data->fortunes_template) {
-		mustache_api_t api = {.freedata = NULL};
-
-		mustache_free(&api, global_data->fortunes_template);
-	}
-
-	cache_destroy(&global_data->world_cache);
+	cleanup_request_handlers(global_data);
+	remove_prepared_statements(global_data->prepared_statements);
 	h2o_config_dispose(&global_data->h2o_config);
 	h2o_config_dispose(&global_data->h2o_config);
 
 
 	if (global_data->ssl_ctx)
 	if (global_data->ssl_ctx)
 		cleanup_openssl(global_data);
 		cleanup_openssl(global_data);
 }
 }
 
 
-static void free_world_cache_entry(h2o_iovec_t value)
-{
-	free(value.base);
-}
-
-static size_t get_maximum_cache_line_size(void)
-{
-	const int name[] = {_SC_LEVEL1_DCACHE_LINESIZE,
-	                    _SC_LEVEL2_CACHE_LINESIZE,
-	                    _SC_LEVEL3_CACHE_LINESIZE,
-	                    _SC_LEVEL4_CACHE_LINESIZE};
-	size_t ret = 0;
-
-	for (size_t i = 0; i < ARRAY_SIZE(name); i++) {
-		errno = 0;
-
-		const long rc = sysconf(name[i]);
-
-		if (rc < 0) {
-			if (errno)
-				STANDARD_ERROR("sysconf");
-		}
-		else if ((size_t) rc > ret)
-			ret = rc;
-	}
-
-	if (!ret)
-		ret = DEFAULT_CACHE_LINE_SIZE;
-
-	return ret;
-}
-
 static int initialize_global_data(const config_t *config, global_data_t *global_data)
 static int initialize_global_data(const config_t *config, global_data_t *global_data)
 {
 {
 	sigset_t signals;
 	sigset_t signals;
@@ -128,16 +84,8 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
 #endif // NDEBUG
 #endif // NDEBUG
 	CHECK_ERRNO(sigaddset, &signals, SIGTERM);
 	CHECK_ERRNO(sigaddset, &signals, SIGTERM);
 	CHECK_ERRNO_RETURN(global_data->signal_fd, signalfd, -1, &signals, SFD_NONBLOCK | SFD_CLOEXEC);
 	CHECK_ERRNO_RETURN(global_data->signal_fd, signalfd, -1, &signals, SFD_NONBLOCK | SFD_CLOEXEC);
-	global_data->fortunes_template = get_fortunes_template(config->template_path);
 	h2o_config_init(&global_data->h2o_config);
 	h2o_config_init(&global_data->h2o_config);
 
 
-	if (cache_create(config->thread_num,
-	                 config->world_cache_capacity,
-	                 config->world_cache_duration,
-	                 free_world_cache_entry,
-	                 &global_data->world_cache))
-		goto error;
-
 	if (config->cert && config->key)
 	if (config->cert && config->key)
 		initialize_openssl(config, global_data);
 		initialize_openssl(config, global_data);
 
 
@@ -154,7 +102,7 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
 			goto error;
 			goto error;
 	}
 	}
 
 
-	register_request_handlers(hostconf, log_handle);
+	initialize_request_handlers(config, global_data, hostconf, log_handle);
 
 
 	// Must be registered after the rest of the request handlers.
 	// Must be registered after the rest of the request handlers.
 	if (config->root) {
 	if (config->root) {
@@ -188,7 +136,7 @@ static int parse_options(int argc, char *argv[], config_t *config)
 	opterr = 0;
 	opterr = 0;
 
 
 	while (1) {
 	while (1) {
-		const int opt = getopt(argc, argv, "?a:b:c:d:e:f:j:k:l:m:p:q:r:s:t:w:");
+		const int opt = getopt(argc, argv, "?a:b:c:d:f:j:k:l:m:p:q:r:s:t:");
 
 
 		if (opt == -1)
 		if (opt == -1)
 			break;
 			break;
@@ -221,10 +169,6 @@ static int parse_options(int argc, char *argv[], config_t *config)
 			case 'd':
 			case 'd':
 				config->db_host = optarg;
 				config->db_host = optarg;
 				break;
 				break;
-			case 'e':
-				PARSE_NUMBER(config->world_cache_duration);
-				config->world_cache_duration *= MS_IN_S;
-				break;
 			case 'f':
 			case 'f':
 				config->template_path = optarg;
 				config->template_path = optarg;
 				break;
 				break;
@@ -255,9 +199,6 @@ static int parse_options(int argc, char *argv[], config_t *config)
 			case 't':
 			case 't':
 				PARSE_NUMBER(config->thread_num);
 				PARSE_NUMBER(config->thread_num);
 				break;
 				break;
-			case 'w':
-				PARSE_NUMBER(config->world_cache_capacity);
-				break;
 			default:
 			default:
 				fprintf(stderr, USAGE_MESSAGE, *argv);
 				fprintf(stderr, USAGE_MESSAGE, *argv);
 				return EXIT_FAILURE;
 				return EXIT_FAILURE;
@@ -272,9 +213,6 @@ static int parse_options(int argc, char *argv[], config_t *config)
 
 
 static void set_default_options(config_t *config)
 static void set_default_options(config_t *config)
 {
 {
-	if (!config->world_cache_duration)
-		config->world_cache_duration = 3600000;
-
 	if (!config->max_accept)
 	if (!config->max_accept)
 		config->max_accept = 10;
 		config->max_accept = 10;
 
 
@@ -290,9 +228,6 @@ static void set_default_options(config_t *config)
 	if (!config->thread_num)
 	if (!config->thread_num)
 		config->thread_num = h2o_numproc();
 		config->thread_num = h2o_numproc();
 
 
-	if (!config->world_cache_capacity)
-		config->world_cache_capacity = 131072;
-
 	if (!config->https_port)
 	if (!config->https_port)
 		config->https_port = 4443;
 		config->https_port = 4443;
 }
 }

+ 28 - 48
frameworks/C/h2o/src/request_handler.c

@@ -22,13 +22,14 @@
 #include <string.h>
 #include <string.h>
 #include <yajl/yajl_gen.h>
 #include <yajl/yajl_gen.h>
 
 
-#include "fortune.h"
-#include "json_serializer.h"
-#include "plaintext.h"
+#include "global_data.h"
 #include "request_handler.h"
 #include "request_handler.h"
 #include "thread.h"
 #include "thread.h"
 #include "utility.h"
 #include "utility.h"
-#include "world.h"
+#include "handlers/fortune.h"
+#include "handlers/json_serializer.h"
+#include "handlers/plaintext.h"
+#include "handlers/world.h"
 
 
 static const char *status_code_to_string(http_status_code_t status_code)
 static const char *status_code_to_string(http_status_code_t status_code)
 {
 {
@@ -57,6 +58,12 @@ static const char *status_code_to_string(http_status_code_t status_code)
 	return ret;
 	return ret;
 }
 }
 
 
+void cleanup_request_handlers(global_data_t *global_data)
+{
+	cleanup_fortunes_handler(global_data);
+	cleanup_world_handlers(global_data);
+}
+
 const char *get_query_param(const char *query,
 const char *get_query_param(const char *query,
                             size_t query_len,
                             size_t query_len,
                             const char *param,
                             const char *param,
@@ -82,56 +89,29 @@ const char *get_query_param(const char *query,
 	return ret;
 	return ret;
 }
 }
 
 
-void register_request_handlers(h2o_hostconf_t *hostconf, h2o_access_log_filehandle_t *log_handle)
+void initialize_request_handlers(const config_t *config,
+                                 global_data_t *global_data,
+                                 h2o_hostconf_t *hostconf,
+                                 h2o_access_log_filehandle_t *log_handle)
 {
 {
-	h2o_pathconf_t *pathconf = h2o_config_register_path(hostconf, "/json", 0);
-	h2o_handler_t *handler = h2o_create_handler(pathconf, sizeof(*handler));
-
-	if (log_handle)
-		h2o_access_log_register(pathconf, log_handle);
-
-	handler->on_req = json_serializer;
-	pathconf = h2o_config_register_path(hostconf, "/db", 0);
-	handler = h2o_create_handler(pathconf, sizeof(*handler));
-	handler->on_req = single_query;
-
-	if (log_handle)
-		h2o_access_log_register(pathconf, log_handle);
-
-	pathconf = h2o_config_register_path(hostconf, "/queries", 0);
-	handler = h2o_create_handler(pathconf, sizeof(*handler));
-	handler->on_req = multiple_queries;
-
-	if (log_handle)
-		h2o_access_log_register(pathconf, log_handle);
-
-	pathconf = h2o_config_register_path(hostconf, "/fortunes", 0);
-	handler = h2o_create_handler(pathconf, sizeof(*handler));
-	handler->on_req = fortunes;
-
-	if (log_handle)
-		h2o_access_log_register(pathconf, log_handle);
-
-	pathconf = h2o_config_register_path(hostconf, "/updates", 0);
-	handler = h2o_create_handler(pathconf, sizeof(*handler));
-	handler->on_req = updates;
-
-	if (log_handle)
-		h2o_access_log_register(pathconf, log_handle);
+	initialize_fortunes_handler(config, global_data, hostconf, log_handle);
+	initialize_json_serializer_handler(hostconf, log_handle);
+	initialize_plaintext_handler(hostconf, log_handle);
+	initialize_world_handlers(config, global_data, hostconf, log_handle);
+}
 
 
-	pathconf = h2o_config_register_path(hostconf, "/plaintext", 0);
-	handler = h2o_create_handler(pathconf, sizeof(*handler));
-	handler->on_req = plaintext;
+void register_request_handler(const char *path,
+                              int (*handler)(struct st_h2o_handler_t *, h2o_req_t *),
+                              h2o_hostconf_t *hostconf,
+                              h2o_access_log_filehandle_t *log_handle)
+{
+	h2o_pathconf_t * const pathconf = h2o_config_register_path(hostconf, path, 0);
+	h2o_handler_t * const h = h2o_create_handler(pathconf, sizeof(*h));
 
 
 	if (log_handle)
 	if (log_handle)
 		h2o_access_log_register(pathconf, log_handle);
 		h2o_access_log_register(pathconf, log_handle);
 
 
-	pathconf = h2o_config_register_path(hostconf, "/cached-worlds", 0);
-	handler = h2o_create_handler(pathconf, sizeof(*handler));
-	handler->on_req = cached_queries;
-
-	if (log_handle)
-		h2o_access_log_register(pathconf, log_handle);
+	h->on_req = handler;
 }
 }
 
 
 void send_error(http_status_code_t status_code, const char *body, h2o_req_t *req)
 void send_error(http_status_code_t status_code, const char *body, h2o_req_t *req)

+ 10 - 1
frameworks/C/h2o/src/request_handler.h

@@ -24,6 +24,7 @@
 #include <h2o.h>
 #include <h2o.h>
 #include <stdbool.h>
 #include <stdbool.h>
 
 
+#include "global_data.h"
 #include "utility.h"
 #include "utility.h"
 
 
 #define REQ_ERROR "request error\n"
 #define REQ_ERROR "request error\n"
@@ -42,11 +43,19 @@ typedef enum {
 	GATEWAY_TIMEOUT = 504
 	GATEWAY_TIMEOUT = 504
 } http_status_code_t;
 } http_status_code_t;
 
 
+void cleanup_request_handlers(global_data_t *global_data);
 const char *get_query_param(const char *query,
 const char *get_query_param(const char *query,
                             size_t query_len,
                             size_t query_len,
                             const char *param,
                             const char *param,
                             size_t param_len);
                             size_t param_len);
-void register_request_handlers(h2o_hostconf_t *hostconf, h2o_access_log_filehandle_t *log_handle);
+void initialize_request_handlers(const config_t *config,
+                                 global_data_t *global_data,
+                                 h2o_hostconf_t *hostconf,
+                                 h2o_access_log_filehandle_t *log_handle);
+void register_request_handler(const char *path,
+                              int (*handler)(struct st_h2o_handler_t *, h2o_req_t *),
+                              h2o_hostconf_t *hostconf,
+                              h2o_access_log_filehandle_t *log_handle);
 void send_error(http_status_code_t status_code, const char *body, h2o_req_t *req);
 void send_error(http_status_code_t status_code, const char *body, h2o_req_t *req);
 int send_json_response(json_generator_t *gen, bool free_gen, h2o_req_t *req);
 int send_json_response(json_generator_t *gen, bool free_gen, h2o_req_t *req);
 void send_service_unavailable_error(const char *body, h2o_req_t *req);
 void send_service_unavailable_error(const char *body, h2o_req_t *req);

+ 0 - 144
frameworks/C/h2o/src/template.c

@@ -1,144 +0,0 @@
-/*
- Copyright (c) 2016 Anton Valentinov Kirilov
-
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
- associated documentation files (the "Software"), to deal in the Software without restriction,
- including without limitation the rights to use, copy, modify, merge, publish, distribute,
- sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all copies or
- substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
- NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
- OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#include <errno.h>
-#include <mustache.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "database.h"
-#include "error.h"
-#include "fortune.h"
-#include "template.h"
-#include "utility.h"
-
-typedef struct {
-	FILE *input;
-	const char *name;
-} template_input_t;
-
-static uintmax_t prerender_section(mustache_api_t *api,
-                                   void *userdata,
-                                   mustache_token_section_t *token);
-static uintmax_t prerender_variable(mustache_api_t *api,
-                                    void *userdata,
-                                    mustache_token_variable_t *token);
-static uintmax_t read_template(mustache_api_t *api,
-                               void *userdata,
-                               char *buffer,
-                               uintmax_t buffer_size);
-static void template_error(mustache_api_t *api,
-                           void *userdata,
-                           uintmax_t lineno,
-                           const char *error);
-
-static uintmax_t prerender_section(mustache_api_t *api,
-                                   void *userdata,
-                                   mustache_token_section_t *token)
-{
-	bool * const in_section = userdata;
-	uintmax_t ret = 0;
-
-	if (!*in_section && !strcmp(token->name, FORTUNE_TABLE_NAME)) {
-		*in_section = true;
-		ret = mustache_prerender(api, userdata, token->section);
-		*in_section = false;
-	}
-
-	return ret;
-}
-
-static uintmax_t prerender_variable(mustache_api_t *api,
-                                    void *userdata,
-                                    mustache_token_variable_t *token)
-{
-	IGNORE_FUNCTION_PARAMETER(api);
-
-	bool * const in_section = userdata;
-	uintmax_t ret = 0;
-
-	if (*in_section) {
-		if (token->text_length == sizeof(ID_FIELD_NAME) - 1 &&
-		    !memcmp(token->text, ID_FIELD_NAME, sizeof(ID_FIELD_NAME) - 1)) {
-			token->userdata = (void *) offsetof(fortune_t, id);
-			ret = 1;
-		}
-		else if (token->text_length == sizeof(MESSAGE_FIELD_NAME) - 1 &&
-		         !memcmp(token->text, MESSAGE_FIELD_NAME, sizeof(MESSAGE_FIELD_NAME) - 1)) {
-			token->userdata = (void *) offsetof(fortune_t, message);
-			ret = 1;
-		}
-	}
-
-	return ret;
-}
-
-static uintmax_t read_template(mustache_api_t *api,
-                               void *userdata,
-                               char *buffer,
-                               uintmax_t buffer_size)
-{
-	IGNORE_FUNCTION_PARAMETER(api);
-
-	const template_input_t * const template_input = userdata;
-
-	return fread(buffer, sizeof(*buffer), buffer_size, template_input->input);
-}
-
-static void template_error(mustache_api_t *api,
-                           void *userdata,
-                           uintmax_t lineno,
-                           const char *error)
-{
-	IGNORE_FUNCTION_PARAMETER(api);
-
-	const template_input_t * const template_input = userdata;
-
-	print_error(template_input->name, lineno, "mustache_compile", error);
-}
-
-mustache_template_t *get_fortunes_template(const char *path)
-{
-	mustache_template_t *ret = NULL;
-	template_input_t template_input = {.input = fopen(path, "rb"), .name = path};
-
-	if (template_input.input) {
-		mustache_api_t api = {.error = template_error,
-		                      .read = read_template,
-		                      .sectget = prerender_section,
-		                      .varget = prerender_variable};
-		bool in_section = false;
-
-		ret = mustache_compile(&api, &template_input);
-
-		if (ret && !mustache_prerender(&api, &in_section, ret)) {
-			mustache_free(&api, ret);
-			ret = NULL;
-		}
-
-		fclose(template_input.input);
-	}
-	else
-		STANDARD_ERROR("fopen");
-
-	return ret;
-}

+ 2 - 2
frameworks/C/h2o/src/thread.c

@@ -34,6 +34,7 @@
 #include "database.h"
 #include "database.h"
 #include "error.h"
 #include "error.h"
 #include "event_loop.h"
 #include "event_loop.h"
+#include "global_data.h"
 #include "thread.h"
 #include "thread.h"
 #include "utility.h"
 #include "utility.h"
 
 
@@ -128,8 +129,7 @@ void initialize_thread_context(global_thread_data_t *global_thread_data,
 	ctx->config = global_thread_data->config;
 	ctx->config = global_thread_data->config;
 	ctx->global_data = global_thread_data->global_data;
 	ctx->global_data = global_thread_data->global_data;
 	ctx->global_thread_data = global_thread_data;
 	ctx->global_thread_data = global_thread_data;
-	ctx->tid = syscall(SYS_gettid);
-	ctx->random_seed = ctx->tid;
+	ctx->random_seed = syscall(SYS_gettid);
 	initialize_event_loop(is_main_thread,
 	initialize_event_loop(is_main_thread,
 	                      global_thread_data->global_data,
 	                      global_thread_data->global_data,
 	                      &global_thread_data->h2o_receiver,
 	                      &global_thread_data->h2o_receiver,

+ 1 - 2
frameworks/C/h2o/src/thread.h

@@ -29,7 +29,7 @@
 
 
 #include "database.h"
 #include "database.h"
 #include "event_loop.h"
 #include "event_loop.h"
-#include "utility.h"
+#include "global_data.h"
 
 
 typedef struct thread_context_t thread_context_t;
 typedef struct thread_context_t thread_context_t;
 
 
@@ -50,7 +50,6 @@ struct thread_context_t {
 	list_t *json_generator;
 	list_t *json_generator;
 	size_t json_generator_num;
 	size_t json_generator_num;
 	unsigned random_seed;
 	unsigned random_seed;
-	pid_t tid;
 	db_state_t db_state;
 	db_state_t db_state;
 	event_loop_t event_loop;
 	event_loop_t event_loop;
 };
 };

+ 1 - 1
frameworks/C/h2o/src/tls.c

@@ -29,8 +29,8 @@
 #include <openssl/ssl.h>
 #include <openssl/ssl.h>
 
 
 #include "error.h"
 #include "error.h"
+#include "global_data.h"
 #include "tls.h"
 #include "tls.h"
-#include "utility.h"
 
 
 #define CHECK_OPENSSL_ERROR(function, ...) \
 #define CHECK_OPENSSL_ERROR(function, ...) \
 	do { \
 	do { \

+ 1 - 1
frameworks/C/h2o/src/tls.h

@@ -21,7 +21,7 @@
 
 
 #define TLS_H_
 #define TLS_H_
 
 
-#include "utility.h"
+#include "global_data.h"
 
 
 void cleanup_openssl(global_data_t *global_data);
 void cleanup_openssl(global_data_t *global_data);
 void initialize_openssl(const config_t *config, global_data_t *global_data);
 void initialize_openssl(const config_t *config, global_data_t *global_data);

+ 36 - 3
frameworks/C/h2o/src/utility.c

@@ -18,17 +18,23 @@
 */
 */
 
 
 #include <assert.h>
 #include <assert.h>
+#include <h2o.h>
+#include <errno.h>
 #include <inttypes.h>
 #include <inttypes.h>
 #include <limits.h>
 #include <limits.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <yajl/yajl_gen.h>
 #include <yajl/yajl_gen.h>
 
 
+#include "error.h"
 #include "list.h"
 #include "list.h"
 #include "utility.h"
 #include "utility.h"
 
 
+#define DEFAULT_CACHE_LINE_SIZE 128
+
 void free_json_generator(json_generator_t *gen, list_t **pool, size_t *gen_num, size_t max_gen)
 void free_json_generator(json_generator_t *gen, list_t **pool, size_t *gen_num, size_t max_gen)
 {
 {
 	if (gen) {
 	if (gen) {
@@ -48,12 +54,12 @@ void free_json_generator(json_generator_t *gen, list_t **pool, size_t *gen_num,
 	}
 	}
 }
 }
 
 
-yajl_gen_status gen_integer(int64_t number, char *buf, size_t len, yajl_gen gen)
+yajl_gen_status gen_integer(long long number, char *buf, size_t len, yajl_gen gen)
 {
 {
 	if (!len)
 	if (!len)
 		return yajl_gen_invalid_number;
 		return yajl_gen_invalid_number;
-	else if (number == INT64_MIN) {
-		const size_t l = snprintf(buf, len, "%" PRId64, number);
+	else if (number == LLONG_MIN) {
+		const size_t l = snprintf(buf, len, "%lld", number);
 
 
 		if (l >= len)
 		if (l >= len)
 			return yajl_gen_invalid_number;
 			return yajl_gen_invalid_number;
@@ -120,6 +126,33 @@ json_generator_t *get_json_generator(list_t **pool, size_t *gen_num)
 	return ret;
 	return ret;
 }
 }
 
 
+size_t get_maximum_cache_line_size(void)
+{
+	const int name[] = {_SC_LEVEL1_DCACHE_LINESIZE,
+	                    _SC_LEVEL2_CACHE_LINESIZE,
+	                    _SC_LEVEL3_CACHE_LINESIZE,
+	                    _SC_LEVEL4_CACHE_LINESIZE};
+	size_t ret = 0;
+
+	for (size_t i = 0; i < ARRAY_SIZE(name); i++) {
+		errno = 0;
+
+		const long rc = sysconf(name[i]);
+
+		if (rc < 0) {
+			if (errno)
+				STANDARD_ERROR("sysconf");
+		}
+		else if ((size_t) rc > ret)
+			ret = rc;
+	}
+
+	if (!ret)
+		ret = DEFAULT_CACHE_LINE_SIZE;
+
+	return ret;
+}
+
 uint32_t get_random_number(uint32_t max_rand, unsigned int *seed)
 uint32_t get_random_number(uint32_t max_rand, unsigned int *seed)
 {
 {
 	assert(max_rand <= (uint32_t) RAND_MAX);
 	assert(max_rand <= (uint32_t) RAND_MAX);

+ 3 - 40
frameworks/C/h2o/src/utility.h

@@ -21,15 +21,11 @@
 
 
 #define UTILITY_H_
 #define UTILITY_H_
 
 
-#include <h2o.h>
-#include <mustache.h>
 #include <stdbool.h>
 #include <stdbool.h>
+#include <stddef.h>
 #include <stdint.h>
 #include <stdint.h>
-#include <h2o/cache.h>
-#include <openssl/ssl.h>
 #include <yajl/yajl_gen.h>
 #include <yajl/yajl_gen.h>
 
 
-#include "cache.h"
 #include "list.h"
 #include "list.h"
 
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -42,48 +38,15 @@
 #define TOSTRING(x) # x
 #define TOSTRING(x) # x
 #define YAJL_STRLIT(s) (const unsigned char *) (s), sizeof(s) - 1
 #define YAJL_STRLIT(s) (const unsigned char *) (s), sizeof(s) - 1
 
 
-typedef struct global_thread_data_t global_thread_data_t;
-
-typedef struct {
-	const char *bind_address;
-	const char *cert;
-	const char *db_host;
-	const char *key;
-	const char *log;
-	const char *root;
-	const char *template_path;
-	uint64_t world_cache_duration;
-	size_t max_accept;
-	size_t max_db_conn_num;
-	size_t max_json_generator;
-	size_t max_query_num;
-	size_t thread_num;
-	size_t world_cache_capacity;
-	uint16_t https_port;
-	uint16_t port;
-} config_t;
-
-typedef struct {
-	h2o_logger_t *file_logger;
-	mustache_template_t *fortunes_template;
-	global_thread_data_t *global_thread_data;
-	h2o_socket_t *signals;
-	SSL_CTX *ssl_ctx;
-	size_t memory_alignment;
-	int signal_fd;
-	bool shutdown;
-	h2o_globalconf_t h2o_config;
-	cache_t world_cache;
-} global_data_t;
-
 typedef struct {
 typedef struct {
 	list_t l;
 	list_t l;
 	yajl_gen gen;
 	yajl_gen gen;
 } json_generator_t;
 } json_generator_t;
 
 
 void free_json_generator(json_generator_t *gen, list_t **pool, size_t *gen_num, size_t max_gen);
 void free_json_generator(json_generator_t *gen, list_t **pool, size_t *gen_num, size_t max_gen);
-yajl_gen_status gen_integer(int64_t number, char *buf, size_t len, yajl_gen gen);
+yajl_gen_status gen_integer(long long number, char *buf, size_t len, yajl_gen gen);
 json_generator_t *get_json_generator(list_t **pool, size_t *gen_num);
 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);
 uint32_t get_random_number(uint32_t max_rand, unsigned int *seed);
 bool is_power_of_2(size_t x);
 bool is_power_of_2(size_t x);
 size_t round_up_to_power_of_2(size_t x);
 size_t round_up_to_power_of_2(size_t x);

+ 1 - 1
frameworks/C/h2o/start-servers.sh

@@ -38,7 +38,7 @@ run_curl()
 
 
 run_h2o_app()
 run_h2o_app()
 {
 {
-	taskset -c "$1" "$2/h2o_app" -a20 -f "$3/template/fortunes.mustache" -m "$DB_CONN" "$4" "$5" \
+	taskset -c "$1" "$2/h2o_app" -a20 -f "$3/template" -m "$DB_CONN" "$4" "$5" \
 	        -d "host=tfb-database dbname=hello_world user=benchmarkdbuser \
 	        -d "host=tfb-database dbname=hello_world user=benchmarkdbuser \
 	            password=benchmarkdbpass" &
 	            password=benchmarkdbpass" &
 }
 }