|
57 | 57 | // MAX_UPDATE_QUERY_LEN must be updated whenever UPDATE_QUERY_BEGIN, UPDATE_QUERY_ELEM,
|
58 | 58 | // UPDATE_QUERY_MIDDLE, UPDATE_QUERY_ELEM2, and UPDATE_QUERY_END are changed.
|
59 | 59 | #define UPDATE_QUERY_BEGIN "UPDATE " WORLD_TABLE_NAME " SET randomNumber = CASE id "
|
60 |
| -#define UPDATE_QUERY_ELEM "WHEN %" PRIu32 " THEN %" PRIu32 " " |
61 |
| -#define UPDATE_QUERY_MIDDLE "ELSE randomNumber END WHERE id IN (%" PRIu32 |
62 |
| -#define UPDATE_QUERY_ELEM2 ",%" PRIu32 |
| 60 | +#define UPDATE_QUERY_ELEM "WHEN $%zu::integer THEN $%zu::integer " |
| 61 | +#define UPDATE_QUERY_MIDDLE "ELSE randomNumber END WHERE id IN ($1::integer" |
| 62 | +#define UPDATE_QUERY_ELEM2 ",$%zu::integer" |
63 | 63 | #define UPDATE_QUERY_END ");"
|
64 | 64 |
|
65 | 65 | #define MAX_UPDATE_QUERY_LEN(n) \
|
66 | 66 | (sizeof(UPDATE_QUERY_BEGIN) + sizeof(UPDATE_QUERY_MIDDLE) + \
|
67 | 67 | sizeof(UPDATE_QUERY_END) - 1 - sizeof(UPDATE_QUERY_ELEM2) + \
|
68 | 68 | (n) * (sizeof(UPDATE_QUERY_ELEM) - 1 + sizeof(UPDATE_QUERY_ELEM2) - 1 + \
|
69 |
| - 3 * (sizeof(MKSTR(MAX_ID)) - 1) - 3 * (sizeof(PRIu32) - 1) - 3)) |
| 69 | + 3 * sizeof(MKSTR(MAX_QUERIES)) - 3 * (sizeof("%zu") - 1))) |
70 | 70 |
|
| 71 | +#define UPDATE_QUERY_NAME_PREFIX WORLD_TABLE_NAME "Update" |
71 | 72 | #define USE_CACHE 2
|
72 | 73 | #define WORLD_QUERY "SELECT * FROM " WORLD_TABLE_NAME " WHERE id = $1::integer;"
|
73 | 74 |
|
@@ -259,11 +260,16 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req)
|
259 | 260 | size_t sz = base_size + num_query_in_progress * sizeof(query_param_t);
|
260 | 261 |
|
261 | 262 | if (do_update) {
|
262 |
| - const size_t reuse_size = (num_query_in_progress - 1) * sizeof(query_param_t); |
263 |
| - const size_t update_query_len = MAX_UPDATE_QUERY_LEN(num_query); |
| 263 | + size_t s = base_size + sizeof(query_param_t); |
264 | 264 |
|
265 |
| - if (update_query_len > reuse_size) |
266 |
| - sz += update_query_len - reuse_size; |
| 265 | + s = (s + _Alignof(const char *) - 1) / _Alignof(const char *); |
| 266 | + s = s * _Alignof(const char *) + 2 * num_query * sizeof(const char *); |
| 267 | + s = (s + _Alignof(int) - 1) / _Alignof(int); |
| 268 | + s = s * _Alignof(int) + 4 * num_query * sizeof(int); |
| 269 | + s += sizeof(UPDATE_QUERY_NAME_PREFIX MKSTR(MAX_QUERIES)); |
| 270 | + |
| 271 | + if (s > sz) |
| 272 | + sz = s; |
267 | 273 | }
|
268 | 274 |
|
269 | 275 | multiple_query_ctx_t * const query_ctx = h2o_mem_alloc(sz);
|
@@ -332,65 +338,57 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req)
|
332 | 338 |
|
333 | 339 | static void do_updates(multiple_query_ctx_t *query_ctx)
|
334 | 340 | {
|
335 |
| - char *iter = (char *) (query_ctx->query_param + 1); |
336 |
| - size_t sz = MAX_UPDATE_QUERY_LEN(query_ctx->num_result); |
337 |
| - |
338 |
| - // Sort the results to avoid database deadlock. |
339 |
| - qsort(query_ctx->res, query_ctx->num_result, sizeof(*query_ctx->res), compare_items); |
340 |
| - query_ctx->query_param->param.command = iter; |
341 |
| - query_ctx->query_param->param.nParams = 0; |
342 |
| - query_ctx->query_param->param.on_result = on_update_result; |
343 |
| - query_ctx->query_param->param.paramFormats = NULL; |
344 |
| - query_ctx->query_param->param.paramLengths = NULL; |
345 |
| - query_ctx->query_param->param.paramValues = NULL; |
346 |
| - query_ctx->query_param->param.flags = 0; |
| 341 | + size_t offset = |
| 342 | + offsetof(multiple_query_ctx_t, res) + query_ctx->num_result * sizeof(*query_ctx->res); |
347 | 343 |
|
348 |
| - int c = snprintf(iter, sz, UPDATE_QUERY_BEGIN); |
349 |
| - |
350 |
| - if ((size_t) c >= sz) |
351 |
| - goto error; |
352 |
| - |
353 |
| - iter += c; |
354 |
| - sz -= c; |
355 |
| - |
356 |
| - for (size_t i = 0; i < query_ctx->num_result; i++) { |
357 |
| - query_ctx->res[i].random_number = 1 + get_random_number(MAX_ID, |
358 |
| - &query_ctx->ctx->random_seed); |
359 |
| - c = snprintf(iter, |
360 |
| - sz, |
361 |
| - UPDATE_QUERY_ELEM, |
362 |
| - query_ctx->res[i].id, |
363 |
| - query_ctx->res[i].random_number); |
| 344 | + offset = ((offset + _Alignof(query_param_t) - 1) / _Alignof(query_param_t)); |
| 345 | + offset = offset * _Alignof(query_param_t) + sizeof(query_param_t); |
| 346 | + offset = (offset + _Alignof(const char *) - 1) / _Alignof(const char *); |
| 347 | + offset *= _Alignof(const char *); |
364 | 348 |
|
365 |
| - if ((size_t) c >= sz) |
366 |
| - goto error; |
| 349 | + const char ** const paramValues = (const char **) ((char *) query_ctx + offset); |
| 350 | + const size_t nParams = query_ctx->num_result * 2; |
367 | 351 |
|
368 |
| - iter += c; |
369 |
| - sz -= c; |
370 |
| - } |
| 352 | + offset += nParams * sizeof(*paramValues); |
| 353 | + offset = (offset + _Alignof(int) - 1) / _Alignof(int); |
| 354 | + offset *= _Alignof(int); |
371 | 355 |
|
372 |
| - c = snprintf(iter, sz, UPDATE_QUERY_MIDDLE, query_ctx->res->id); |
| 356 | + int * const paramFormats = (int *) ((char *) query_ctx + offset); |
| 357 | + int * const paramLengths = paramFormats + nParams; |
| 358 | + char * const command = (char *) (paramLengths + nParams); |
| 359 | + const size_t command_size = |
| 360 | + sizeof(UPDATE_QUERY_NAME_PREFIX MKSTR(MAX_QUERIES)) - sizeof(UPDATE_QUERY_NAME_PREFIX) + 1; |
| 361 | + const int c = snprintf(command + sizeof(UPDATE_QUERY_NAME_PREFIX) - 1, |
| 362 | + command_size, |
| 363 | + "%zu", |
| 364 | + query_ctx->num_result); |
373 | 365 |
|
374 |
| - if ((size_t) c >= sz) |
| 366 | + if ((size_t) c >= command_size) |
375 | 367 | goto error;
|
376 | 368 |
|
377 |
| - iter += c; |
378 |
| - sz -= c; |
379 |
| - |
380 |
| - for (size_t i = 1; i < query_ctx->num_result; i++) { |
381 |
| - c = snprintf(iter, sz, UPDATE_QUERY_ELEM2, query_ctx->res[i].id); |
382 |
| - |
383 |
| - if ((size_t) c >= sz) |
384 |
| - goto error; |
385 |
| - |
386 |
| - iter += c; |
387 |
| - sz -= c; |
388 |
| - } |
389 |
| - |
390 |
| - c = snprintf(iter, sz, UPDATE_QUERY_END); |
| 369 | + memcpy(command, UPDATE_QUERY_NAME_PREFIX, sizeof(UPDATE_QUERY_NAME_PREFIX) - 1); |
| 370 | + // Sort the results to avoid database deadlock. |
| 371 | + qsort(query_ctx->res, query_ctx->num_result, sizeof(*query_ctx->res), compare_items); |
391 | 372 |
|
392 |
| - if ((size_t) c >= sz) |
393 |
| - goto error; |
| 373 | + for (size_t i = 0; i < query_ctx->num_result; i++) { |
| 374 | + query_ctx->res[i].id = htonl(query_ctx->res[i].id); |
| 375 | + query_ctx->res[i].random_number = |
| 376 | + htonl(1 + get_random_number(MAX_ID, &query_ctx->ctx->random_seed)); |
| 377 | + paramFormats[2 * i] = 1; |
| 378 | + paramFormats[2 * i + 1] = 1; |
| 379 | + paramLengths[2 * i] = sizeof(query_ctx->res[i].id); |
| 380 | + paramLengths[2 * i + 1] = sizeof(query_ctx->res[i].random_number); |
| 381 | + paramValues[2 * i] = (const char *) &query_ctx->res[i].id; |
| 382 | + paramValues[2 * i + 1] = (const char *) &query_ctx->res[i].random_number; |
| 383 | + } |
| 384 | + |
| 385 | + query_ctx->query_param->param.command = command; |
| 386 | + query_ctx->query_param->param.flags = IS_PREPARED; |
| 387 | + query_ctx->query_param->param.nParams = nParams; |
| 388 | + query_ctx->query_param->param.on_result = on_update_result; |
| 389 | + query_ctx->query_param->param.paramFormats = paramFormats; |
| 390 | + query_ctx->query_param->param.paramLengths = paramLengths; |
| 391 | + query_ctx->query_param->param.paramValues = paramValues; |
394 | 392 |
|
395 | 393 | if (execute_database_query(&query_ctx->ctx->request_handler_data.hello_world_db,
|
396 | 394 | &query_ctx->query_param->param)) {
|
@@ -726,8 +724,14 @@ static result_return_t on_update_result(db_query_param_t *param, PGresult *resul
|
726 | 724 | query_ctx->gen = get_json_generator(&query_ctx->ctx->json_generator,
|
727 | 725 | &query_ctx->ctx->json_generator_num);
|
728 | 726 |
|
729 |
| - if (query_ctx->gen) |
| 727 | + if (query_ctx->gen) { |
| 728 | + for (size_t i = 0; i < query_ctx->num_result; i++) { |
| 729 | + query_ctx->res[i].id = ntohl(query_ctx->res[i].id); |
| 730 | + query_ctx->res[i].random_number = ntohl(query_ctx->res[i].random_number); |
| 731 | + } |
| 732 | + |
730 | 733 | serialize_items(query_ctx->res, query_ctx->num_result, &query_ctx->gen, query_ctx->req);
|
| 734 | + } |
731 | 735 | else
|
732 | 736 | send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, query_ctx->req);
|
733 | 737 | }
|
@@ -887,6 +891,57 @@ void initialize_world_handlers(h2o_hostconf_t *hostconf,
|
887 | 891 | h2o_access_log_filehandle_t *log_handle,
|
888 | 892 | request_handler_data_t *data)
|
889 | 893 | {
|
| 894 | + char name[sizeof(UPDATE_QUERY_NAME_PREFIX MKSTR(MAX_QUERIES))]; |
| 895 | + char query[MAX_UPDATE_QUERY_LEN(MAX_QUERIES)]; |
| 896 | + const size_t name_size = sizeof(name) - sizeof(UPDATE_QUERY_NAME_PREFIX) + 1; |
| 897 | + |
| 898 | + assert(sizeof(name) >= sizeof(UPDATE_QUERY_NAME_PREFIX)); |
| 899 | + memcpy(name, UPDATE_QUERY_NAME_PREFIX, sizeof(UPDATE_QUERY_NAME_PREFIX) - 1); |
| 900 | + assert(sizeof(query) >= sizeof(UPDATE_QUERY_BEGIN)); |
| 901 | + memcpy(query, UPDATE_QUERY_BEGIN, sizeof(UPDATE_QUERY_BEGIN) - 1); |
| 902 | + |
| 903 | + for (size_t i = 0; i < MAX_QUERIES; i++) { |
| 904 | + char *iter = query + sizeof(UPDATE_QUERY_BEGIN) - 1; |
| 905 | + size_t sz = sizeof(query) - sizeof(UPDATE_QUERY_BEGIN) + 1; |
| 906 | + int c = snprintf(name + sizeof(UPDATE_QUERY_NAME_PREFIX) - 1, name_size, "%zu", i + 1); |
| 907 | + |
| 908 | + if ((size_t) c >= name_size) |
| 909 | + continue; |
| 910 | + |
| 911 | + for (size_t j = 0; j <= i; j++) { |
| 912 | + c = snprintf(iter, |
| 913 | + sz, |
| 914 | + UPDATE_QUERY_ELEM, |
| 915 | + 2 * j + 1, |
| 916 | + 2 * j + 2); |
| 917 | + |
| 918 | + if ((size_t) c >= sz) |
| 919 | + continue; |
| 920 | + |
| 921 | + iter += c; |
| 922 | + sz -= c; |
| 923 | + } |
| 924 | + |
| 925 | + assert(sz >= sizeof(UPDATE_QUERY_MIDDLE)); |
| 926 | + memcpy(iter, UPDATE_QUERY_MIDDLE, sizeof(UPDATE_QUERY_MIDDLE) - 1); |
| 927 | + iter += sizeof(UPDATE_QUERY_MIDDLE) - 1; |
| 928 | + sz -= sizeof(UPDATE_QUERY_MIDDLE) - 1; |
| 929 | + |
| 930 | + for (size_t j = 1; j <= i; j++) { |
| 931 | + c = snprintf(iter, sz, UPDATE_QUERY_ELEM2, 2 * j + 1); |
| 932 | + |
| 933 | + if ((size_t) c >= sz) |
| 934 | + continue; |
| 935 | + |
| 936 | + iter += c; |
| 937 | + sz -= c; |
| 938 | + } |
| 939 | + |
| 940 | + assert(sz >= sizeof(UPDATE_QUERY_END)); |
| 941 | + memcpy(iter, UPDATE_QUERY_END, sizeof(UPDATE_QUERY_END)); |
| 942 | + add_prepared_statement(name, query, &data->prepared_statements); |
| 943 | + } |
| 944 | + |
890 | 945 | add_prepared_statement(WORLD_TABLE_NAME, WORLD_QUERY, &data->prepared_statements);
|
891 | 946 | register_request_handler("/cached-worlds", cached_queries, hostconf, log_handle);
|
892 | 947 | register_request_handler("/db", single_query, hostconf, log_handle);
|
|
0 commit comments