diff options
author | Ilya Maximets <i.maximets@ovn.org> | 2021-09-23 01:47:22 +0200 |
---|---|---|
committer | Ilya Maximets <i.maximets@ovn.org> | 2021-09-24 14:55:54 +0200 |
commit | 51946d22274cd591dc061358fb507056fbd91420 (patch) | |
tree | ca4878042e9197e4193766aba81fec3f0b0259b0 /vswitchd | |
parent | bfc6e9735c64d050ec8817759adf6e572d897b65 (diff) | |
download | openvswitch-51946d22274cd591dc061358fb507056fbd91420.tar.gz |
ovsdb-data: Optimize union of sets.
Current algorithm of ovsdb_datum_union looks like this:
for-each atom in b:
if not bin_search(a, atom):
push(a, clone(atom))
quicksort(a)
So, the complexity looks like this:
Nb * log2(Na) + Nb + (Na + Nb) * log2(Na + Nb)
Comparisons clones Comparisons for quicksort
for search
ovsdb_datum_union() is heavily used in database transactions while
new element is added to a set. For example, if new logical switch
port is added to a logical switch in OVN. This is a very common
use case where CMS adds one new port to an existing switch that
already has, let's say, 100 ports. For this case ovsdb-server will
have to perform:
1 * log2(100) + 1 clone + 101 * log2(101)
Comparisons Comparisons for
for search quicksort.
~7 1 ~707
Roughly 714 comparisons of atoms and 1 clone.
Since binary search can give us position, where new atom should go
(it's the 'low' index after the search completion) for free, the
logic can be re-worked like this:
copied = 0
for-each atom in b:
desired_position = bin_search(a, atom)
push(result, a[ copied : desired_position - 1 ])
copied = desired_position
push(result, clone(atom))
push(result, a[ copied : Na ])
swap(a, result)
Complexity of this schema:
Nb * log2(Na) + Nb + Na
Comparisons clones memory copy on push
for search
'swap' is just a swap of a few pointers. 'push' is not a 'clone',
but a simple memory copy of 'union ovsdb_atom'.
In general, this schema substitutes complexity of a quicksort
with complexity of a memory copy of Na atom structures, where we're
not even copying strings that these atoms are pointing to.
Complexity in the example above goes down from 714 comparisons
to 7 comparisons and memcpy of 100 * sizeof (union ovsdb_atom) bytes.
General complexity of a memory copy should always be lower than
complexity of a quicksort, especially because these copies usually
performed in bulk, so this new schema should work faster for any input.
All in all, this change allows to execute several times more
transactions per second for transactions that adds new entries to sets.
Alternatively, union can be implemented as a linear merge of two
sorted arrays, but this will result in O(Na) comparisons, which
is more than Nb * log2(Na) in common case, since Na is usually
far bigger than Nb. Linear merge will also mean per-atom memory
copies instead of copying in bulk.
'replace' functionality of ovsdb_datum_union() had no users, so it
just removed. But it can easily be added back if needed in the future.
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Acked-by: Han Zhou <hzhou@ovn.org>
Acked-by: Mark D. Gray <mark.d.gray@redhat.com>
Diffstat (limited to 'vswitchd')
-rw-r--r-- | vswitchd/bridge.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index cb7c5cb76..c790a56ad 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -4229,7 +4229,7 @@ bridge_configure_aa(struct bridge *br) union ovsdb_atom atom; atom.integer = m->isid; - if (ovsdb_datum_find_key(mc, &atom, OVSDB_TYPE_INTEGER) == UINT_MAX) { + if (!ovsdb_datum_find_key(mc, &atom, OVSDB_TYPE_INTEGER, NULL)) { VLOG_INFO("Deleting isid=%"PRIu32", vlan=%"PRIu16, m->isid, m->vlan); bridge_aa_mapping_destroy(m); @@ -4826,7 +4826,7 @@ queue_ids_include(const struct ovsdb_datum *queues, int64_t target) union ovsdb_atom atom; atom.integer = target; - return ovsdb_datum_find_key(queues, &atom, OVSDB_TYPE_INTEGER) != UINT_MAX; + return ovsdb_datum_find_key(queues, &atom, OVSDB_TYPE_INTEGER, NULL); } static void @@ -5020,7 +5020,7 @@ bridge_configure_mirrors(struct bridge *br) union ovsdb_atom atom; atom.uuid = m->uuid; - if (ovsdb_datum_find_key(mc, &atom, OVSDB_TYPE_UUID) == UINT_MAX) { + if (!ovsdb_datum_find_key(mc, &atom, OVSDB_TYPE_UUID, NULL)) { mirror_destroy(m); } } |