Exemple #1
0
void send_error_response(struct watchman_client *client,
    const char *fmt, ...)
{
  char buf[WATCHMAN_NAME_MAX];
  va_list ap;
  json_t *resp = make_response();
  json_t *errstr;

  va_start(ap, fmt);
  vsnprintf(buf, sizeof(buf), fmt, ap);
  va_end(ap);

  errstr = typed_string_to_json(buf, W_STRING_MIXED);
  set_prop(resp, "error", errstr);

  json_incref(errstr);
  w_perf_add_meta(&client->perf_sample, "error", errstr);

  if (client->current_command) {
    char *command = NULL;
    command = json_dumps(client->current_command, 0);
    w_log(W_LOG_ERR, "send_error_response: %s failed: %s\n",
        command, buf);
    free(command);
  } else {
    w_log(W_LOG_ERR, "send_error_response: %s\n", buf);
  }

  send_and_dispose_response(client, resp);
}
Exemple #2
0
bool dispatch_command(struct watchman_client *client, json_t *args, int mode)
{
  struct watchman_command_handler_def *def;
  char *errmsg = NULL;
  bool result = false;
  char sample_name[128];

  // Stash a reference to the current command to make it easier to log
  // the command context in some of the error paths
  client->current_command = args;
  json_incref(client->current_command);

  def = lookup(args, &errmsg, mode);

  if (!def) {
    send_error_response(client, "%s", errmsg);
    goto done;
  }

  if (poisoned_reason && (def->flags & CMD_POISON_IMMUNE) == 0) {
    send_error_response(client, "%s", poisoned_reason);
    goto done;
  }

  if (!client->client_is_owner && (def->flags & CMD_ALLOW_ANY_USER) == 0) {
    send_error_response(client, "you must be the process owner to execute '%s'",
                        def->name);
    return false;
  }

  w_log(W_LOG_DBG, "dispatch_command: %s\n", def->name);
  snprintf(sample_name, sizeof(sample_name), "dispatch_command:%s", def->name);
  w_perf_start(&client->perf_sample, sample_name);
  w_perf_set_wall_time_thresh(
      &client->perf_sample,
      cfg_get_double(NULL, "slow_command_log_threshold_seconds", 1.0));

  result = true;
  def->func(client, args);

  if (w_perf_finish(&client->perf_sample)) {
    json_incref(args);
    w_perf_add_meta(&client->perf_sample, "args", args);
    w_perf_log(&client->perf_sample);
  } else {
    w_log(W_LOG_DBG, "dispatch_command: %s (completed)\n", def->name);
  }

done:
  free(errmsg);
  json_decref(client->current_command);
  client->current_command = NULL;
  w_perf_destroy(&client->perf_sample);
  return result;
}
Exemple #3
0
void w_perf_add_root_meta(w_perf_t *perf, w_root_t *root) {
  // Note: if the root lock isn't held, we may read inaccurate numbers for
  // some of these properties.  We're ok with that, and don't want to force
  // the root lock to be re-acquired just for this.

  // The funky comments at the end of the line force clang-format to keep the
  // elements on lines of their own
  w_perf_add_meta(perf, "root",
                  json_pack("{s:o, s:i, s:i, s:i, s:b, s:u}",          //
                            "path", w_string_to_json(root->root_path), //
                            "recrawl_count", root->recrawl_count,      //
                            "number", root->number,                    //
                            "ticks", root->ticks,                      //
                            "case_sensitive", root->case_sensitive,    //
                            "watcher", root->watcher_ops->name         //
                            ));
}
Exemple #4
0
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;
}