summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Maximets <i.maximets@ovn.org>2021-09-14 00:19:57 +0200
committerIlya Maximets <i.maximets@ovn.org>2021-09-23 00:21:49 +0200
commitb2712d026eae2d9a5150c2805310eaf506e1f162 (patch)
treed6c7772b8dd992725f41122def8da77d7ddad647
parent9e7081b141ca86b71dc4dbd0744a5fe8560909f2 (diff)
downloadopenvswitch-b2712d026eae2d9a5150c2805310eaf506e1f162.tar.gz
ovsdb: transaction: Use diffs for strong reference counting.
Currently, even if one reference added to the set of strong references or removed from it, ovsdb-server will walk through the whole set and re-count references to other rows. These referenced rows will also be added to the transaction in order to re-count their references. For example, every time Logical Switch Port added to a Logical Switch, OVN Northbound database server will walk through all ports of this Logical Switch, clone their rows, and re-count references. This is not very efficient. Instead, it can only increase reference counters for added references and reduce for removed ones. In many cases this will be only one row affected in the Logical_Switch_Port table. Introducing new function that generates a diff of two datum objects, but stores added and removed atoms separately, so they can be used to increase or decrease row reference counters accordingly. This change allows to perform several times more transactions that adds or removes strong references to/from sets per second, because ovsdb-server no longer clones and re-counts rows that are irrelevant to current transaction. Acked-by: Dumitru Ceara <dceara@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
-rw-r--r--lib/ovsdb-data.c58
-rw-r--r--lib/ovsdb-data.h6
-rw-r--r--ovsdb/transaction.c39
3 files changed, 96 insertions, 7 deletions
diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c
index c145f5ad9..1f491a98b 100644
--- a/lib/ovsdb-data.c
+++ b/lib/ovsdb-data.c
@@ -2067,6 +2067,64 @@ ovsdb_symbol_table_insert(struct ovsdb_symbol_table *symtab,
/* APIs for Generating and apply diffs. */
+/* Find what needs to be added to and removed from 'old' to construct 'new'.
+ *
+ * The 'added' and 'removed' datums are always safe; the orders of keys are
+ * maintained since they are added in order. */
+void
+ovsdb_datum_added_removed(struct ovsdb_datum *added,
+ struct ovsdb_datum *removed,
+ const struct ovsdb_datum *old,
+ const struct ovsdb_datum *new,
+ const struct ovsdb_type *type)
+{
+ size_t oi, ni;
+
+ ovsdb_datum_init_empty(added);
+ ovsdb_datum_init_empty(removed);
+ if (!ovsdb_type_is_composite(type)) {
+ ovsdb_datum_clone(removed, old, type);
+ ovsdb_datum_clone(added, new, type);
+ return;
+ }
+
+ /* Generate the diff in O(n) time. */
+ for (oi = ni = 0; oi < old->n && ni < new->n;) {
+ int c = ovsdb_atom_compare_3way(&old->keys[oi], &new->keys[ni],
+ type->key.type);
+ if (c < 0) {
+ ovsdb_datum_add_unsafe(removed, &old->keys[oi], &old->values[oi],
+ type, NULL);
+ oi++;
+ } else if (c > 0) {
+ ovsdb_datum_add_unsafe(added, &new->keys[ni], &new->values[ni],
+ type, NULL);
+ ni++;
+ } else {
+ if (type->value.type != OVSDB_TYPE_VOID &&
+ ovsdb_atom_compare_3way(&old->values[oi], &new->values[ni],
+ type->value.type)) {
+ ovsdb_datum_add_unsafe(removed, &old->keys[oi],
+ &old->values[oi], type, NULL);
+ ovsdb_datum_add_unsafe(added, &new->keys[ni], &new->values[ni],
+ type, NULL);
+ }
+ oi++; ni++;
+ }
+ }
+
+ for (; oi < old->n; oi++) {
+ ovsdb_datum_add_unsafe(removed, &old->keys[oi], &old->values[oi],
+ type, NULL);
+ }
+
+ for (; ni < new->n; ni++) {
+ ovsdb_datum_add_unsafe(added, &new->keys[ni], &new->values[ni],
+ type, NULL);
+ }
+}
+
+
/* Generate a difference ovsdb_dataum between 'old' and 'new'.
* 'new' can be regenerated by applying the difference to the 'old'.
*
diff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h
index c5a80ee39..aa035ebad 100644
--- a/lib/ovsdb-data.h
+++ b/lib/ovsdb-data.h
@@ -235,6 +235,12 @@ void ovsdb_datum_subtract(struct ovsdb_datum *a,
const struct ovsdb_type *b_type);
/* Generate and apply diffs */
+void ovsdb_datum_added_removed(struct ovsdb_datum *added,
+ struct ovsdb_datum *removed,
+ const struct ovsdb_datum *old,
+ const struct ovsdb_datum *new,
+ const struct ovsdb_type *type);
+
void ovsdb_datum_diff(struct ovsdb_datum *diff,
const struct ovsdb_datum *old_datum,
const struct ovsdb_datum *new_datum,
diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c
index 8ffefcf7c..dcccc61c0 100644
--- a/ovsdb/transaction.c
+++ b/ovsdb/transaction.c
@@ -266,9 +266,9 @@ ovsdb_txn_adjust_atom_refs(struct ovsdb_txn *txn, const struct ovsdb_row *r,
static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
ovsdb_txn_adjust_row_refs(struct ovsdb_txn *txn, const struct ovsdb_row *r,
- const struct ovsdb_column *column, int delta)
+ const struct ovsdb_column *column,
+ const struct ovsdb_datum *field, int delta)
{
- const struct ovsdb_datum *field = &r->fields[column->index];
struct ovsdb_error *error;
error = ovsdb_txn_adjust_atom_refs(txn, r, column, &column->type.key,
@@ -291,14 +291,39 @@ update_row_ref_count(struct ovsdb_txn *txn, struct ovsdb_txn_row *r)
struct ovsdb_error *error;
if (bitmap_is_set(r->changed, column->index)) {
- if (r->old) {
- error = ovsdb_txn_adjust_row_refs(txn, r->old, column, -1);
+ if (r->old && !r->new) {
+ error = ovsdb_txn_adjust_row_refs(
+ txn, r->old, column,
+ &r->old->fields[column->index], -1);
if (error) {
return OVSDB_WRAP_BUG("error decreasing refcount", error);
}
- }
- if (r->new) {
- error = ovsdb_txn_adjust_row_refs(txn, r->new, column, 1);
+ } else if (!r->old && r->new) {
+ error = ovsdb_txn_adjust_row_refs(
+ txn, r->new, column,
+ &r->new->fields[column->index], 1);
+ if (error) {
+ return error;
+ }
+ } else if (r->old && r->new) {
+ struct ovsdb_datum added, removed;
+
+ ovsdb_datum_added_removed(&added, &removed,
+ &r->old->fields[column->index],
+ &r->new->fields[column->index],
+ &column->type);
+
+ error = ovsdb_txn_adjust_row_refs(
+ txn, r->old, column, &removed, -1);
+ ovsdb_datum_destroy(&removed, &column->type);
+ if (error) {
+ ovsdb_datum_destroy(&added, &column->type);
+ return OVSDB_WRAP_BUG("error decreasing refcount", error);
+ }
+
+ error = ovsdb_txn_adjust_row_refs(
+ txn, r->new, column, &added, 1);
+ ovsdb_datum_destroy(&added, &column->type);
if (error) {
return error;
}