static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req) { thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t, event_loop.h2o_ctx, req->conn->ctx); const size_t num_query = get_query_number(req); // MAX_QUERIES is a relatively small number, so assume no overflow in the following // arithmetic operations. assert(num_query <= MAX_QUERIES); size_t base_size = offsetof(multiple_query_ctx_t, res) + num_query * sizeof(query_result_t); base_size = ((base_size + _Alignof(query_param_t) - 1) / _Alignof(query_param_t)); base_size = base_size * _Alignof(query_param_t); const size_t num_query_in_progress = MIN(num_query, ctx->config->max_db_conn_num); size_t sz = base_size + num_query_in_progress * sizeof(query_param_t); if (do_update) { const size_t reuse_size = (num_query_in_progress - 1) * sizeof(query_param_t); const size_t update_query_len = MAX_UPDATE_QUERY_LEN(num_query); if (update_query_len > reuse_size) sz += update_query_len - reuse_size; } multiple_query_ctx_t * const query_ctx = calloc(1, sz); if (query_ctx) { multiple_query_ctx_t ** const p = h2o_mem_alloc_shared(&req->pool, sizeof(*p), cleanup_multiple_query_request); *p = query_ctx; query_ctx->ctx = ctx; query_ctx->num_query = num_query; query_ctx->req = req; query_ctx->do_update = do_update; query_ctx->use_cache = use_cache; query_ctx->query_param = (query_param_t *) ((char *) query_ctx + base_size); initialize_ids(num_query, query_ctx->res, &ctx->random_seed); if (use_cache) { fetch_from_cache(h2o_now(ctx->event_loop.h2o_ctx.loop), &ctx->global_data->world_cache, query_ctx); if (query_ctx->num_result == query_ctx->num_query) { complete_multiple_query(query_ctx); return 0; } } query_ctx->num_query_in_progress = MIN(num_query_in_progress, query_ctx->num_query - query_ctx->num_result); for (size_t i = 0; i < query_ctx->num_query_in_progress; i++) { query_ctx->query_param[i].ctx = query_ctx; // We need a copy of id because the original may be overwritten // by a completed query. query_ctx->query_param[i].id = htonl(query_ctx->res[query_ctx->num_result + i].id); query_ctx->query_param[i].id_format = 1; query_ctx->query_param[i].id_len = sizeof(query_ctx->query_param[i].id); query_ctx->query_param[i].id_pointer = (const char *) &query_ctx->query_param[i].id; query_ctx->query_param[i].param.command = WORLD_TABLE_NAME; query_ctx->query_param[i].param.nParams = 1; query_ctx->query_param[i].param.on_error = on_multiple_query_error; query_ctx->query_param[i].param.on_result = on_multiple_query_result; query_ctx->query_param[i].param.on_timeout = on_multiple_query_timeout; query_ctx->query_param[i].param.paramFormats = &query_ctx->query_param[i].id_format; query_ctx->query_param[i].param.paramLengths = &query_ctx->query_param[i].id_len; query_ctx->query_param[i].param.paramValues = &query_ctx->query_param[i].id_pointer; query_ctx->query_param[i].param.flags = IS_PREPARED; query_ctx->query_param[i].param.resultFormat = 1; if (execute_query(ctx, &query_ctx->query_param[i].param)) { query_ctx->num_query_in_progress = i; query_ctx->cleanup = true; send_service_unavailable_error(DB_REQ_ERROR, req); return 0; } } } else send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, req); return 0; }
static void do_updates(multiple_query_ctx_t *query_ctx) { char *iter = (char *) (query_ctx->query_param + 1); size_t sz = MAX_UPDATE_QUERY_LEN(query_ctx->num_result); // Sort the results to avoid database deadlock. qsort(query_ctx->res, query_ctx->num_result, sizeof(*query_ctx->res), compare_items); query_ctx->query_param->param.command = iter; query_ctx->query_param->param.nParams = 0; query_ctx->query_param->param.on_result = on_update_result; query_ctx->query_param->param.paramFormats = NULL; query_ctx->query_param->param.paramLengths = NULL; query_ctx->query_param->param.paramValues = NULL; query_ctx->query_param->param.flags = 0; query_ctx->res->random_number = 1 + get_random_number(MAX_ID, &query_ctx->ctx->random_seed); int c = snprintf(iter, sz, UPDATE_QUERY_BEGIN, query_ctx->res->id, query_ctx->res->random_number); if ((size_t) c >= sz) goto error; iter += c; sz -= c; for (size_t i = 1; i < query_ctx->num_result; i++) { query_ctx->res[i].random_number = 1 + get_random_number(MAX_ID, &query_ctx->ctx->random_seed); c = snprintf(iter, sz, UPDATE_QUERY_ELEM, query_ctx->res[i].id, query_ctx->res[i].random_number); if ((size_t) c >= sz) goto error; iter += c; sz -= c; } c = snprintf(iter, sz, UPDATE_QUERY_END); if ((size_t) c >= sz) goto error; if (execute_query(query_ctx->ctx, &query_ctx->query_param->param)) { query_ctx->cleanup = true; send_service_unavailable_error(DB_REQ_ERROR, query_ctx->req); } else query_ctx->num_query_in_progress++; return; error: query_ctx->cleanup = true; LIBRARY_ERROR("snprintf", "Truncated output."); send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, query_ctx->req); }
static void do_updates(multiple_query_ctx_t *query_ctx) { thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t, event_loop.h2o_ctx, query_ctx->req->conn->ctx); char *iter = (char *) (query_ctx->query_param + 1); size_t sz = MAX_UPDATE_QUERY_LEN(query_ctx->num_result); // Sort the results to avoid database deadlock. qsort(query_ctx->res, query_ctx->num_result, sizeof(*query_ctx->res), compare_items); query_ctx->query_param->param.command = iter; query_ctx->query_param->param.nParams = 0; query_ctx->query_param->param.on_result = on_update_result; query_ctx->query_param->param.paramFormats = NULL; query_ctx->query_param->param.paramLengths = NULL; query_ctx->query_param->param.paramValues = NULL; query_ctx->query_param->param.flags = 0; query_ctx->res->random_number = get_random_number(MAX_ID, &ctx->random_seed) + 1; int c = snprintf(iter, sz, UPDATE_QUERY_BEGIN, query_ctx->res->id, query_ctx->res->random_number); if ((size_t) c >= sz) goto error; iter += c; sz -= c; for (size_t i = 1; i < query_ctx->num_result; i++) { query_ctx->res[i].random_number = get_random_number(MAX_ID, &ctx->random_seed) + 1; c = snprintf(iter, sz, UPDATE_QUERY_ELEM, query_ctx->res[i].id, query_ctx->res[i].random_number); if ((size_t) c >= sz) goto error; iter += c; sz -= c; } c = snprintf(iter, sz, UPDATE_QUERY_END); if ((size_t) c >= sz) goto error; if (execute_query(ctx, &query_ctx->query_param->param)) send_service_unavailable_error(DB_REQ_ERROR, query_ctx->req); else { query_ctx->num_query_in_progress++; h2o_mem_addref_shared(query_ctx); } return; error: LIBRARY_ERROR("snprintf", "Truncated output."); send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, query_ctx->req); }