2012-05-02 15:21:36 -07:00
|
|
|
|
/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
|
2009-11-04 15:11:44 -08:00
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef OVSDB_ROW_H
|
|
|
|
|
#define OVSDB_ROW_H 1
|
|
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include "column.h"
|
2016-07-12 16:37:34 -05:00
|
|
|
|
#include "openvswitch/hmap.h"
|
2016-03-25 14:10:21 -07:00
|
|
|
|
#include "openvswitch/list.h"
|
2009-11-04 15:11:44 -08:00
|
|
|
|
#include "ovsdb-data.h"
|
|
|
|
|
|
|
|
|
|
struct ovsdb_column_set;
|
|
|
|
|
|
2010-03-15 15:41:54 -07:00
|
|
|
|
/* A weak reference.
|
|
|
|
|
*
|
|
|
|
|
* When a column in row A contains a weak reference to UUID of a row B this
|
|
|
|
|
* constitutes a weak reference from A (the source) to B (the destination).
|
|
|
|
|
*
|
|
|
|
|
* Rows A and B may be in the same table or different tables.
|
|
|
|
|
*
|
|
|
|
|
* Weak references from a row to itself are allowed, but no "struct
|
|
|
|
|
* ovsdb_weak_ref" structures are created for them.
|
|
|
|
|
*/
|
|
|
|
|
struct ovsdb_weak_ref {
|
ovsdb: transaction: Incremental reassessment of weak refs.
The main idea is to not store list of weak references in the source
row, so they all don't need to be re-checked/updated on every
modification of that source row. The point is that source row already
knows UUIDs of all destination rows stored in the data, so there is no
much profit in storing this information somewhere else. If needed,
destination row can be looked up and reference can be looked up in the
destination row. For the fast lookup, destination row now stores
references in a hash map.
Weak reference structure now contains the table and uuid of a source
row instead of a direct pointer. This allows to replace/update the
source row without breaking any weak references stored in destination
rows.
Structure also now contains the key-value pair of atoms that triggered
creation of this reference. These atoms can be used to quickly
subtract removed references from a source row. During reassessment,
ovsdb now only needs to care about new added or removed atoms, and
atoms that got removed due to removal of the destination rows, but
these are marked for reassessment by the destination row.
ovsdb_datum_subtract() is used to remove atoms that points to removed
or incorrect rows, so there is no need to re-sort datum in the end.
Results of an OVN load-balancer benchmark that adds 3K load-balancers
to each of 120 logical switches and 120 logical routers in the OVN
sandbox with clustered Northbound database and then removes them:
Before:
%CPU CPU Time CMD
86.8 00:16:05 ovsdb-server nb1.db
44.1 00:08:11 ovsdb-server nb2.db
43.2 00:08:00 ovsdb-server nb3.db
After:
%CPU CPU Time CMD
54.9 00:02:58 ovsdb-server nb1.db
33.3 00:01:48 ovsdb-server nb2.db
32.2 00:01:44 ovsdb-server nb3.db
So, on a cluster leader the processing time dropped by 5.4x, on
followers - by 4.5x. More load-balancers - larger the performance
difference. There is a slight increase of memory usage, because new
reference structure is larger, but the difference is not significant.
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Acked-by: Dumitru Ceara <dceara@redhat.com>
2021-10-16 03:20:23 +02:00
|
|
|
|
struct hmap_node dst_node; /* In ovsdb_row's 'dst_refs' hmap. */
|
|
|
|
|
struct ovs_list src_node; /* In txn_row's 'deleted/added_refs'. */
|
|
|
|
|
|
|
|
|
|
struct ovsdb_table *src_table; /* Source row table. */
|
|
|
|
|
struct uuid src; /* Source row uuid. */
|
|
|
|
|
|
|
|
|
|
struct ovsdb_table *dst_table; /* Destination row table. */
|
2016-07-13 17:28:51 +00:00
|
|
|
|
struct uuid dst; /* Destination row uuid. */
|
ovsdb: transaction: Incremental reassessment of weak refs.
The main idea is to not store list of weak references in the source
row, so they all don't need to be re-checked/updated on every
modification of that source row. The point is that source row already
knows UUIDs of all destination rows stored in the data, so there is no
much profit in storing this information somewhere else. If needed,
destination row can be looked up and reference can be looked up in the
destination row. For the fast lookup, destination row now stores
references in a hash map.
Weak reference structure now contains the table and uuid of a source
row instead of a direct pointer. This allows to replace/update the
source row without breaking any weak references stored in destination
rows.
Structure also now contains the key-value pair of atoms that triggered
creation of this reference. These atoms can be used to quickly
subtract removed references from a source row. During reassessment,
ovsdb now only needs to care about new added or removed atoms, and
atoms that got removed due to removal of the destination rows, but
these are marked for reassessment by the destination row.
ovsdb_datum_subtract() is used to remove atoms that points to removed
or incorrect rows, so there is no need to re-sort datum in the end.
Results of an OVN load-balancer benchmark that adds 3K load-balancers
to each of 120 logical switches and 120 logical routers in the OVN
sandbox with clustered Northbound database and then removes them:
Before:
%CPU CPU Time CMD
86.8 00:16:05 ovsdb-server nb1.db
44.1 00:08:11 ovsdb-server nb2.db
43.2 00:08:00 ovsdb-server nb3.db
After:
%CPU CPU Time CMD
54.9 00:02:58 ovsdb-server nb1.db
33.3 00:01:48 ovsdb-server nb2.db
32.2 00:01:44 ovsdb-server nb3.db
So, on a cluster leader the processing time dropped by 5.4x, on
followers - by 4.5x. More load-balancers - larger the performance
difference. There is a slight increase of memory usage, because new
reference structure is larger, but the difference is not significant.
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Acked-by: Dumitru Ceara <dceara@redhat.com>
2021-10-16 03:20:23 +02:00
|
|
|
|
|
|
|
|
|
/* Source row's key-value pair that created this reference.
|
|
|
|
|
* This information is needed in order to find and delete the reference
|
|
|
|
|
* from the source row. We need both key and value in order to avoid
|
|
|
|
|
* accidential deletion of an updated data, i.e. if value in datum got
|
|
|
|
|
* updated and the reference was created by the old value.
|
|
|
|
|
* Storing column index in order to remove references from the correct
|
|
|
|
|
* column. 'by_key' flag allows to distinguish 2 references in a corner
|
|
|
|
|
* case where key and value are the same. */
|
|
|
|
|
union ovsdb_atom key;
|
|
|
|
|
union ovsdb_atom value;
|
|
|
|
|
struct ovsdb_type type; /* Datum type of the key-value pair. */
|
|
|
|
|
unsigned int column_idx; /* Row column index for this pair. */
|
|
|
|
|
bool by_key; /* 'true' if reference is a 'key'. */
|
2010-03-15 15:41:54 -07:00
|
|
|
|
};
|
|
|
|
|
|
2009-11-04 15:11:44 -08:00
|
|
|
|
/* A row in a database table. */
|
|
|
|
|
struct ovsdb_row {
|
2010-03-15 15:41:54 -07:00
|
|
|
|
struct hmap_node hmap_node; /* Element in ovsdb_table's 'rows' hmap. */
|
2012-03-28 14:13:02 -07:00
|
|
|
|
struct ovsdb_table *table; /* Table to which this belongs. */
|
2009-11-04 15:11:44 -08:00
|
|
|
|
struct ovsdb_txn_row *txn_row; /* Transaction that row is in, if any. */
|
2010-02-08 14:09:41 -08:00
|
|
|
|
|
2018-11-01 09:29:07 -07:00
|
|
|
|
/* Weak references. Updated and checked only at transaction commit. */
|
ovsdb: transaction: Incremental reassessment of weak refs.
The main idea is to not store list of weak references in the source
row, so they all don't need to be re-checked/updated on every
modification of that source row. The point is that source row already
knows UUIDs of all destination rows stored in the data, so there is no
much profit in storing this information somewhere else. If needed,
destination row can be looked up and reference can be looked up in the
destination row. For the fast lookup, destination row now stores
references in a hash map.
Weak reference structure now contains the table and uuid of a source
row instead of a direct pointer. This allows to replace/update the
source row without breaking any weak references stored in destination
rows.
Structure also now contains the key-value pair of atoms that triggered
creation of this reference. These atoms can be used to quickly
subtract removed references from a source row. During reassessment,
ovsdb now only needs to care about new added or removed atoms, and
atoms that got removed due to removal of the destination rows, but
these are marked for reassessment by the destination row.
ovsdb_datum_subtract() is used to remove atoms that points to removed
or incorrect rows, so there is no need to re-sort datum in the end.
Results of an OVN load-balancer benchmark that adds 3K load-balancers
to each of 120 logical switches and 120 logical routers in the OVN
sandbox with clustered Northbound database and then removes them:
Before:
%CPU CPU Time CMD
86.8 00:16:05 ovsdb-server nb1.db
44.1 00:08:11 ovsdb-server nb2.db
43.2 00:08:00 ovsdb-server nb3.db
After:
%CPU CPU Time CMD
54.9 00:02:58 ovsdb-server nb1.db
33.3 00:01:48 ovsdb-server nb2.db
32.2 00:01:44 ovsdb-server nb3.db
So, on a cluster leader the processing time dropped by 5.4x, on
followers - by 4.5x. More load-balancers - larger the performance
difference. There is a slight increase of memory usage, because new
reference structure is larger, but the difference is not significant.
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Acked-by: Dumitru Ceara <dceara@redhat.com>
2021-10-16 03:20:23 +02:00
|
|
|
|
struct hmap dst_refs; /* Weak references to this row. */
|
2010-03-15 15:41:54 -07:00
|
|
|
|
|
|
|
|
|
/* Number of strong refs to this row from other rows, in this table or
|
|
|
|
|
* other tables, through 'uuid' columns that have a 'refTable' constraint
|
|
|
|
|
* pointing to this table and a 'refType' of "strong". A row with nonzero
|
|
|
|
|
* 'n_refs' cannot be deleted. Updated and checked only at transaction
|
|
|
|
|
* commit. */
|
2010-02-08 14:09:41 -08:00
|
|
|
|
size_t n_refs;
|
|
|
|
|
|
2011-06-06 09:09:10 -07:00
|
|
|
|
/* One datum for each column (shash_count(&table->schema->columns)
|
|
|
|
|
* elements). */
|
2009-11-04 15:11:44 -08:00
|
|
|
|
struct ovsdb_datum fields[];
|
2011-06-06 09:09:10 -07:00
|
|
|
|
|
|
|
|
|
/* Followed by table->schema->n_indexes "struct hmap_node"s. In rows that
|
|
|
|
|
* have have been committed as part of the database, the hmap_node with
|
|
|
|
|
* index 'i' is contained in hmap table->indexes[i]. */
|
2009-11-04 15:11:44 -08:00
|
|
|
|
};
|
|
|
|
|
|
ovsdb: transaction: Incremental reassessment of weak refs.
The main idea is to not store list of weak references in the source
row, so they all don't need to be re-checked/updated on every
modification of that source row. The point is that source row already
knows UUIDs of all destination rows stored in the data, so there is no
much profit in storing this information somewhere else. If needed,
destination row can be looked up and reference can be looked up in the
destination row. For the fast lookup, destination row now stores
references in a hash map.
Weak reference structure now contains the table and uuid of a source
row instead of a direct pointer. This allows to replace/update the
source row without breaking any weak references stored in destination
rows.
Structure also now contains the key-value pair of atoms that triggered
creation of this reference. These atoms can be used to quickly
subtract removed references from a source row. During reassessment,
ovsdb now only needs to care about new added or removed atoms, and
atoms that got removed due to removal of the destination rows, but
these are marked for reassessment by the destination row.
ovsdb_datum_subtract() is used to remove atoms that points to removed
or incorrect rows, so there is no need to re-sort datum in the end.
Results of an OVN load-balancer benchmark that adds 3K load-balancers
to each of 120 logical switches and 120 logical routers in the OVN
sandbox with clustered Northbound database and then removes them:
Before:
%CPU CPU Time CMD
86.8 00:16:05 ovsdb-server nb1.db
44.1 00:08:11 ovsdb-server nb2.db
43.2 00:08:00 ovsdb-server nb3.db
After:
%CPU CPU Time CMD
54.9 00:02:58 ovsdb-server nb1.db
33.3 00:01:48 ovsdb-server nb2.db
32.2 00:01:44 ovsdb-server nb3.db
So, on a cluster leader the processing time dropped by 5.4x, on
followers - by 4.5x. More load-balancers - larger the performance
difference. There is a slight increase of memory usage, because new
reference structure is larger, but the difference is not significant.
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Acked-by: Dumitru Ceara <dceara@redhat.com>
2021-10-16 03:20:23 +02:00
|
|
|
|
uint32_t ovsdb_weak_ref_hash(const struct ovsdb_weak_ref *);
|
|
|
|
|
struct ovsdb_weak_ref * ovsdb_row_find_weak_ref(const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_weak_ref *);
|
|
|
|
|
void ovsdb_weak_ref_destroy(struct ovsdb_weak_ref *);
|
|
|
|
|
|
|
|
|
|
|
2009-11-04 15:11:44 -08:00
|
|
|
|
struct ovsdb_row *ovsdb_row_create(const struct ovsdb_table *);
|
|
|
|
|
struct ovsdb_row *ovsdb_row_clone(const struct ovsdb_row *);
|
ovsdb: Prepare snapshot JSON in a separate thread.
Conversion of the database data into JSON object, serialization
and destruction of that object are the most heavy operations
during the database compaction. If these operations are moved
to a separate thread, the main thread can continue processing
database requests in the meantime.
With this change, the compaction is split in 3 phases:
1. Initialization:
- Create a copy of the database.
- Remember current database index.
- Start a separate thread to convert a copy of the database
into serialized JSON object.
2. Wait:
- Continue normal operation until compaction thread is done.
- Meanwhile, compaction thread:
* Convert database copy to JSON.
* Serialize resulted JSON.
* Destroy original JSON object.
3. Finish:
- Destroy the database copy.
- Take the snapshot created by the thread.
- Write on disk.
The key for this schema to be fast is the ability to create
a shallow copy of the database. This doesn't take too much
time allowing the thread to do most of work.
Database copy is created and destroyed only by the main thread,
so there is no need for synchronization.
Such solution allows to reduce the time main thread is blocked
by compaction by 80-90%. For example, in ovn-heater tests
with 120 node density-heavy scenario, where compaction normally
takes 5-6 seconds at the end of a test, measured compaction
times was all below 1 second with the change applied. Also,
note that these measured times are the sum of phases 1 and 3,
so actual poll intervals are about half a second in this case.
Only implemented for raft storage for now. The implementation
for standalone databases can be added later by using a file
offset as a database index and copying newly added changes
from the old file to a new one during ovsdb_log_replace().
Reported-at: https://bugzilla.redhat.com/2069108
Acked-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
2022-07-01 01:34:07 +02:00
|
|
|
|
struct ovsdb_row *ovsdb_row_datum_clone(const struct ovsdb_row *);
|
2009-11-04 15:11:44 -08:00
|
|
|
|
void ovsdb_row_destroy(struct ovsdb_row *);
|
|
|
|
|
|
|
|
|
|
uint32_t ovsdb_row_hash_columns(const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_column_set *,
|
|
|
|
|
uint32_t basis);
|
|
|
|
|
bool ovsdb_row_equal_columns(const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_column_set *);
|
|
|
|
|
int ovsdb_row_compare_columns_3way(const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_column_set *);
|
2021-06-01 23:01:22 +02:00
|
|
|
|
struct ovsdb_error *ovsdb_row_update_columns(struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_column_set *,
|
|
|
|
|
bool xor);
|
2011-06-06 09:02:01 -07:00
|
|
|
|
void ovsdb_row_columns_to_string(const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_column_set *, struct ds *);
|
2009-11-04 15:11:44 -08:00
|
|
|
|
struct ovsdb_error *ovsdb_row_from_json(struct ovsdb_row *,
|
|
|
|
|
const struct json *,
|
2010-02-08 16:03:21 -08:00
|
|
|
|
struct ovsdb_symbol_table *,
|
2023-07-25 11:32:19 +02:00
|
|
|
|
struct ovsdb_column_set *included,
|
|
|
|
|
bool is_diff)
|
2014-12-15 14:10:38 +01:00
|
|
|
|
OVS_WARN_UNUSED_RESULT;
|
2009-11-04 15:11:44 -08:00
|
|
|
|
struct json *ovsdb_row_to_json(const struct ovsdb_row *,
|
|
|
|
|
const struct ovsdb_column_set *include);
|
2022-06-24 11:55:58 +02:00
|
|
|
|
void ovsdb_row_to_string(const struct ovsdb_row *, struct ds *);
|
2009-11-04 15:11:44 -08:00
|
|
|
|
|
|
|
|
|
static inline const struct uuid *
|
|
|
|
|
ovsdb_row_get_uuid(const struct ovsdb_row *row)
|
|
|
|
|
{
|
|
|
|
|
return &row->fields[OVSDB_COL_UUID].keys[0].uuid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline struct uuid *
|
|
|
|
|
ovsdb_row_get_uuid_rw(struct ovsdb_row *row)
|
|
|
|
|
{
|
2023-12-18 03:02:40 +01:00
|
|
|
|
ovsdb_datum_unshare(&row->fields[OVSDB_COL_UUID], &ovsdb_type_uuid);
|
2009-11-04 15:11:44 -08:00
|
|
|
|
return &row->fields[OVSDB_COL_UUID].keys[0].uuid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const struct uuid *
|
|
|
|
|
ovsdb_row_get_version(const struct ovsdb_row *row)
|
|
|
|
|
{
|
|
|
|
|
return &row->fields[OVSDB_COL_VERSION].keys[0].uuid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline struct uuid *
|
|
|
|
|
ovsdb_row_get_version_rw(struct ovsdb_row *row)
|
|
|
|
|
{
|
2023-12-18 03:02:40 +01:00
|
|
|
|
ovsdb_datum_unshare(&row->fields[OVSDB_COL_VERSION], &ovsdb_type_uuid);
|
2009-11-04 15:11:44 -08:00
|
|
|
|
return &row->fields[OVSDB_COL_VERSION].keys[0].uuid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline uint32_t
|
|
|
|
|
ovsdb_row_hash(const struct ovsdb_row *row)
|
|
|
|
|
{
|
|
|
|
|
return uuid_hash(ovsdb_row_get_uuid(row));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* An unordered collection of rows. */
|
|
|
|
|
struct ovsdb_row_set {
|
|
|
|
|
const struct ovsdb_row **rows;
|
|
|
|
|
size_t n_rows, allocated_rows;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define OVSDB_ROW_SET_INITIALIZER { NULL, 0, 0 }
|
|
|
|
|
|
|
|
|
|
void ovsdb_row_set_init(struct ovsdb_row_set *);
|
|
|
|
|
void ovsdb_row_set_destroy(struct ovsdb_row_set *);
|
|
|
|
|
void ovsdb_row_set_add_row(struct ovsdb_row_set *, const struct ovsdb_row *);
|
|
|
|
|
|
|
|
|
|
struct json *ovsdb_row_set_to_json(const struct ovsdb_row_set *,
|
|
|
|
|
const struct ovsdb_column_set *);
|
|
|
|
|
|
|
|
|
|
void ovsdb_row_set_sort(struct ovsdb_row_set *,
|
|
|
|
|
const struct ovsdb_column_set *);
|
|
|
|
|
|
|
|
|
|
/* A hash table of rows. A specified set of columns is used for hashing and
|
|
|
|
|
* comparing rows.
|
|
|
|
|
*
|
|
|
|
|
* The row hash doesn't necessarily own its rows. They may be owned by, for
|
|
|
|
|
* example, an ovsdb_table. */
|
|
|
|
|
struct ovsdb_row_hash {
|
|
|
|
|
struct hmap rows;
|
|
|
|
|
struct ovsdb_column_set columns;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define OVSDB_ROW_HASH_INITIALIZER(RH) \
|
|
|
|
|
{ HMAP_INITIALIZER(&(RH).rows), OVSDB_COLUMN_SET_INITIALIZER }
|
|
|
|
|
|
|
|
|
|
struct ovsdb_row_hash_node {
|
|
|
|
|
struct hmap_node hmap_node;
|
|
|
|
|
const struct ovsdb_row *row;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void ovsdb_row_hash_init(struct ovsdb_row_hash *,
|
|
|
|
|
const struct ovsdb_column_set *);
|
|
|
|
|
void ovsdb_row_hash_destroy(struct ovsdb_row_hash *, bool destroy_rows);
|
|
|
|
|
size_t ovsdb_row_hash_count(const struct ovsdb_row_hash *);
|
|
|
|
|
bool ovsdb_row_hash_contains(const struct ovsdb_row_hash *,
|
|
|
|
|
const struct ovsdb_row *);
|
|
|
|
|
bool ovsdb_row_hash_contains_all(const struct ovsdb_row_hash *,
|
|
|
|
|
const struct ovsdb_row_hash *);
|
|
|
|
|
bool ovsdb_row_hash_insert(struct ovsdb_row_hash *, const struct ovsdb_row *);
|
|
|
|
|
bool ovsdb_row_hash_contains__(const struct ovsdb_row_hash *,
|
|
|
|
|
const struct ovsdb_row *, size_t hash);
|
|
|
|
|
bool ovsdb_row_hash_insert__(struct ovsdb_row_hash *,
|
|
|
|
|
const struct ovsdb_row *, size_t hash);
|
|
|
|
|
|
|
|
|
|
#endif /* ovsdb/row.h */
|