[ovs-dev] [PATCH monitor_cond V2 10/12] lib: add monitor_cond_update to idl session

Andy Zhou azhou at ovn.org
Fri Jan 22 03:55:45 UTC 2016


On Sat, Jan 16, 2016 at 12:16 AM, Liran Schour <lirans at il.ibm.com> wrote:

> Implement function for changing condition in an idl session.
>
> Signed-off-by: Liran Schour <lirans at il.ibm.com>
>

Tabs are used in this file.


> ---
>  lib/ovsdb-idl-provider.h |  33 ++++
>  lib/ovsdb-idl.c          | 399
> ++++++++++++++++++++++++++++++++++++++++++++++-
>  lib/ovsdb-idl.h          |  13 ++
>  3 files changed, 444 insertions(+), 1 deletion(-)
>
> diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
> index 190acca..2722922 100644
> --- a/lib/ovsdb-idl-provider.h
> +++ b/lib/ovsdb-idl-provider.h
> @@ -51,6 +51,38 @@ struct ovsdb_idl_column {
>      void (*unparse)(struct ovsdb_idl_row *);
>  };
>
> +
> +/* These list is ordered in ascending order of the fraction of tables row
> that
> + * they are (heuristically) expected to leave in query results. */
> +#define OVSDB_IDL_FUNCTIONS                         \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_FALSE, "false")            \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_TRUE, "true")              \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_EQ, "==")                  \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_INCLUDES, "includes")      \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_LE, "<=")                  \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_LT, "<")                   \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_GE, ">=")                  \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_GT, ">")                   \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_EXCLUDES, "excludes")      \
> +    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_NE, "!=")
> +
> +enum ovsdb_idl_function {
> +#define OVSDB_IDL_FUNCTION(ENUM, NAME) ENUM,
> +    OVSDB_IDL_FUNCTIONS
> +#undef OVSDB_IDL_FUNCTION
> +};
> +
> +struct ovsdb_idl_clause {
> +    enum ovsdb_idl_function function;
> +    const struct ovsdb_idl_column *column;
> +    struct ovsdb_datum arg;
> +};
> +
> +struct ovsdb_idl_condition {
> +    struct ovsdb_idl_clause *clauses;
> +    size_t n_clauses;
> +};
> +
>  struct ovsdb_idl_table_class {
>      char *name;
>      bool is_root;
> @@ -70,6 +102,7 @@ struct ovsdb_idl_table {
>      struct ovsdb_idl *idl;   /* Containing idl. */
>      unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX];
>      struct ovs_list track_list; /* Tracked rows
> (ovsdb_idl_row.track_node). */
> +    struct ovsdb_idl_condition condition;
>  };
>
>  struct ovsdb_idl_class {
> diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
> index 1b8731e..c3550b9 100644
> --- a/lib/ovsdb-idl.c
> +++ b/lib/ovsdb-idl.c
> @@ -261,6 +261,7 @@ ovsdb_idl_create(const char *remote, const struct
> ovsdb_idl_class *class,
>              = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
>              = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
>          table->idl = idl;
> +        ovsdb_idl_condition_init(&table->condition);
>      }
>
>      idl->state_seqno = UINT_MAX;
> @@ -650,6 +651,397 @@ ovsdb_idl_add_table(struct ovsdb_idl *idl,
>      OVS_NOT_REACHED();
>  }
>
> +static const struct ovsdb_idl_table_class *
> +ovsdb_idl_table_name_to_class(struct ovsdb_idl *idl, const char *name)
> +{
> +    int i;
> +    struct ovsdb_idl_table *table;
> +
> +    /* Ensure table are being replicated */
> +    for (i = 0; i < idl->class->n_tables; i++) {
> +        table = &idl->tables[i];
> +
> +        if (strcmp(table->class->name, name) == 0) {
> +            return table->class;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static const struct ovsdb_idl_column *
> +ovsdb_table_get_column(const struct ovsdb_idl_table_class *tc, const char
> *name)
> +{
> +    int i;
> +
> +    for (i = 0; i < tc->n_columns; i++) {
> +        if(!strcmp(tc->columns[i].name, name)) {
> +            return &tc->columns[i];
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static struct ovsdb_error *
> +ovsdb_idl_function_from_string(const char *name,
> +                               enum ovsdb_idl_function *function)
> +{
> +#define OVSDB_IDL_FUNCTION(ENUM, NAME)              \
> +    if (!strcmp(name, NAME)) {                  \
> +        *function = ENUM;                       \
> +        return NULL;                            \
> +    }
> +    OVSDB_IDL_FUNCTIONS;
> +#undef OVSDB_IDL_FUNCTION
> +
> +    return ovsdb_syntax_error(NULL, "unknown function",
> +                              "No function named %s.", name);
> +}
> +
> +static const char *
> +ovsdb_idl_function_to_string(enum ovsdb_idl_function function)
> +{
> +    switch (function) {
> +#define OVSDB_IDL_FUNCTION(ENUM, NAME) case ENUM: return NAME;
> +        OVSDB_IDL_FUNCTIONS;
> +#undef OVSDB_IDL_FUNCTION
> +    }
> +
> +    return NULL;
> +}
> +
> +static struct json *
> +ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause *clause)
> +{
> +    if (clause->function != OVSDB_IDL_F_TRUE &&
> +        clause->function != OVSDB_IDL_F_FALSE) {
> +        const char *function =
> ovsdb_idl_function_to_string(clause->function);
> +
> +        return
> json_array_create_3(json_string_create(clause->column->name),
> +                                   json_string_create(function),
> +                                   ovsdb_datum_to_json(&clause->arg,
> +
>  &clause->column->type));
> +    }
> +
> +    return json_boolean_create(clause->function == OVSDB_IDL_F_TRUE ?
> +                              true : false);
> +}
> +
> +static void
> +ovsdb_idl_clause_free(struct ovsdb_idl_clause *clause)
> +{
> +    if (clause->function != OVSDB_IDL_F_TRUE &&
> +        clause->function != OVSDB_IDL_F_FALSE) {
> +       ovsdb_datum_destroy(&clause->arg, &clause->column->type);
> +    }
> +}
> +
> +void
> +ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < cnd->n_clauses; i++) {
> +        ovsdb_idl_clause_free(&cnd->clauses[i]);
> +    }
> +    free(cnd->clauses);
> +    cnd->n_clauses = 0;
> +}
> +
> +void
> +ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd)
> +{
> +    cnd->clauses = NULL;
> +    cnd->n_clauses = 0;
> +}
> +
> +static int
> +compare_clauses(const void *a_, const void *b_)
> +{
> +    const struct ovsdb_idl_clause *a = a_;
> +    const struct ovsdb_idl_clause *b = b_;
> +
> +    if (a->function != b->function) {
> +        return a->function < b->function ? -1 : 1;
> +    } else if (a->function == OVSDB_IDL_F_TRUE ||
> +               a->function == OVSDB_IDL_F_FALSE) {
> +        return 0;
> +    } else if (strcmp(a->column->name, b->column->name)) {
> +        return strcmp(a->column->name, b->column->name);
> +    } else {
> +        return ovsdb_datum_compare_3way(&a->arg, &b->arg,
> &a->column->type);
> +    }
> +    OVS_NOT_REACHED();
> +}
> +
> +static int
> +ovsdb_idl_clause_exists(const struct ovsdb_idl_condition *cnd,
> +                        const struct ovsdb_idl_clause *clause)
> +{
> +    size_t i;
> +
> +    for (i=0; i < cnd->n_clauses; i++) {
> +        if(!compare_clauses(&cnd->clauses[i], clause)) {
> +            return i;
> +        }
> +    }
> +
> +    return -1;
> +}
> +
> +static void
> +ovsdb_idl_clone_clause(struct ovsdb_idl_clause *new,
> +                       struct ovsdb_idl_clause *old)
> +{
> +    new->function = old->function;
> +    if (new->function == OVSDB_IDL_F_TRUE ||
> +        new->function ==OVSDB_IDL_F_FALSE) {
> +        return;
> +    }
> +    new->column = old->column;
> +    ovsdb_datum_clone(&new->arg,
> +                     &old->arg,
> +                     &old->column->type);
> +}
> +
> +static void
> +ovsdb_idl_condition_add(struct ovsdb_idl_condition *to,
> +                        const struct ovsdb_idl_condition *add)
> +{
> +    size_t i, count = 0;
> +    struct ovsdb_idl_clause *clauses;
> +    unsigned long int *clause_map =
> xzalloc(bitmap_n_bytes(add->n_clauses));
> +    int index = to->n_clauses;;
> +
> +    for (i = 0; i < add->n_clauses; i++) {
> +        if (ovsdb_idl_clause_exists(to, &add->clauses[i]) == -1) {
> +           bitmap_set1(clause_map, i);
> +           count++;
> +       }
> +    }
> +
> +    if (!count) {
> +        free(clause_map);
> +        return;
> +    }
> +    clauses = xzalloc((to->n_clauses + count) * sizeof *clauses);
> +
> +    for (i = 0; i < to->n_clauses; i++) {
> +        ovsdb_idl_clone_clause(&clauses[i], &to->clauses[i]);
> +        ovsdb_idl_clause_free(&to->clauses[i]);
> +    }
> +
> +    for (i = 0; i < add->n_clauses; i++) {
> +        if (bitmap_is_set(clause_map, i)) {
> +           ovsdb_idl_clone_clause(&clauses[index++], &add->clauses[i]);
> +        }
> +    }
> +
> +    free(to->clauses);
> +    free(clause_map);
> +    to->clauses = clauses;
> +    to->n_clauses += count;
> +}
> +
> +static struct json *
> +ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
> +{
> +    struct json **clauses;
> +    size_t i;
> +
> +    clauses = xmalloc(cnd->n_clauses * sizeof *clauses);
> +    for (i = 0; i < cnd->n_clauses; i++) {
> +        clauses[i] = ovsdb_idl_clause_to_json(&cnd->clauses[i]);
> +    }
> +    return json_array_create(clauses, cnd->n_clauses);
> +}
> +
> +static struct ovsdb_error *
> +ovsdb_idl_clause_from_json(const struct ovsdb_idl_table_class *tc,
> +                           const struct json *json,
> +                           struct ovsdb_idl_clause *clause)
> +{
> +    const struct json_array *array;
> +    struct ovsdb_error *error;
> +    const char *function_name;
> +    const char *column_name;
> +    struct ovsdb_type type;
> +
> +    if (json->type == JSON_TRUE || json->type == JSON_FALSE) {
> +       /* column and arg fields are not being used with boolean function
> */
> +       function_name = (json->type == JSON_TRUE) ? "true" : "false";
> +       error = ovsdb_idl_function_from_string(function_name,
> &clause->function);
> +
> +       return error;
> +    }
> +
> +    if (json->type != JSON_ARRAY
> +        || json->u.array.n != 3
> +        || json->u.array.elems[0]->type != JSON_STRING
> +        || json->u.array.elems[1]->type != JSON_STRING) {
> +        return ovsdb_syntax_error(json, NULL, "Parse error in
> condition.");
> +    }
> +    array = json_array(json);
> +
> +    column_name = json_string(array->elems[0]);
> +    clause->column = ovsdb_table_get_column(tc, column_name);
> +    if (!clause->column) {
> +        return ovsdb_syntax_error(json, "unknown column",
> +                                  "No column %s in table %s.",
> +                                  column_name, tc->name);
> +    }
> +    type = clause->column->type;
> +
> +    function_name = json_string(array->elems[1]);
> +    error = ovsdb_idl_function_from_string(function_name,
> &clause->function);
> +    if (error) {
> +        return error;
> +    }
> +
> +    /* Type-check and relax restrictions on 'type' if appropriate.  */
> +    switch (clause->function) {
> +    case OVSDB_IDL_F_LT:
> +    case OVSDB_IDL_F_LE:
> +    case OVSDB_IDL_F_GT:
> +    case OVSDB_IDL_F_GE:
> +        /* Allow these operators for types with n_min == 0, n_max == 1.
> +         * (They will always be "false" if the value is missing.) */
> +        if (!(ovsdb_type_is_scalar(&type)
> +            || ovsdb_type_is_optional_scalar(&type))
> +            || (type.key.type != OVSDB_TYPE_INTEGER
> +                && type.key.type != OVSDB_TYPE_REAL)) {
> +            char *s = ovsdb_type_to_english(&type);
> +            error = ovsdb_syntax_error(
> +                json, NULL, "Type mismatch: \"%s\" operator may not be "
> +                "applied to column %s of type %s.",
> +                ovsdb_idl_function_to_string(clause->function),
> +                clause->column->name, s);
> +            free(s);
> +            return error;
> +        }
> +        break;
> +    case OVSDB_IDL_F_TRUE:
> +    case OVSDB_IDL_F_FALSE:
> +    case OVSDB_IDL_F_EQ:
> +    case OVSDB_IDL_F_NE:
> +        break;
> +
> +    case OVSDB_IDL_F_EXCLUDES:
> +        if (!ovsdb_type_is_scalar(&type)) {
> +            type.n_min = 0;
> +            type.n_max = UINT_MAX;
> +        }
> +        break;
> +
> +    case OVSDB_IDL_F_INCLUDES:
> +        if (!ovsdb_type_is_scalar(&type)) {
> +            type.n_min = 0;
> +        }
> +        break;
> +    }
> +    return ovsdb_datum_from_json(&clause->arg, &type, array->elems[2],
> NULL);
> +}
> +
> +struct ovsdb_error *
> +ovsdb_idl_condition_from_json(struct ovsdb_idl *idl,
> +                              const char *table_name,
> +                              const struct json *json,
> +                              struct ovsdb_idl_condition *cnd)
> +{
> +    const struct ovsdb_idl_table_class *table_class =
> +        ovsdb_idl_table_name_to_class(idl, table_name);
> +    const struct json_array *array = json_array(json);
> +    struct ovsdb_error *error;
> +    size_t i;
> +
> +    if (!table_class) {
> +        error = ovsdb_syntax_error(NULL, NULL, "Error finding table %s ",
> +                                   table_name);
> +        return error;
> +    }
> +
> +    cnd->clauses = xzalloc(array->n * sizeof *cnd->clauses);
> +    cnd->n_clauses = 0;
> +    for (i = 0; i < array->n; i++) {
> +        struct ovsdb_error *error;
> +        error = ovsdb_idl_clause_from_json(table_class, array->elems[i],
> +                                           &cnd->clauses[i]);
> +        if (error) {
> +            ovsdb_idl_condition_destroy(cnd);
> +            cnd->clauses = NULL;
> +            cnd->n_clauses = 0;
> +            return error;
> +        }
> +        cnd->n_clauses++;
> +    }
> +
> +    return NULL;
> +}
> +
> +static void
> +ovsdb_idl_send_cond_update__(struct ovsdb_idl *idl,
> +                             struct ovsdb_idl_table *table,
> +                             const struct ovsdb_idl_condition *add,
> +                             const struct ovsdb_idl_condition *remove)
> +{
> +    char uuid[UUID_LEN + 1];
> +    struct json *monitor_cond_update_requests = json_object_create();
> +    struct json *monitor_cond_update_request = json_object_create();
> +    struct json *added = ovsdb_idl_condition_to_json(add);
> +    struct json *removed = ovsdb_idl_condition_to_json(remove);
> +    struct json *params, *json_uuid;
> +    struct jsonrpc_msg *request;
> +
> +    json_object_put(monitor_cond_update_request, "added", added);
> +    json_object_put(monitor_cond_update_request, "removed", removed);
> +    json_object_put(monitor_cond_update_requests,
> +                    table->class->name,
> +                    json_array_create_1(monitor_cond_update_request));
> +
> +    snprintf(uuid, sizeof uuid, UUID_FMT,
> +             UUID_ARGS(&idl->uuid));
> +    json_uuid = json_string_create(uuid);
> +
> +    /* Create a new uuid */
> +    uuid_generate(&idl->uuid);
>
How should we handle any on going update2 message of the old condition?

+    snprintf(uuid, sizeof uuid, UUID_FMT,
> +             UUID_ARGS(&idl->uuid));
> +    params = json_array_create_3(json_uuid, json_string_create(uuid),
> +                                 monitor_cond_update_requests);
> +
> +    request = jsonrpc_create_request("monitor_cond_update", params, NULL);
> +    jsonrpc_session_send(idl->session, request);
> +}
> +
> +/* Add conditions to the replicated tables. Ensure that tables are added
> to the
> + * replication.
> + */
> +bool
> +ovsdb_idl_cond_update(struct ovsdb_idl *idl,
> +                      const char *table_name,
> +                      const struct ovsdb_idl_condition *add,
> +                      const struct ovsdb_idl_condition *remove)
> +{
> +    const struct ovsdb_idl_table_class *table_class =
> +        ovsdb_idl_table_name_to_class(idl, table_name);
> +    struct ovsdb_idl_table *table;
> +
> +    if (table_class == NULL) {
> +        return false;
> +    }
> +    table = ovsdb_idl_table_from_class(idl, table_class);
> +
> +    if (jsonrpc_session_is_connected(idl->session)) {
> +        ovsdb_idl_send_cond_update__(idl, table, add, remove);
> +    } else {
> +        if (remove && remove->n_clauses > 0) {
> +            /* No remove conditions on an unconnected session */
> +            return false;
> +        }
> +        ovsdb_idl_condition_add(&table->condition, add);
> +    }
> +    return true;
> +}
> +
>  /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
>   *
>   * This function should be called between ovsdb_idl_create() and the
> first call
> @@ -949,7 +1341,7 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl
> *idl,
>      for (i = 0; i < idl->class->n_tables; i++) {
>          const struct ovsdb_idl_table *table = &idl->tables[i];
>          const struct ovsdb_idl_table_class *tc = table->class;
> -        struct json *monitor_request, *columns;
> +        struct json *monitor_request, *columns, *where;
>          const struct sset *table_schema;
>          size_t j;
>
> @@ -987,6 +1379,11 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl
> *idl,
>
>              monitor_request = json_object_create();
>              json_object_put(monitor_request, "columns", columns);
> +            if (!strcmp(method, "monitor_cond") &&
> +                table->condition.n_clauses > 0) {
> +                where = ovsdb_idl_condition_to_json(&table->condition);
> +                json_object_put(monitor_request, "where", where);
> +            }
>              json_object_put(monitor_requests, tc->name, monitor_request);
>          }
>      }
> diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
> index 1cbaf35..413da7d 100644
> --- a/lib/ovsdb-idl.h
> +++ b/lib/ovsdb-idl.h
> @@ -45,6 +45,7 @@ struct ovsdb_idl_class;
>  struct ovsdb_idl_row;
>  struct ovsdb_idl_column;
>  struct ovsdb_idl_table_class;
> +struct ovsdb_idl_condition;
>  struct uuid;
>
>  struct ovsdb_idl *ovsdb_idl_create(const char *remote,
> @@ -276,5 +277,17 @@ struct ovsdb_idl_loop {
>  void ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *);
>  struct ovsdb_idl_txn *ovsdb_idl_loop_run(struct ovsdb_idl_loop *);
>  void ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *);
> +#define OVSDB_IDL_CONDITION_INITIALIZER { NULL, 0 }
> +void ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd);
> +void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd);
> +struct ovsdb_error *
> +ovsdb_idl_condition_from_json(struct ovsdb_idl *idl,
> +                              const char *table_name,
> +                              const struct json *json,
> +                              struct ovsdb_idl_condition *cnd);
> +bool ovsdb_idl_cond_update(struct ovsdb_idl *idl,
> +                           const char *table_name,
> +                           const struct ovsdb_idl_condition *add,
> +                           const struct ovsdb_idl_condition *remove);
>
>  #endif /* ovsdb-idl.h */
> --
> 2.1.4
>
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>



More information about the dev mailing list