示例#1
0
void w_query_delref(w_query *query)
{
  uint32_t i;

  if (!w_refcnt_del(&query->refcnt)) {
    return;
  }

  for (i = 0; i < query->npaths; i++) {
    if (query->paths[i].name) {
      w_string_delref(query->paths[i].name);
    }
  }
  free(query->paths);

  if (query->since_spec) {
    w_clockspec_free(query->since_spec);
  }

  if (query->expr) {
    w_query_expr_delref(query->expr);
  }

  free(query);
}
示例#2
0
static void update_subscription_ticks(struct watchman_client_subscription *sub,
    w_query_res *res) {
  // create a new spec that will be used the next time
  if (sub->query->since_spec) {
    w_clockspec_free(sub->query->since_spec);
  }
  sub->query->since_spec = w_clockspec_new_clock(res->root_number, res->ticks);
}
示例#3
0
void w_assess_trigger(w_root_t *root, struct watchman_trigger_command *cmd)
{
  w_query_res res;
  struct w_clockspec *since_spec = cmd->query->since_spec;

  if (since_spec && since_spec->tag == w_cs_clock) {
    w_log(W_LOG_DBG, "running trigger rules! since %" PRIu32 "\n",
        since_spec->clock.ticks);
  } else {
    w_log(W_LOG_DBG, "running trigger rules!\n");
  }

  // Triggers never need to sync explicitly; we are only dispatched
  // at settle points which are by definition sync'd to the present time
  cmd->query->sync_timeout = 0;
  if (!w_query_execute(cmd->query, root, &res, trigger_generator, cmd)) {
    w_log(W_LOG_ERR, "error running trigger query: %s", res.errmsg);
    w_query_result_free(&res);
    return;
  }

  w_log(W_LOG_DBG, "trigger generated %" PRIu32 " results\n",
      res.num_results);

  // create a new spec that will be used the next time
  cmd->query->since_spec = w_clockspec_new_clock(res.root_number, res.ticks);

  if (res.num_results) {
    spawn_command(root, cmd, &res, since_spec);
  }

  if (since_spec) {
    w_clockspec_free(since_spec);
    since_spec = NULL;
  }

  w_query_result_free(&res);
}
示例#4
0
static json_t *build_subscription_results(
    struct watchman_client_subscription *sub,
    w_root_t *root)
{
  w_query_res res;
  json_t *response;
  json_t *file_list;
  char clockbuf[128];
  struct w_clockspec *since_spec = sub->query->since_spec;

  if (since_spec && since_spec->tag == w_cs_clock) {
    w_log(W_LOG_DBG, "running subscription rules! since %" PRIu32 "\n",
        since_spec->clock.ticks);
  } else {
    w_log(W_LOG_DBG, "running subscription rules!\n");
  }

  // Subscriptions never need to sync explicitly; we are only dispatched
  // at settle points which are by definition sync'd to the present time
  sub->query->sync_timeout = 0;
  if (!w_query_execute(sub->query, root, &res, subscription_generator, sub)) {
    w_log(W_LOG_ERR, "error running subscription query: %s", res.errmsg);
    w_query_result_free(&res);
    return NULL;
  }

  w_log(W_LOG_DBG, "subscription generated %" PRIu32 " results\n",
      res.num_results);

  if (res.num_results == 0) {
    w_query_result_free(&res);
    return NULL;
  }

  file_list = w_query_results_to_json(&sub->field_list,
      res.num_results, res.results);
  w_query_result_free(&res);

  response = make_response();

  // It is way too much of a hassle to try to recreate the clock value if it's
  // not a relative clock spec, and it's only going to happen on the first run
  // anyway, so just skip doing that entirely.
  if (since_spec && since_spec->tag == w_cs_clock &&
      clock_id_string(since_spec->clock.root_number, since_spec->clock.ticks,
                      clockbuf, sizeof(clockbuf))) {
    set_prop(response, "since", json_string_nocheck(clockbuf));
  }
  if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) {
    set_prop(response, "clock", json_string_nocheck(clockbuf));
  }
  // create a new spec that will be used the next time
  if (since_spec) {
    w_clockspec_free(since_spec);
    since_spec = NULL;
  }
  sub->query->since_spec = w_clockspec_new_clock(res.root_number, res.ticks);

  set_prop(response, "is_fresh_instance", json_boolean(res.is_fresh_instance));
  set_prop(response, "files", file_list);
  set_prop(response, "root", json_string(root->root_path->buf));
  set_prop(response, "subscription", json_string(sub->name->buf));

  return response;
}
示例#5
0
w_query_expr *w_expr_since_parser(w_query *query, json_t *term)
{
  json_t *jval;

  struct w_clockspec *spec;
  struct since_term *sterm;
  int selected_field = SINCE_OCLOCK;
  const char *fieldname = "oclock";

  if (!json_is_array(term)) {
    query->errmsg = strdup("\"since\" term must be an array");
    return NULL;
  }

  if (json_array_size(term) < 2 || json_array_size(term) > 3) {
    query->errmsg = strdup("\"since\" term has invalid number of parameters");
    return NULL;
  }

  jval = json_array_get(term, 1);
  spec = w_clockspec_parse(jval);
  if (!spec) {
    query->errmsg = strdup("invalid clockspec for \"since\" term");
    return NULL;
  }
  if (spec->tag == w_cs_named_cursor) {
    query->errmsg = strdup("named cursors are not allowed in \"since\" terms");
    goto fail;
  }

  jval = json_array_get(term, 2);
  if (jval) {
    int i;
    bool valid = false;

    fieldname = json_string_value(jval);
    if (!fieldname) {
      query->errmsg = strdup("field name for \"since\" term must be a string");
      goto fail;
    }

    for (i = 0; allowed_fields[i].label; i++) {
      if (!strcmp(allowed_fields[i].label, fieldname)) {
        selected_field = allowed_fields[i].value;
        valid = true;
        break;
      }
    }

    if (!valid) {
      ignore_result(asprintf(&query->errmsg,
          "invalid field name \"%s\" for \"since\" term",
          fieldname));
      goto fail;
    }
  }

  switch (selected_field) {
    case SINCE_CTIME:
    case SINCE_MTIME:
      if (spec->tag != w_cs_timestamp) {
        ignore_result(asprintf(&query->errmsg,
            "field \"%s\" requires a timestamp value "
            "for comparison in \"since\" term",
            fieldname));
        goto fail;
      }
      break;
    case SINCE_OCLOCK:
    case SINCE_CCLOCK:
      /* we'll work with clocks or timestamps */
      break;
  }

  sterm = calloc(1, sizeof(*sterm));
  if (!sterm) {
    query->errmsg = strdup("out of memory");
    goto fail;
  }

  sterm->spec = spec;
  sterm->field = selected_field;

  return w_query_expr_new(eval_since, dispose_since, sterm);

fail:
  w_clockspec_free(spec);
  return NULL;
}
示例#6
0
static void dispose_since(void *data)
{
  struct since_term *term = data;
  w_clockspec_free(term->spec);
  free(data);
}