diff --git a/ovsdb/execution.c b/ovsdb/execution.c index 38cdcd166..99856f8fe 100644 --- a/ovsdb/execution.c +++ b/ovsdb/execution.c @@ -459,7 +459,7 @@ ovsdb_execute_select(struct ovsdb_execution *x, struct ovsdb_parser *parser, if (!error) { struct ovsdb_row_set rows = OVSDB_ROW_SET_INITIALIZER; - ovsdb_query_distinct(table, &condition, &columns, &rows); + ovsdb_query_distinct(table, &condition, &columns, &rows, x->txn); ovsdb_row_set_sort(&rows, &sort); json_object_put(result, "rows", ovsdb_row_set_to_json(&rows, &columns)); @@ -545,8 +545,8 @@ ovsdb_execute_update(struct ovsdb_execution *x, struct ovsdb_parser *parser, ur.row = row; ur.columns = &columns; if (ovsdb_rbac_update(x->db, table, &columns, &condition, x->role, - x->id)) { - ovsdb_query(table, &condition, update_row_cb, &ur); + x->id, x->txn)) { + ovsdb_query(table, &condition, update_row_cb, &ur, x->txn); } else { error = ovsdb_perm_error("RBAC rules for client \"%s\" role " "\"%s\" prohibit modification of " @@ -626,7 +626,7 @@ ovsdb_execute_mutate(struct ovsdb_execution *x, struct ovsdb_parser *parser, json_integer_create(hmap_count(&table->rows))); } else { size_t row_count = 0; - ovsdb_query(table, &condition, count_row_cb, &row_count); + ovsdb_query(table, &condition, count_row_cb, &row_count, x->txn); json_object_put(result, "count", json_integer_create(row_count)); } @@ -636,8 +636,8 @@ ovsdb_execute_mutate(struct ovsdb_execution *x, struct ovsdb_parser *parser, mr.mutations = &mutations; mr.error = &error; if (ovsdb_rbac_mutate(x->db, table, &mutations, &condition, x->role, - x->id)) { - ovsdb_query(table, &condition, mutate_row_cb, &mr); + x->id, x->txn)) { + ovsdb_query(table, &condition, mutate_row_cb, &mr, x->txn); } else { error = ovsdb_perm_error("RBAC rules for client \"%s\" role " "\"%s\" prohibit mutate operation on " @@ -693,8 +693,9 @@ ovsdb_execute_delete(struct ovsdb_execution *x, struct ovsdb_parser *parser, dr.table = table; dr.txn = x->txn; - if (ovsdb_rbac_delete(x->db, table, &condition, x->role, x->id)) { - ovsdb_query(table, &condition, delete_row_cb, &dr); + if (ovsdb_rbac_delete(x->db, table, &condition, x->role, x->id, + x->txn)) { + ovsdb_query(table, &condition, delete_row_cb, &dr, x->txn); } else { error = ovsdb_perm_error("RBAC rules for client \"%s\" role " "\"%s\" prohibit row deletion from " @@ -813,7 +814,8 @@ ovsdb_execute_wait(struct ovsdb_execution *x, struct ovsdb_parser *parser, aux.actual = &actual; aux.expected = &expected; aux.equal = &equal; - ovsdb_query(table, &condition, ovsdb_execute_wait_query_cb, &aux); + ovsdb_query(table, &condition, ovsdb_execute_wait_query_cb, &aux, + x->txn); if (equal) { /* We know that every row in 'actual' is also in 'expected'. We * also know that all of the rows in 'actual' are distinct and that diff --git a/ovsdb/query.c b/ovsdb/query.c index eebe56412..f13735c42 100644 --- a/ovsdb/query.c +++ b/ovsdb/query.c @@ -21,32 +21,174 @@ #include "condition.h" #include "row.h" #include "table.h" +#include "transaction.h" + +struct txn_state { + const struct ovsdb_condition *cnd; + struct ovsdb_table *table; + bool match; +}; + +static bool +search_txn(const struct ovsdb_row *old, const struct ovsdb_row *new, + const unsigned long int *changed OVS_UNUSED, void *aux) +{ + struct txn_state *ts = aux; + + if (ts->match) { + return false; + } + + if (new && new->table == ts->table) { + if (ovsdb_condition_match_every_clause(new, ts->cnd)) { + ts->match = true; + return false; + } + } + + if (old && old->table == ts->table) { + if (ovsdb_condition_match_every_clause(old, ts->cnd)) { + ts->match = true; + return false; + } + } + + return true; +} + +static bool +ovsdb_query_index(struct ovsdb_table *table, + const struct ovsdb_condition *cnd, + const struct ovsdb_row **out, + const struct ovsdb_txn *txn) +{ + size_t n_fields = shash_count(&table->schema->columns); + struct ovsdb_row *row; + bool ret = false; + + if (txn) { + /* Check the transaction first. If a modified row matches the + * conditions then bail out before an index search. There are a lot of + * different possible conditions and including support for returning + * mid-transaction rows adds a lot of complications. */ + + struct txn_state ts = { + .cnd = cnd, + .table = table, + .match = false, + }; + + ovsdb_txn_for_each_change(txn, search_txn, &ts); + + if (ts.match) { + return false; + } + } + + /* Construct a mock row. */ + row = xzalloc(sizeof *row + sizeof *row->fields * n_fields); + row->table = table; + + for (size_t c = 0; c < cnd->n_clauses; c++) { + const struct ovsdb_clause *cnd_cls = &cnd->clauses[c]; + + if (cnd_cls->function != OVSDB_F_EQ) { + goto done; + } + + row->fields[cnd_cls->index] = cnd_cls->arg; + } + + /* Per index search. */ + for (size_t idx = 0; idx < table->schema->n_indexes; idx++) { + const struct ovsdb_column_set *index = &table->schema->indexes[idx]; + size_t matches = 0; + size_t hash; + + if (index->n_columns > cnd->n_clauses) { + /* Only index search if condition counts are greater or equal to + * index length. */ + continue; + } + + hash = 0; + + /* The conditions may not be in the same order as the index. */ + for (size_t i = 0; i < index->n_columns && matches == i; i++) { + const struct ovsdb_column *idx_col = index->columns[i]; + + if (row->fields[idx_col->index].n) { + hash = ovsdb_datum_hash(&row->fields[idx_col->index], + &idx_col->type, hash); + matches++; + } + } + + if (matches != index->n_columns) { + continue; + } + + /* The index matches so a linear search isn't needed. */ + ret = true; + + /* The return code doesn't matter in this case, because this function + * returns true on a suitable index instead of a matching key. */ + *out = ovsdb_index_search(&table->indexes[idx], row, idx, hash); + + /* If the index has fewer rows than the condition, verify that all + * conditions are true. */ + if (*out && index->n_columns != cnd->n_clauses) { + if (!ovsdb_condition_match_every_clause(*out, cnd)) { + /* Non-index condition doesn't match. */ + *out = NULL; + } + } + + /* In the case that there was a matching index but no matching row, the + * index check is still considered to be a success. */ + break; + } + +done: + free(row); + return ret; +} void ovsdb_query(struct ovsdb_table *table, const struct ovsdb_condition *cnd, - bool (*output_row)(const struct ovsdb_row *, void *aux), void *aux) + bool (*output_row)(const struct ovsdb_row *, void *aux), void *aux, + const struct ovsdb_txn *txn) { + const struct ovsdb_row *row = NULL; + if (cnd->n_clauses > 0 && cnd->clauses[0].column->index == OVSDB_COL_UUID && cnd->clauses[0].function == OVSDB_F_EQ) { /* Optimize the case where the query has a clause of the form "uuid == * ", since we have an index on UUID. */ - const struct ovsdb_row *row; row = ovsdb_table_get_row(table, &cnd->clauses[0].arg.keys[0].uuid); if (row && row->table == table && ovsdb_condition_match_every_clause(row, cnd)) { output_row(row, aux); } - } else { - /* Linear scan. */ - const struct ovsdb_row *row; + return; + } - HMAP_FOR_EACH_SAFE (row, hmap_node, &table->rows) { - if (ovsdb_condition_match_every_clause(row, cnd) && - !output_row(row, aux)) { - break; - } + /* Check the indexes. */ + if (ovsdb_query_index(table, cnd, &row, txn)) { + if (row) { + output_row(row, aux); + return; + } + return; + } + + /* Linear scan. */ + HMAP_FOR_EACH_SAFE (row, hmap_node, &table->rows) { + if (ovsdb_condition_match_every_clause(row, cnd) && + !output_row(row, aux)) { + break; } } } @@ -62,9 +204,10 @@ query_row_set_cb(const struct ovsdb_row *row, void *results_) void ovsdb_query_row_set(struct ovsdb_table *table, const struct ovsdb_condition *condition, - struct ovsdb_row_set *results) + struct ovsdb_row_set *results, + const struct ovsdb_txn *txn) { - ovsdb_query(table, condition, query_row_set_cb, results); + ovsdb_query(table, condition, query_row_set_cb, results, txn); } static bool @@ -79,11 +222,12 @@ void ovsdb_query_distinct(struct ovsdb_table *table, const struct ovsdb_condition *condition, const struct ovsdb_column_set *columns, - struct ovsdb_row_set *results) + struct ovsdb_row_set *results, + const struct ovsdb_txn *txn) { if (!columns || ovsdb_column_set_contains(columns, OVSDB_COL_UUID)) { /* All the result rows are guaranteed to be distinct anyway. */ - ovsdb_query_row_set(table, condition, results); + ovsdb_query_row_set(table, condition, results, txn); return; } else { /* Use hash table to drop duplicates. */ @@ -91,7 +235,7 @@ ovsdb_query_distinct(struct ovsdb_table *table, struct ovsdb_row_hash hash; ovsdb_row_hash_init(&hash, columns); - ovsdb_query(table, condition, query_distinct_cb, &hash); + ovsdb_query(table, condition, query_distinct_cb, &hash, txn); HMAP_FOR_EACH (node, hmap_node, &hash.rows) { ovsdb_row_set_add_row(results, node->row); } diff --git a/ovsdb/query.h b/ovsdb/query.h index 5cc9b11da..e1bdef762 100644 --- a/ovsdb/query.h +++ b/ovsdb/query.h @@ -27,11 +27,11 @@ struct ovsdb_txn; void ovsdb_query(struct ovsdb_table *, const struct ovsdb_condition *, bool (*output_row)(const struct ovsdb_row *, void *aux), - void *aux); + void *aux, const struct ovsdb_txn *); void ovsdb_query_row_set(struct ovsdb_table *, const struct ovsdb_condition *, - struct ovsdb_row_set *); + struct ovsdb_row_set *, const struct ovsdb_txn *); void ovsdb_query_distinct(struct ovsdb_table *, const struct ovsdb_condition *, const struct ovsdb_column_set *, - struct ovsdb_row_set *); + struct ovsdb_row_set *, const struct ovsdb_txn *); #endif /* ovsdb/query.h */ diff --git a/ovsdb/rbac.c b/ovsdb/rbac.c index a3fe97120..d543df41d 100644 --- a/ovsdb/rbac.c +++ b/ovsdb/rbac.c @@ -219,7 +219,8 @@ denied: bool ovsdb_rbac_delete(const struct ovsdb *db, struct ovsdb_table *table, struct ovsdb_condition *condition, - const char *role, const char *id) + const char *role, const char *id, + const struct ovsdb_txn *txn) { const struct ovsdb_table_schema *ts = table->schema; const struct ovsdb_row *perms; @@ -244,7 +245,7 @@ ovsdb_rbac_delete(const struct ovsdb *db, struct ovsdb_table *table, rd.role = role; rd.id = id; - ovsdb_query(table, condition, rbac_delete_cb, &rd); + ovsdb_query(table, condition, rbac_delete_cb, &rd, txn); if (rd.permitted) { return true; @@ -309,7 +310,8 @@ ovsdb_rbac_update(const struct ovsdb *db, struct ovsdb_table *table, struct ovsdb_column_set *columns, struct ovsdb_condition *condition, - const char *role, const char *id) + const char *role, const char *id, + const struct ovsdb_txn *txn) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); const struct ovsdb_table_schema *ts = table->schema; @@ -348,7 +350,7 @@ ovsdb_rbac_update(const struct ovsdb *db, ru.modifiable = datum; ru.permitted = true; - ovsdb_query(table, condition, rbac_update_cb, &ru); + ovsdb_query(table, condition, rbac_update_cb, &ru, txn); if (ru.permitted) { return true; @@ -398,7 +400,8 @@ ovsdb_rbac_mutate(const struct ovsdb *db, struct ovsdb_table *table, struct ovsdb_mutation_set *mutations, struct ovsdb_condition *condition, - const char *role, const char *id) + const char *role, const char *id, + const struct ovsdb_txn *txn) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); const struct ovsdb_table_schema *ts = table->schema; @@ -437,7 +440,7 @@ ovsdb_rbac_mutate(const struct ovsdb *db, rm.modifiable = datum; rm.permitted = true; - ovsdb_query(table, condition, rbac_mutate_cb, &rm); + ovsdb_query(table, condition, rbac_mutate_cb, &rm, txn); if (rm.permitted) { return true; diff --git a/ovsdb/rbac.h b/ovsdb/rbac.h index 42f2ef925..b46a6235e 100644 --- a/ovsdb/rbac.h +++ b/ovsdb/rbac.h @@ -25,6 +25,7 @@ struct ovsdb_condition; struct ovsdb_mutation_set; struct ovsdb_row; struct ovsdb_table; +struct ovsdb_txn; bool ovsdb_rbac_insert(const struct ovsdb *, const struct ovsdb_table *, @@ -33,16 +34,19 @@ bool ovsdb_rbac_insert(const struct ovsdb *, bool ovsdb_rbac_delete(const struct ovsdb *, struct ovsdb_table *, struct ovsdb_condition *, - const char *role, const char *id); + const char *role, const char *id, + const struct ovsdb_txn *); bool ovsdb_rbac_update(const struct ovsdb *, struct ovsdb_table *, struct ovsdb_column_set *, struct ovsdb_condition *condition, - const char *role, const char *id); + const char *role, const char *id, + const struct ovsdb_txn *); bool ovsdb_rbac_mutate(const struct ovsdb *, struct ovsdb_table *, struct ovsdb_mutation_set *, struct ovsdb_condition *, - const char *role, const char *id); + const char *role, const char *id, + const struct ovsdb_txn *); #endif /* ovsdb/rbac.h */ diff --git a/ovsdb/row.h b/ovsdb/row.h index 6f5e58acb..f585b9fdc 100644 --- a/ovsdb/row.h +++ b/ovsdb/row.h @@ -22,6 +22,7 @@ #include "openvswitch/hmap.h" #include "openvswitch/list.h" #include "ovsdb-data.h" +#include "table.h" struct ovsdb_column_set; @@ -152,6 +153,33 @@ ovsdb_row_hash(const struct ovsdb_row *row) { return uuid_hash(ovsdb_row_get_uuid(row)); } + +/* Returns the offset in bytes from the start of an ovsdb_row for 'table' to + * the hmap_node for the index numbered 'i'. */ +static inline size_t +ovsdb_row_index_offset__(const struct ovsdb_table *table, size_t i) +{ + size_t n_fields = shash_count(&table->schema->columns); + return (offsetof(struct ovsdb_row, fields) + + n_fields * sizeof(struct ovsdb_datum) + + i * sizeof(struct hmap_node)); +} + +/* Returns the hmap_node in 'row' for the index numbered 'i'. */ +static inline struct hmap_node * +ovsdb_row_get_index_node(struct ovsdb_row *row, size_t i) +{ + return (void *) ((char *) row + ovsdb_row_index_offset__(row->table, i)); +} + +/* Returns the ovsdb_row given 'index_node', which is a pointer to that row's + * hmap_node for the index numbered 'i' within 'table'. */ +static inline struct ovsdb_row * +ovsdb_row_from_index_node(struct hmap_node *index_node, + const struct ovsdb_table *table, size_t i) +{ + return (void *) ((char *) index_node - ovsdb_row_index_offset__(table, i)); +} /* An unordered collection of rows. */ struct ovsdb_row_set { diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c index 98fff1a74..39650d3b3 100644 --- a/ovsdb/transaction.c +++ b/ovsdb/transaction.c @@ -194,33 +194,6 @@ ovsdb_txn_row_abort(struct ovsdb_txn *txn OVS_UNUSED, return NULL; } -/* Returns the offset in bytes from the start of an ovsdb_row for 'table' to - * the hmap_node for the index numbered 'i'. */ -static size_t -ovsdb_row_index_offset__(const struct ovsdb_table *table, size_t i) -{ - size_t n_fields = shash_count(&table->schema->columns); - return (offsetof(struct ovsdb_row, fields) - + n_fields * sizeof(struct ovsdb_datum) - + i * sizeof(struct hmap_node)); -} - -/* Returns the hmap_node in 'row' for the index numbered 'i'. */ -static struct hmap_node * -ovsdb_row_get_index_node(struct ovsdb_row *row, size_t i) -{ - return (void *) ((char *) row + ovsdb_row_index_offset__(row->table, i)); -} - -/* Returns the ovsdb_row given 'index_node', which is a pointer to that row's - * hmap_node for the index numbered 'i' within 'table'. */ -static struct ovsdb_row * -ovsdb_row_from_index_node(struct hmap_node *index_node, - const struct ovsdb_table *table, size_t i) -{ - return (void *) ((char *) index_node - ovsdb_row_index_offset__(table, i)); -} - void ovsdb_txn_abort(struct ovsdb_txn *txn) { @@ -889,7 +862,7 @@ check_max_rows(struct ovsdb_txn *txn) return NULL; } -static struct ovsdb_row * +struct ovsdb_row * ovsdb_index_search(struct hmap *index, struct ovsdb_row *row, size_t i, uint32_t hash) { diff --git a/ovsdb/transaction.h b/ovsdb/transaction.h index f659838dc..d94205414 100644 --- a/ovsdb/transaction.h +++ b/ovsdb/transaction.h @@ -17,8 +17,10 @@ #define OVSDB_TRANSACTION_H 1 #include +#include #include "compiler.h" +struct hmap; struct json; struct ovsdb; struct ovsdb_row; @@ -66,6 +68,9 @@ typedef bool ovsdb_txn_row_cb_func(const struct ovsdb_row *old, void *aux); void ovsdb_txn_for_each_change(const struct ovsdb_txn *, ovsdb_txn_row_cb_func *, void *aux); +struct ovsdb_row *ovsdb_index_search(struct hmap *index, + struct ovsdb_row *, size_t i, + uint32_t hash); void ovsdb_txn_add_comment(struct ovsdb_txn *, const char *); const char *ovsdb_txn_get_comment(const struct ovsdb_txn *); diff --git a/tests/ovsdb-execution.at b/tests/ovsdb-execution.at index 868abca13..8c23033f3 100644 --- a/tests/ovsdb-execution.at +++ b/tests/ovsdb-execution.at @@ -11,7 +11,7 @@ ordinal_schema () { "columns": { "number": {"type": "integer"}, "name": {"type": "string"}}, - "indexes": [["number"]]}}, + "indexes": [["number"], ["number", "name"]]}}, "version": "5.1.3", "cksum": "12345678 9"} EOF @@ -273,6 +273,112 @@ dnl Attempt to insert second row with same UUID (fails). [{"details":"This UUID would duplicate a UUID already present within the table or deleted within the same transaction.","error":"duplicate uuid","syntax":"\"ffffffff-971b-4cba-bf42-520515973b7e\""}] ]]) +OVSDB_CHECK_EXECUTION([insert rows, query by index], + [ordinal_schema], +dnl Insert initial rows. + [[[["ordinals", + {"op": "insert", + "table": "ordinals", + "row": {"number": 0, "name": "zero"}}]]], + [[["ordinals", + {"op": "insert", + "table": "ordinals", + "row": {"number": 1, "name": "one"}}]]], + [[["ordinals", + {"op": "delete", + "table": "ordinals", + "where": [["number", "==", 1]]}]]], + [[["ordinals", + {"op": "insert", + "table": "ordinals", + "row": {"number": 2, "name": "two"}}]]], + [[["ordinals", + {"op": "insert", + "table": "ordinals", + "row": {"number": 3, "name": "three"}}]]], +dnl Query the deleted row. + [[["ordinals", + {"op": "select", + "table": "ordinals", + "where": [["number", "==", 1]]}]]], +dnl Query a non-deleted row with first index. + [[["ordinals", + {"op": "select", + "table": "ordinals", + "where": [["number", "==", 3]]}]]], +dnl Query with second index. + [[["ordinals", + {"op": "select", + "table": "ordinals", + "where": [["name", "==", "two"], ["number", "==", 2]]}]]], +dnl Delete a row and query in the same transaction. + [[["ordinals", + {"op": "delete", + "table": "ordinals", + "where": [["number", "==", 2]]}, + {"op": "select", + "table": "ordinals", + "where": [["number", "==", 2]]}]]], +dnl Mutate a row and query in the same transaction. + [[["ordinals", + {"op": "mutate", + "table": "ordinals", + "mutations": [["number", "+=", 2]], + "where": [["number", "==", 0]]}, + {"op": "select", + "table": "ordinals", + "where": [["number", "==", 0]]}, + {"op": "select", + "table": "ordinals", + "where": [["number", "==", 2]]}]]]], +[[[{"uuid":["uuid","<0>"]}] +[{"uuid":["uuid","<1>"]}] +[{"count":1}] +[{"uuid":["uuid","<2>"]}] +[{"uuid":["uuid","<3>"]}] +[{"rows":[]}] +[{"rows":[{"_uuid":["uuid","<3>"],"_version":["uuid","<4>"],"name":"three","number":3}]}] +[{"rows":[{"_uuid":["uuid","<2>"],"_version":["uuid","<5>"],"name":"two","number":2}]}] +[{"count":1},{"rows":[]}] +[{"count":1},{"rows":[]},{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<6>"],"name":"zero","number":2}]}] +]]) + +OVSDB_CHECK_EXECUTION([reinsert indexed rows mid flight], + [ordinal_schema], +dnl Insert initial rows. + [[[["ordinals", + {"op": "insert", + "table": "ordinals", + "row": {"number": 0, "name": "orig"} + }]]], + [[["ordinals", + {"op": "select", + "table": "ordinals", + "where": [["number", "==", 0]] + }, + {"op": "insert", + "table": "ordinals", + "uuid-name": "dup", + "row": {"number": 0, "name": "dup"} + }, + {"op": "select", + "table": "ordinals", + "sort": ["name"], + "where": [["number", "==", 0]] + }, + {"op": "delete", + "table": "ordinals", + "where": [["_uuid", "==", ["named-uuid", "dup"]]] + }, + {"op": "select", + "table": "ordinals", + "where": [["number", "==", 0]] + }]]] + ], +[[[{"uuid":["uuid","<0>"]}] +[{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<1>"],"name":"orig","number":0}]},{"uuid":["uuid","<2>"]},{"rows":[{"_uuid":["uuid","<2>"],"_version":["uuid","<3>"],"name":"dup","number":0},{"_uuid":["uuid","<0>"],"_version":["uuid","<1>"],"name":"orig","number":0}]},{"count":1},{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<1>"],"name":"orig","number":0}]}] +]]) + OVSDB_CHECK_EXECUTION([insert rows, query by value], [ordinal_schema], [[[["ordinals", diff --git a/tests/ovsdb-macros.at b/tests/ovsdb-macros.at index 8dca0b798..3c4e15c13 100644 --- a/tests/ovsdb-macros.at +++ b/tests/ovsdb-macros.at @@ -38,6 +38,16 @@ m4_define([OVSDB_CHECK_POSITIVE], ], []) AT_CLEANUP]) +# OVSDB_CHECK_POSITIVE_IDX(TITLE, TEST-OVSDB-ARGS, OUTPUT, [KEYWORDS], [PREREQ], [INDEX]) +# +# Runs "test-ovsdb TEST-OVSDB-ARGS" twice, with and without an index, and checks +# that it exits with status 0 and prints OUTPUT on stdout. +# +# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS. +m4_define([OVSDB_CHECK_POSITIVE_IDX], + [OVSDB_CHECK_POSITIVE($1, [$2], $3, $4, $5) + OVSDB_CHECK_POSITIVE([indexed $1], [m4_bpatsubst([$2], ["columns":], ["indexes": [$6], "columns":])], $3, $4, $5)]) + # OVSDB_CHECK_POSITIVE_PY(TITLE, TEST-OVSDB-ARGS, OUTPUT, [KEYWORDS], [PREREQ], # [PY-CHECK]) # diff --git a/tests/ovsdb-query.at b/tests/ovsdb-query.at index 0814fda2a..7d891da06 100644 --- a/tests/ovsdb-query.at +++ b/tests/ovsdb-query.at @@ -1,6 +1,6 @@ AT_BANNER([OVSDB -- queries]) -OVSDB_CHECK_POSITIVE([queries on scalars], +OVSDB_CHECK_POSITIVE_IDX([queries on scalars], [[query \ '{"columns": {"i": {"type": "integer"}, @@ -90,9 +90,9 @@ query 24: 111-1 query 25: 1---- query 26: 1-111 query 27: --1--], - [query]) + [query], [], [["i"], ["r"], ["s"], ["u"]]) -OVSDB_CHECK_POSITIVE([queries on sets], +OVSDB_CHECK_POSITIVE_IDX([queries on sets], [[query \ '{"columns": {"i": {"type": {"key": "integer", "min": 0, "max": "unlimited"}}}}' \ '[{"i": ["set", []]}, @@ -169,11 +169,11 @@ query 28: 1---1 --- query 29: 1111- --- query 30: 1-1-- --- query 31: 11--- --- -query 32: 1---- ---], [query]) +query 32: 1---- ---], [query], [], [["i"]]) # This is the same as the "set" test except that it adds values, # all of which always match. -OVSDB_CHECK_POSITIVE([queries on maps (1)], +OVSDB_CHECK_POSITIVE_IDX([queries on maps (1)], [[query \ '{"columns": {"i": {"type": {"key": "integer", "value": "boolean", @@ -253,11 +253,11 @@ query 28: 1---1 --- query 29: 1111- --- query 30: 1-1-- --- query 31: 11--- --- -query 32: 1---- ---], [query]) +query 32: 1---- ---], [query], [], [["i"]]) # This is the same as the "set" test except that it adds values, # and those values don't always match. -OVSDB_CHECK_POSITIVE([queries on maps (2)], +OVSDB_CHECK_POSITIVE_IDX([queries on maps (2)], [[query \ '{"columns": {"i": {"type": {"key": "integer", "value": "boolean", @@ -346,7 +346,7 @@ query 28: 1-1-1 --11- --1-- query 29: 11111 11-1- 1---- query 30: 1-111 ---1- ----- query 31: 111-1 -1-1- 1---- -query 32: 1-1-1 ---1- -----], [query]) +query 32: 1-1-1 ---1- -----], [query], [], [["i"]]) OVSDB_CHECK_POSITIVE([UUID-distinct queries on scalars], [[query-distinct \ @@ -439,7 +439,7 @@ query 24: abc-e query 25: a---- query 26: a-cde query 27: --c--], - [query]) + [query], [], [["i"], ["r"], ["s"], ["u"]]) OVSDB_CHECK_POSITIVE([Boolean-distinct queries on scalars], [[query-distinct \ diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index fb8a229d7..ca6e931be 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -1103,7 +1103,7 @@ ovsdb_check_online_compaction() { AT_CHECK([[uuidfilt db | grep -v ^OVSDB | \ sed 's/"_date":[0-9]*/"_date":0/' | sed 's/"_is_diff":true,//' | \ ovstest test-json --multiple -]], [0], -[[{"cksum":"12345678 9","name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}},"indexes":[["number"]]}},"version":"5.1.3"} +[[{"cksum":"12345678 9","name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}},"indexes":[["number"],["number","name"]]}},"version":"5.1.3"} {"_comment":"add row for zero 0","_date":0,"ordinals":{"<0>":{"name":"zero"}}} {"_comment":"delete row for 0","_date":0,"ordinals":{"<0>":null}} {"_comment":"add back row for zero 0","_date":0,"ordinals":{"<1>":{"name":"zero"}}} diff --git a/tests/ovsdb-tool.at b/tests/ovsdb-tool.at index d8d2b1c99..cf4a0fd2e 100644 --- a/tests/ovsdb-tool.at +++ b/tests/ovsdb-tool.at @@ -95,7 +95,7 @@ AT_CHECK( dnl Check that all the crap is in fact in the database log. AT_CHECK([[uuidfilt db | grep -v ^OVSDB | sed 's/"_date":[0-9]*/"_date":0/' | \ sed 's/"_is_diff":true,//' | ovstest test-json --multiple -]], [0], - [[{"cksum":"12345678 9","name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}},"indexes":[["number"]]}},"version":"5.1.3"} + [[{"cksum":"12345678 9","name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}},"indexes":[["number"],["number","name"]]}},"version":"5.1.3"} {"_comment":"add row for zero 0","_date":0,"ordinals":{"<0>":{"name":"zero"}}} {"_comment":"delete row for 0","_date":0,"ordinals":{"<0>":null}} {"_comment":"add back row for zero 0","_date":0,"ordinals":{"<1>":{"name":"zero"}}} diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c index 99ddb9034..d3bb199ef 100644 --- a/tests/test-ovsdb.c +++ b/tests/test-ovsdb.c @@ -1277,7 +1277,8 @@ do_execute_mutations(struct ovs_cmdl_context *ctx) ovsdb_table_destroy(table); /* Also destroys 'ts'. */ } -/* Inserts a row, without bothering to update metadata such as refcounts. */ +/* Inserts a row and update the indexes, without bothering to update metadata + * such as refcounts. */ static void put_row(struct ovsdb_table *table, struct ovsdb_row *row) { @@ -1285,6 +1286,14 @@ put_row(struct ovsdb_table *table, struct ovsdb_row *row) if (!ovsdb_table_get_row(table, uuid)) { hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid)); } + + for (size_t i = 0; i < table->schema->n_indexes; i++) { + const struct ovsdb_column_set *index = &table->schema->indexes[i]; + struct hmap_node *node = ovsdb_row_get_index_node(row, i); + uint32_t hash = ovsdb_row_hash_columns(row, index, 0); + + hmap_insert(&table->indexes[i], node, hash); + } } struct do_query_cbdata { @@ -1362,7 +1371,7 @@ do_query(struct ovs_cmdl_context *ctx) NULL, &cnd)); memset(cbdata.counts, 0, cbdata.n_rows * sizeof *cbdata.counts); - ovsdb_query(table, &cnd, do_query_cb, &cbdata); + ovsdb_query(table, &cnd, do_query_cb, &cbdata, NULL); printf("query %2"PRIuSIZE":", i); for (j = 0; j < cbdata.n_rows; j++) { @@ -1490,7 +1499,7 @@ do_query_distinct(struct ovs_cmdl_context *ctx) classes[j].count = 0; } ovsdb_row_set_init(&results); - ovsdb_query_distinct(table, &cnd, &columns, &results); + ovsdb_query_distinct(table, &cnd, &columns, &results, NULL); for (j = 0; j < results.n_rows; j++) { size_t k;