@@ -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 "
@@ -811,7 +812,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
@@ -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 ==
* <some-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);
}
@@ -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 */
@@ -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;
@@ -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 */
@@ -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 {
@@ -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)
{
@@ -17,8 +17,10 @@
#define OVSDB_TRANSACTION_H 1
#include <stdbool.h>
+#include <stdint.h>
#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 *);
@@ -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",
@@ -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])
#
@@ -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 \
@@ -1007,7 +1007,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"}}}
@@ -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"}}}
@@ -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;