bool w_query_execute( w_query *query, w_root_t *root, w_query_res *res, w_query_generator generator, void *gendata) { struct w_query_ctx ctx; memset(&ctx, 0, sizeof(ctx)); ctx.query = query; ctx.root = root; memset(res, 0, sizeof(*res)); if (query->sync_timeout && !w_root_sync_to_now(root, query->sync_timeout)) { ignore_result(asprintf(&res->errmsg, "synchronization failed: %s\n", strerror(errno))); return false; } /* The first stage of execution is generation. * We generate a series of file inputs to pass to * the query executor. * * We evaluate each of the generators one after the * other. If multiple generators are used, it is * possible and expected that the same file name * will be evaluated multiple times if those generators * both emit the same file. */ // Lock the root and begin generation w_root_lock(root); res->root_number = root->number; res->ticks = root->ticks; // Evaluate the cursor for this root w_clockspec_eval(root, query->since_spec, &ctx.since); res->is_fresh_instance = !ctx.since.is_timestamp && ctx.since.clock.is_fresh_instance; if (!(res->is_fresh_instance && query->empty_on_fresh_instance)) { if (!generator) { generator = default_generators; } generator(query, root, &ctx, gendata); } w_root_unlock(root); if (ctx.wholename) { w_string_delref(ctx.wholename); } res->results = ctx.results; res->num_results = ctx.num_results; return true; }
bool w_query_execute( w_query *query, w_root_t *root, w_query_res *res, w_query_generator generator, void *gendata) { struct w_query_ctx ctx; w_perf_t sample; int64_t num_walked = 0; memset(&ctx, 0, sizeof(ctx)); ctx.query = query; ctx.root = root; memset(res, 0, sizeof(*res)); w_perf_start(&sample, "query_execute"); if (query->sync_timeout && !w_root_sync_to_now(root, query->sync_timeout)) { ignore_result(asprintf(&res->errmsg, "synchronization failed: %s\n", strerror(errno))); return false; } /* The first stage of execution is generation. * We generate a series of file inputs to pass to * the query executor. * * We evaluate each of the generators one after the * other. If multiple generators are used, it is * possible and expected that the same file name * will be evaluated multiple times if those generators * both emit the same file. */ // Lock the root and begin generation if (!w_root_lock_with_timeout(root, "w_query_execute", query->lock_timeout)) { ignore_result(asprintf(&res->errmsg, "couldn't acquire root lock within " "lock_timeout of %dms. root is " "currently busy (%s)\n", query->lock_timeout, root->lock_reason)); return false; } res->root_number = root->number; res->ticks = root->ticks; // Evaluate the cursor for this root w_clockspec_eval(root, query->since_spec, &ctx.since); res->is_fresh_instance = !ctx.since.is_timestamp && ctx.since.clock.is_fresh_instance; if (!(res->is_fresh_instance && query->empty_on_fresh_instance)) { if (!generator) { generator = default_generators; } generator(query, root, &ctx, gendata, &num_walked); } if (w_perf_finish(&sample)) { w_perf_add_root_meta(&sample, root); w_perf_add_meta(&sample, "query_execute", json_pack("{s:b, s:i, s:i, s:O}", // "fresh_instance", res->is_fresh_instance, // "num_results", ctx.num_results, // "num_walked", num_walked, // "query", ctx.query->query_spec // )); w_perf_log(&sample); } w_root_unlock(root); w_perf_destroy(&sample); if (ctx.wholename) { w_string_delref(ctx.wholename); } if (ctx.last_parent_path) { w_string_delref(ctx.last_parent_path); } res->results = ctx.results; res->num_results = ctx.num_results; return true; }