2016-08-13 21:52:27 -07:00
|
|
|
|
/* Copyright (c) 2009, 2010, 2011, 2012, 2016 Nicira, Inc.
|
2017-08-03 14:20:15 -04:00
|
|
|
|
* Copyright (C) 2016 Hewlett Packard Enterprise Development LP
|
2009-12-02 11:26:15 -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_IDL_PROVIDER_H
|
|
|
|
|
#define OVSDB_IDL_PROVIDER_H 1
|
|
|
|
|
|
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-12-02 11:26:15 -08:00
|
|
|
|
#include "ovsdb-idl.h"
|
ovsdb-idl: Add partial map updates functionality.
In the current implementation, every time an element of either a map or set
column has to be modified, the entire content of the column is sent to the
server to be updated. This is not a major problem if the information contained
in the column for the corresponding row is small, but there are cases where
these columns can have a significant amount of elements per row, or these
values are updated frequently, therefore the cost of the modifications becomes
high in terms of time and bandwidth.
In this solution, the ovsdb-idl code is modified to use the RFC 7047 'mutate'
operation, to allow sending partial modifications on map columns to the server.
The functionality is exposed to clients in the vswitch idl. This was
implemented through map operations.
A map operation is defined as an insertion, update or deletion of a key-value
pair inside a map. The idea is to minimize the amount of map operations
that are send to the OVSDB server when a transaction is committed.
In order to keep track of the requested map operations, structs map_op and
map_op_list were defined with accompanying functions to manipulate them. These
functions make sure that only one operation is send to the server for each
key-value that wants to be modified, so multiple operation on a key value are
collapsed into a single operation.
As an example, if a client using the IDL updates several times the value for
the same key, the functions will ensure that only the last value is send to
the server, instead of multiple updates. Or, if the client inserts a key-value,
and later on deletes the key before committing the transaction, then both
actions cancel out and no map operation is send for that key.
To keep track of the desired map operations on each transaction, a list of map
operations (struct map_op_list) is created for every column on the row on which
a map operation is performed. When a new map operation is requested on the same
column, the corresponding map_op_list is checked to verify if a previous
operations was performed on the same key, on the same transaction. If there is
no previous operation, then the new operation is just added into the list. But
if there was a previous operation on the same key, then the previous operation
is collapsed with the new operation into a single operation that preserves the
final result if both operations were to be performed sequentially. This design
keep a small memory footprint during transactions.
When a transaction is committed, the map operations lists are checked and
all map operations that belong to the same map are grouped together into a
single JSON RPC "mutate" operation, in which each map_op is transformed into
the necessary "insert" or "delete" mutators. Then the "mutate" operation is
added to the operations that will be send to the server.
Once the transaction is finished, all map operation lists are cleared and
deleted, so the next transaction starts with a clean board for map operations.
Using different structures and logic to handle map operations, instead of
trying to force the current structures (like 'old' and 'new' datums in the row)
to handle then, ensures that map operations won't mess up with the current
logic to generate JSON messages for other operations, avoids duplicating the
whole map for just a few changes, and is faster for insert and delete
operations, because there is no need to maintain the invariants in the 'new'
datum.
Signed-off-by: Edward Aymerich <edward.aymerich@hpe.com>
Signed-off-by: Arnoldo Lutz <arnoldo.lutz.guevara@hpe.com>
Co-authored-by: Arnoldo Lutz <arnoldo.lutz.guevara@hpe.com>
[blp@ovn.org made style changes and factored out error checking]
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-05-02 13:59:44 -06:00
|
|
|
|
#include "ovsdb-map-op.h"
|
2016-08-06 17:46:29 -05:00
|
|
|
|
#include "ovsdb-set-op.h"
|
2009-12-02 11:26:15 -08:00
|
|
|
|
#include "ovsdb-types.h"
|
2016-07-12 16:37:34 -05:00
|
|
|
|
#include "openvswitch/shash.h"
|
2021-08-26 18:56:13 -04:00
|
|
|
|
#include "sset.h"
|
2009-12-02 11:26:15 -08:00
|
|
|
|
#include "uuid.h"
|
|
|
|
|
|
2017-11-30 11:11:50 -08:00
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-08-28 23:21:40 -07:00
|
|
|
|
/* A local copy of a row in an OVSDB table, replicated from an OVSDB server.
|
|
|
|
|
* This structure is used as a header for a larger structure that translates
|
|
|
|
|
* the "struct ovsdb_datum"s into easier-to-use forms, via the ->parse() and
|
|
|
|
|
* ->unparse functions in struct ovsdb_idl_column. (Those functions are
|
|
|
|
|
* generated automatically via ovsdb-idlc.)
|
|
|
|
|
*
|
|
|
|
|
* When no transaction is in progress:
|
|
|
|
|
*
|
2017-08-11 11:06:47 -07:00
|
|
|
|
* - 'old_datum' points to the data committed to the database and currently
|
2016-08-28 23:21:40 -07:00
|
|
|
|
* in the row.
|
|
|
|
|
*
|
2017-08-11 11:06:47 -07:00
|
|
|
|
* - 'new_datum == old_datum'.
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*
|
|
|
|
|
* When a transaction is in progress, the situation is a little different. For
|
2017-08-11 11:06:47 -07:00
|
|
|
|
* a row inserted in the transaction, 'old_datum' is NULL and 'new_datum'
|
|
|
|
|
* points to the row's initial contents. Otherwise:
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*
|
2017-08-11 11:06:47 -07:00
|
|
|
|
* - 'old_datum' points to the data committed to the database and currently
|
|
|
|
|
* in the row. (This is the same as when no transaction is in progress.)
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*
|
2017-08-11 11:06:47 -07:00
|
|
|
|
* - If the transaction does not modify the row, 'new_datum == old_datum'.
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*
|
2017-08-11 11:06:46 -07:00
|
|
|
|
* - If the transaction modifies the row, 'new_datum' points to the
|
|
|
|
|
* modified data.
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*
|
2017-08-11 11:06:46 -07:00
|
|
|
|
* - If the transaction deletes the row, 'new_datum' is NULL.
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*
|
|
|
|
|
* Thus:
|
|
|
|
|
*
|
2017-08-11 11:06:47 -07:00
|
|
|
|
* - 'old_datum' always points to committed data, except that it is NULL if
|
|
|
|
|
* the row is inserted within the current transaction.
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*
|
2017-08-11 11:06:46 -07:00
|
|
|
|
* - 'new_datum' always points to the newest, possibly uncommitted version
|
|
|
|
|
* of the row's data, except that it is NULL if the row is deleted within
|
|
|
|
|
* the current transaction.
|
2016-08-28 23:21:40 -07:00
|
|
|
|
*/
|
2009-12-02 11:26:15 -08:00
|
|
|
|
struct ovsdb_idl_row {
|
|
|
|
|
struct hmap_node hmap_node; /* In struct ovsdb_idl_table's 'rows'. */
|
|
|
|
|
struct uuid uuid; /* Row "_uuid" field. */
|
2014-12-15 14:10:38 +01:00
|
|
|
|
struct ovs_list src_arcs; /* Forward arcs (ovsdb_idl_arc.src_node). */
|
|
|
|
|
struct ovs_list dst_arcs; /* Backward arcs (ovsdb_idl_arc.dst_node). */
|
2009-12-02 11:26:15 -08:00
|
|
|
|
struct ovsdb_idl_table *table; /* Containing table. */
|
2017-08-11 11:06:47 -07:00
|
|
|
|
struct ovsdb_datum *old_datum; /* Committed data (null if orphaned). */
|
2022-11-27 22:56:13 -05:00
|
|
|
|
bool persist_uuid; /* Persist 'uuid' during insert txn if set. */
|
2019-05-17 12:56:33 -07:00
|
|
|
|
bool parsed; /* Whether the row is parsed. */
|
ovsdb-idl: Re-parse backrefs of inserted rows only once.
While adding new rows ovsdb-idl re-parses all the other rows that
references this new one. For example, current ovn-kubernetes creates
load balancers and adds the same load balancer to all logical switches
and logical routers. So, then a new load balancer is added, rows for
all logical switches and routers re-parsed.
During initial database connection (or re-connection with
monitor/monitor_cond or monitor_cond_since with outdated last
transaction id) the client downloads the whole content of a database.
In case of OVN, there might be already thousands of load balancers
configured. ovsdb-idl will process rows in that initial monitor reply
one-by-one. Therefore, for each load balancer row, it will re-parse
all rows for switches and routers.
Assuming that we have 120 Logical Switches and 30K load balancers.
Processing of the initial monitor reply will take 120 (switch rows) *
30K (load balancer references in a switch row) * 30K (load balancer
rows) = 10^11 operations, which may take hours. ovn-kubernetes will
use LB groups eventually, but there are other less obvious cases that
cannot be changed that easily.
Re-parsing doesn't change any internal structures of the IDL. It
destroys and re-creates exactly same arcs between rows. The only
thing that changes is the application-facing array of pointers.
Since internal structures remains intact, suggested solution is to
postpone the re-parsing of back references until all the monitor
updates processed. This way we can re-parse each row only once.
Tested in a sandbox with 120 LSs, 120 LRs and 3K LBs, where each
load balancer added to each LS and LR, by re-statring ovn-northd and
measuring the time spent in ovsdb_idl_run().
Before the change:
OVN_Southbound: ovsdb_idl_run took: 924 ms
OVN_Northbound: ovsdb_idl_run took: 825118 ms --> 13.75 minutes!
After:
OVN_Southbound: ovsdb_idl_run took: 692 ms
OVN_Northbound: ovsdb_idl_run took: 1698 ms
Acked-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
2021-11-19 01:40:33 +01:00
|
|
|
|
struct ovs_list reparse_node; /* Rows that needs to be re-parsed due to
|
|
|
|
|
* insertion of a referenced row. */
|
2009-12-07 17:08:04 -08:00
|
|
|
|
|
|
|
|
|
/* Transactional data. */
|
2017-08-11 11:06:46 -07:00
|
|
|
|
struct ovsdb_datum *new_datum; /* Modified data (null to delete row). */
|
2017-08-11 11:06:47 -07:00
|
|
|
|
unsigned long int *prereqs; /* Bitmap of "old_datum" columns to verify. */
|
2017-08-11 11:06:46 -07:00
|
|
|
|
unsigned long int *written; /* Bitmap of "new_datum" columns to write. */
|
2009-12-07 17:08:04 -08:00
|
|
|
|
struct hmap_node txn_node; /* Node in ovsdb_idl_txn's list. */
|
ovsdb-idl: Add partial map updates functionality.
In the current implementation, every time an element of either a map or set
column has to be modified, the entire content of the column is sent to the
server to be updated. This is not a major problem if the information contained
in the column for the corresponding row is small, but there are cases where
these columns can have a significant amount of elements per row, or these
values are updated frequently, therefore the cost of the modifications becomes
high in terms of time and bandwidth.
In this solution, the ovsdb-idl code is modified to use the RFC 7047 'mutate'
operation, to allow sending partial modifications on map columns to the server.
The functionality is exposed to clients in the vswitch idl. This was
implemented through map operations.
A map operation is defined as an insertion, update or deletion of a key-value
pair inside a map. The idea is to minimize the amount of map operations
that are send to the OVSDB server when a transaction is committed.
In order to keep track of the requested map operations, structs map_op and
map_op_list were defined with accompanying functions to manipulate them. These
functions make sure that only one operation is send to the server for each
key-value that wants to be modified, so multiple operation on a key value are
collapsed into a single operation.
As an example, if a client using the IDL updates several times the value for
the same key, the functions will ensure that only the last value is send to
the server, instead of multiple updates. Or, if the client inserts a key-value,
and later on deletes the key before committing the transaction, then both
actions cancel out and no map operation is send for that key.
To keep track of the desired map operations on each transaction, a list of map
operations (struct map_op_list) is created for every column on the row on which
a map operation is performed. When a new map operation is requested on the same
column, the corresponding map_op_list is checked to verify if a previous
operations was performed on the same key, on the same transaction. If there is
no previous operation, then the new operation is just added into the list. But
if there was a previous operation on the same key, then the previous operation
is collapsed with the new operation into a single operation that preserves the
final result if both operations were to be performed sequentially. This design
keep a small memory footprint during transactions.
When a transaction is committed, the map operations lists are checked and
all map operations that belong to the same map are grouped together into a
single JSON RPC "mutate" operation, in which each map_op is transformed into
the necessary "insert" or "delete" mutators. Then the "mutate" operation is
added to the operations that will be send to the server.
Once the transaction is finished, all map operation lists are cleared and
deleted, so the next transaction starts with a clean board for map operations.
Using different structures and logic to handle map operations, instead of
trying to force the current structures (like 'old' and 'new' datums in the row)
to handle then, ensures that map operations won't mess up with the current
logic to generate JSON messages for other operations, avoids duplicating the
whole map for just a few changes, and is faster for insert and delete
operations, because there is no need to maintain the invariants in the 'new'
datum.
Signed-off-by: Edward Aymerich <edward.aymerich@hpe.com>
Signed-off-by: Arnoldo Lutz <arnoldo.lutz.guevara@hpe.com>
Co-authored-by: Arnoldo Lutz <arnoldo.lutz.guevara@hpe.com>
[blp@ovn.org made style changes and factored out error checking]
Signed-off-by: Ben Pfaff <blp@ovn.org>
2016-05-02 13:59:44 -06:00
|
|
|
|
unsigned long int *map_op_written; /* Bitmap of columns pending map ops. */
|
|
|
|
|
struct map_op_list **map_op_lists; /* Per-column map operations. */
|
2016-08-06 17:46:29 -05:00
|
|
|
|
unsigned long int *set_op_written; /* Bitmap of columns pending set ops. */
|
|
|
|
|
struct set_op_list **set_op_lists; /* Per-column set operations. */
|
ovsdb-idl: Add support for change tracking.
Ovsdb-idl notifies a client that something changed; it does not track
which table, row changed in what way (insert, modify or delete).
As a result, a client has to scan or reconfigure the entire idl after
ovsdb_idl_run(). This is presumably fine for typical ovs schemas where
tables are relatively small. In use-cases where ovsdb is used with
schemas that can have very large tables, the current ovsdb-idl
notification mechanism does not appear to scale - clients need to do a
lot of processing to determine the exact change delta.
This change adds support for:
- Table and row based change sequence numbers to record the
most recent IDL change sequence numbers associated with insert,
modify or delete update on that table or row.
- Change tracking of specific columns. This ensures that changed
rows (inserted, modified, deleted) that have tracked columns, are
tracked by IDL. The client can directly access the changed rows
with get_first, get_next operations without the need to scan the
entire table.
The tracking functionality is not enabled by default and needs to
be turned on per-column by the client after ovsdb_idl_create()
and before ovsdb_idl_run().
/* Example Usage */
idl = ovsdb_idl_create(...);
/* Track specific columns */
ovsdb_idl_track_add_column(idl, column);
/* Or, track all columns */
ovsdb_idl_track_add_all(idl);
for (;;) {
ovsdb_idl_run(idl);
seqno = ovsdb_idl_get_seqno(idl);
/* Process only the changed rows in Table FOO */
FOO_FOR_EACH_TRACKED(row, idl) {
/* Determine the type of change from the row seqnos */
if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE)
>= seqno)) {
printf("row deleted\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_MODIFY)
>= seqno))
printf("row modified\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_INSERT)
>= seqno))
printf("row inserted\n");
}
}
/* All changes processed - clear the change track */
ovsdb_idl_track_clear(idl);
}
Signed-off-by: Shad Ansari <shad.ansari@hp.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2015-10-27 13:55:35 -07:00
|
|
|
|
|
2015-12-10 01:12:31 -08:00
|
|
|
|
/* Tracking data */
|
ovsdb-idl: Add support for change tracking.
Ovsdb-idl notifies a client that something changed; it does not track
which table, row changed in what way (insert, modify or delete).
As a result, a client has to scan or reconfigure the entire idl after
ovsdb_idl_run(). This is presumably fine for typical ovs schemas where
tables are relatively small. In use-cases where ovsdb is used with
schemas that can have very large tables, the current ovsdb-idl
notification mechanism does not appear to scale - clients need to do a
lot of processing to determine the exact change delta.
This change adds support for:
- Table and row based change sequence numbers to record the
most recent IDL change sequence numbers associated with insert,
modify or delete update on that table or row.
- Change tracking of specific columns. This ensures that changed
rows (inserted, modified, deleted) that have tracked columns, are
tracked by IDL. The client can directly access the changed rows
with get_first, get_next operations without the need to scan the
entire table.
The tracking functionality is not enabled by default and needs to
be turned on per-column by the client after ovsdb_idl_create()
and before ovsdb_idl_run().
/* Example Usage */
idl = ovsdb_idl_create(...);
/* Track specific columns */
ovsdb_idl_track_add_column(idl, column);
/* Or, track all columns */
ovsdb_idl_track_add_all(idl);
for (;;) {
ovsdb_idl_run(idl);
seqno = ovsdb_idl_get_seqno(idl);
/* Process only the changed rows in Table FOO */
FOO_FOR_EACH_TRACKED(row, idl) {
/* Determine the type of change from the row seqnos */
if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE)
>= seqno)) {
printf("row deleted\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_MODIFY)
>= seqno))
printf("row modified\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_INSERT)
>= seqno))
printf("row inserted\n");
}
}
/* All changes processed - clear the change track */
ovsdb_idl_track_clear(idl);
}
Signed-off-by: Shad Ansari <shad.ansari@hp.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2015-10-27 13:55:35 -07:00
|
|
|
|
unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX];
|
2015-12-10 01:12:31 -08:00
|
|
|
|
struct ovs_list track_node; /* Rows modified/added/deleted by IDL */
|
|
|
|
|
unsigned long int *updated; /* Bitmap of columns updated by IDL */
|
2019-05-17 12:56:33 -07:00
|
|
|
|
struct ovsdb_datum *tracked_old_datum; /* Old deleted data. */
|
2009-12-02 11:26:15 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_column {
|
|
|
|
|
char *name;
|
|
|
|
|
struct ovsdb_type type;
|
2017-08-11 11:06:45 -07:00
|
|
|
|
bool is_mutable;
|
2016-10-07 09:47:43 -07:00
|
|
|
|
bool is_synthetic;
|
2010-01-25 10:15:17 -08:00
|
|
|
|
void (*parse)(struct ovsdb_idl_row *, const struct ovsdb_datum *);
|
|
|
|
|
void (*unparse)(struct ovsdb_idl_row *);
|
2009-12-02 11:26:15 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_table_class {
|
|
|
|
|
char *name;
|
2011-03-10 11:15:01 -08:00
|
|
|
|
bool is_root;
|
2017-09-12 12:57:46 -07:00
|
|
|
|
bool is_singleton;
|
2009-12-02 11:26:15 -08:00
|
|
|
|
const struct ovsdb_idl_column *columns;
|
|
|
|
|
size_t n_columns;
|
|
|
|
|
size_t allocation_size;
|
2012-05-22 01:53:07 -07:00
|
|
|
|
void (*row_init)(struct ovsdb_idl_row *);
|
2009-12-02 11:26:15 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_table {
|
2017-08-11 11:06:44 -07:00
|
|
|
|
const struct ovsdb_idl_table_class *class_;
|
2010-11-16 09:14:52 -08:00
|
|
|
|
unsigned char *modes; /* OVSDB_IDL_* bitmasks, indexed by column. */
|
2015-11-27 16:57:07 +00:00
|
|
|
|
bool need_table; /* Monitor table even if no columns are selected
|
|
|
|
|
* for replication. */
|
2009-12-02 11:26:15 -08:00
|
|
|
|
struct shash columns; /* Contains "const struct ovsdb_idl_column *"s. */
|
2025-06-27 14:09:05 +02:00
|
|
|
|
struct shash schema_columns; /* Contains "const struct ovsdb_type *" per
|
|
|
|
|
* column as defined in the server schema. */
|
2009-12-02 11:26:15 -08:00
|
|
|
|
struct hmap rows; /* Contains "struct ovsdb_idl_row"s. */
|
2020-11-21 11:47:01 -08:00
|
|
|
|
struct ovsdb_idl *idl; /* Containing IDL instance. */
|
ovsdb-idl: Add support for change tracking.
Ovsdb-idl notifies a client that something changed; it does not track
which table, row changed in what way (insert, modify or delete).
As a result, a client has to scan or reconfigure the entire idl after
ovsdb_idl_run(). This is presumably fine for typical ovs schemas where
tables are relatively small. In use-cases where ovsdb is used with
schemas that can have very large tables, the current ovsdb-idl
notification mechanism does not appear to scale - clients need to do a
lot of processing to determine the exact change delta.
This change adds support for:
- Table and row based change sequence numbers to record the
most recent IDL change sequence numbers associated with insert,
modify or delete update on that table or row.
- Change tracking of specific columns. This ensures that changed
rows (inserted, modified, deleted) that have tracked columns, are
tracked by IDL. The client can directly access the changed rows
with get_first, get_next operations without the need to scan the
entire table.
The tracking functionality is not enabled by default and needs to
be turned on per-column by the client after ovsdb_idl_create()
and before ovsdb_idl_run().
/* Example Usage */
idl = ovsdb_idl_create(...);
/* Track specific columns */
ovsdb_idl_track_add_column(idl, column);
/* Or, track all columns */
ovsdb_idl_track_add_all(idl);
for (;;) {
ovsdb_idl_run(idl);
seqno = ovsdb_idl_get_seqno(idl);
/* Process only the changed rows in Table FOO */
FOO_FOR_EACH_TRACKED(row, idl) {
/* Determine the type of change from the row seqnos */
if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE)
>= seqno)) {
printf("row deleted\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_MODIFY)
>= seqno))
printf("row modified\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_INSERT)
>= seqno))
printf("row inserted\n");
}
}
/* All changes processed - clear the change track */
ovsdb_idl_track_clear(idl);
}
Signed-off-by: Shad Ansari <shad.ansari@hp.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2015-10-27 13:55:35 -07:00
|
|
|
|
unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX];
|
2021-08-26 18:56:13 -04:00
|
|
|
|
bool in_server_schema; /* Indicates if this table is in the server schema
|
|
|
|
|
* or not. */
|
2018-06-07 21:07:34 -07:00
|
|
|
|
struct ovs_list indexes; /* Contains "struct ovsdb_idl_index"s */
|
ovsdb-idl: Add support for change tracking.
Ovsdb-idl notifies a client that something changed; it does not track
which table, row changed in what way (insert, modify or delete).
As a result, a client has to scan or reconfigure the entire idl after
ovsdb_idl_run(). This is presumably fine for typical ovs schemas where
tables are relatively small. In use-cases where ovsdb is used with
schemas that can have very large tables, the current ovsdb-idl
notification mechanism does not appear to scale - clients need to do a
lot of processing to determine the exact change delta.
This change adds support for:
- Table and row based change sequence numbers to record the
most recent IDL change sequence numbers associated with insert,
modify or delete update on that table or row.
- Change tracking of specific columns. This ensures that changed
rows (inserted, modified, deleted) that have tracked columns, are
tracked by IDL. The client can directly access the changed rows
with get_first, get_next operations without the need to scan the
entire table.
The tracking functionality is not enabled by default and needs to
be turned on per-column by the client after ovsdb_idl_create()
and before ovsdb_idl_run().
/* Example Usage */
idl = ovsdb_idl_create(...);
/* Track specific columns */
ovsdb_idl_track_add_column(idl, column);
/* Or, track all columns */
ovsdb_idl_track_add_all(idl);
for (;;) {
ovsdb_idl_run(idl);
seqno = ovsdb_idl_get_seqno(idl);
/* Process only the changed rows in Table FOO */
FOO_FOR_EACH_TRACKED(row, idl) {
/* Determine the type of change from the row seqnos */
if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE)
>= seqno)) {
printf("row deleted\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_MODIFY)
>= seqno))
printf("row modified\n");
} else if (foo_row_get_seqno(row, OVSDB_IDL_CHANGE_INSERT)
>= seqno))
printf("row inserted\n");
}
}
/* All changes processed - clear the change track */
ovsdb_idl_track_clear(idl);
}
Signed-off-by: Shad Ansari <shad.ansari@hp.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2015-10-27 13:55:35 -07:00
|
|
|
|
struct ovs_list track_list; /* Tracked rows (ovsdb_idl_row.track_node). */
|
2009-12-02 11:26:15 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_class {
|
2010-02-09 10:17:58 -08:00
|
|
|
|
const char *database; /* <db-name> for this database. */
|
2009-12-02 11:26:15 -08:00
|
|
|
|
const struct ovsdb_idl_table_class *tables;
|
|
|
|
|
size_t n_tables;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_row *ovsdb_idl_get_row_arc(
|
|
|
|
|
struct ovsdb_idl_row *src,
|
2016-08-24 23:10:15 -07:00
|
|
|
|
const struct ovsdb_idl_table_class *dst_table,
|
2009-12-02 11:26:15 -08:00
|
|
|
|
const struct uuid *dst_uuid);
|
|
|
|
|
|
2009-12-07 17:08:04 -08:00
|
|
|
|
void ovsdb_idl_txn_verify(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *);
|
|
|
|
|
|
2009-12-08 17:14:56 -08:00
|
|
|
|
struct ovsdb_idl_txn *ovsdb_idl_txn_get(const struct ovsdb_idl_row *);
|
2018-06-07 21:07:34 -07:00
|
|
|
|
|
|
|
|
|
/* Index internals. */
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_index {
|
|
|
|
|
struct ovs_list node; /* In ->table->indexes. */
|
|
|
|
|
struct ovsdb_idl_table *table; /* The indexed table. */
|
|
|
|
|
struct ovsdb_idl_index_column *columns; /* The indexed columns. */
|
|
|
|
|
size_t n_columns;
|
|
|
|
|
|
|
|
|
|
/* Skiplist with pointers to rows. */
|
|
|
|
|
struct skiplist *skiplist;
|
|
|
|
|
|
|
|
|
|
/* True if a row in the index is being inserted or deleted. If true, the
|
|
|
|
|
search key is augmented with the UUID and address to discriminate
|
|
|
|
|
between entries with identical keys. */
|
|
|
|
|
bool ins_del;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int ovsdb_idl_index_compare(struct ovsdb_idl_index *,
|
|
|
|
|
const struct ovsdb_idl_row *a,
|
|
|
|
|
const struct ovsdb_idl_row *b);
|
|
|
|
|
|
|
|
|
|
void ovsdb_idl_index_write(struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
struct ovsdb_datum *,
|
|
|
|
|
const struct ovsdb_idl_table_class *);
|
|
|
|
|
struct ovsdb_idl_row *ovsdb_idl_index_init_row(struct ovsdb_idl_index *);
|
|
|
|
|
void ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row *);
|
2009-12-08 17:14:56 -08:00
|
|
|
|
|
2017-11-30 11:11:50 -08:00
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-12-02 11:26:15 -08:00
|
|
|
|
#endif /* ovsdb-idl-provider.h */
|