2016-07-24 13:14:59 -07:00
|
|
|
|
/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
|
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_H
|
|
|
|
|
#define OVSDB_IDL_H 1
|
|
|
|
|
|
2010-06-23 10:13:39 -07:00
|
|
|
|
/* Open vSwitch Database Interface Definition Language (OVSDB IDL).
|
|
|
|
|
*
|
|
|
|
|
* The OVSDB IDL maintains an in-memory replica of a database. It issues RPC
|
|
|
|
|
* requests to an OVSDB database server and parses the responses, converting
|
|
|
|
|
* raw JSON into data structures that are easier for clients to digest. Most
|
|
|
|
|
* notably, references to rows via UUID become C pointers.
|
|
|
|
|
*
|
2015-06-11 10:47:47 -07:00
|
|
|
|
* The IDL always presents a consistent snapshot of the database to its client,
|
|
|
|
|
* that is, it won't present the effects of some part of a transaction applied
|
|
|
|
|
* at the database server without presenting all of its effects.
|
|
|
|
|
*
|
2010-06-23 10:13:39 -07:00
|
|
|
|
* The IDL also assists with issuing database transactions. The client creates
|
|
|
|
|
* a transaction, manipulates the IDL data structures, and commits or aborts
|
|
|
|
|
* the transaction. The IDL then composes and issues the necessary JSON-RPC
|
|
|
|
|
* requests and reports to the client whether the transaction completed
|
|
|
|
|
* successfully.
|
|
|
|
|
*/
|
|
|
|
|
|
2010-01-14 13:10:35 -08:00
|
|
|
|
#include <stdbool.h>
|
2009-12-16 16:26:17 -08:00
|
|
|
|
#include <stdint.h>
|
2010-03-08 14:18:44 -08:00
|
|
|
|
#include "compiler.h"
|
2010-06-16 14:35:48 -07:00
|
|
|
|
#include "ovsdb-types.h"
|
2016-07-18 11:45:58 +03:00
|
|
|
|
#include "ovsdb-data.h"
|
|
|
|
|
#include "openvswitch/list.h"
|
|
|
|
|
#include "ovsdb-condition.h"
|
2009-12-16 16:26:17 -08:00
|
|
|
|
|
|
|
|
|
struct json;
|
2010-01-25 10:15:17 -08:00
|
|
|
|
struct ovsdb_datum;
|
2009-12-02 11:26:15 -08:00
|
|
|
|
struct ovsdb_idl_class;
|
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 ovsdb_idl_row;
|
2010-01-25 10:15:17 -08:00
|
|
|
|
struct ovsdb_idl_column;
|
|
|
|
|
struct ovsdb_idl_table_class;
|
|
|
|
|
struct uuid;
|
2009-12-02 11:26:15 -08:00
|
|
|
|
|
|
|
|
|
struct ovsdb_idl *ovsdb_idl_create(const char *remote,
|
2010-11-16 09:14:52 -08:00
|
|
|
|
const struct ovsdb_idl_class *,
|
2013-03-15 16:14:28 -07:00
|
|
|
|
bool monitor_everything_by_default,
|
|
|
|
|
bool retry);
|
2016-04-12 08:43:59 -05:00
|
|
|
|
void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *, bool);
|
2009-12-02 11:26:15 -08:00
|
|
|
|
void ovsdb_idl_destroy(struct ovsdb_idl *);
|
|
|
|
|
|
2012-03-27 10:16:52 -07:00
|
|
|
|
void ovsdb_idl_run(struct ovsdb_idl *);
|
2009-12-02 11:26:15 -08:00
|
|
|
|
void ovsdb_idl_wait(struct ovsdb_idl *);
|
|
|
|
|
|
2011-07-26 16:49:03 -07:00
|
|
|
|
void ovsdb_idl_set_lock(struct ovsdb_idl *, const char *lock_name);
|
|
|
|
|
bool ovsdb_idl_has_lock(const struct ovsdb_idl *);
|
|
|
|
|
bool ovsdb_idl_is_lock_contended(const struct ovsdb_idl *);
|
|
|
|
|
|
2016-07-18 11:45:56 +03:00
|
|
|
|
const struct uuid * ovsdb_idl_get_monitor_id(const struct ovsdb_idl *);
|
2009-12-02 11:26:15 -08:00
|
|
|
|
unsigned int ovsdb_idl_get_seqno(const struct ovsdb_idl *);
|
2010-01-14 13:10:35 -08:00
|
|
|
|
bool ovsdb_idl_has_ever_connected(const struct ovsdb_idl *);
|
2014-02-18 13:19:36 -08:00
|
|
|
|
void ovsdb_idl_enable_reconnect(struct ovsdb_idl *);
|
2009-12-02 11:26:15 -08:00
|
|
|
|
void ovsdb_idl_force_reconnect(struct ovsdb_idl *);
|
2012-09-20 11:13:15 -07:00
|
|
|
|
void ovsdb_idl_verify_write_only(struct ovsdb_idl *);
|
2013-03-15 16:14:28 -07:00
|
|
|
|
|
|
|
|
|
bool ovsdb_idl_is_alive(const struct ovsdb_idl *);
|
|
|
|
|
int ovsdb_idl_get_last_error(const struct ovsdb_idl *);
|
2016-03-25 02:18:34 +08:00
|
|
|
|
|
|
|
|
|
void ovsdb_idl_set_probe_interval(const struct ovsdb_idl *, int probe_interval);
|
2010-11-16 09:14:52 -08:00
|
|
|
|
|
|
|
|
|
/* Choosing columns and tables to replicate. */
|
|
|
|
|
|
|
|
|
|
/* Modes with which the IDL can monitor a column.
|
|
|
|
|
*
|
|
|
|
|
* If no bits are set, the column is not monitored at all. Its value will
|
|
|
|
|
* always appear to the client to be the default value for its type.
|
|
|
|
|
*
|
|
|
|
|
* If OVSDB_IDL_MONITOR is set, then the column is replicated. Its value will
|
2012-03-27 10:16:52 -07:00
|
|
|
|
* reflect the value in the database. If OVSDB_IDL_ALERT is also set, then the
|
|
|
|
|
* value returned by ovsdb_idl_get_seqno() will change when the column's value
|
|
|
|
|
* changes.
|
2010-11-16 09:14:52 -08:00
|
|
|
|
*
|
|
|
|
|
* The possible mode combinations are:
|
|
|
|
|
*
|
|
|
|
|
* - 0, for a column that a client doesn't care about.
|
|
|
|
|
*
|
|
|
|
|
* - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT), for a column that a client wants
|
|
|
|
|
* to track and possibly update.
|
|
|
|
|
*
|
|
|
|
|
* - OVSDB_IDL_MONITOR, for columns that a client treats as "write-only",
|
|
|
|
|
* that is, it updates them but doesn't want to get alerted about its own
|
|
|
|
|
* updates. It also won't be alerted about other clients' updates, so this
|
|
|
|
|
* is suitable only for use by a client that "owns" a particular column.
|
|
|
|
|
*
|
|
|
|
|
* - OVDSB_IDL_ALERT without OVSDB_IDL_MONITOR is not valid.
|
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
|
|
|
|
*
|
|
|
|
|
* - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_TRACK), for a column
|
|
|
|
|
* that a client wants to track using the change tracking
|
|
|
|
|
* ovsdb_idl_track_get_*() functions.
|
2010-11-16 09:14:52 -08:00
|
|
|
|
*/
|
|
|
|
|
#define OVSDB_IDL_MONITOR (1 << 0) /* Monitor this column? */
|
|
|
|
|
#define OVSDB_IDL_ALERT (1 << 1) /* Alert client when column updated? */
|
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
|
|
|
|
#define OVSDB_IDL_TRACK (1 << 2)
|
2010-11-16 09:14:52 -08:00
|
|
|
|
|
|
|
|
|
void ovsdb_idl_add_column(struct ovsdb_idl *, const struct ovsdb_idl_column *);
|
|
|
|
|
void ovsdb_idl_add_table(struct ovsdb_idl *,
|
|
|
|
|
const struct ovsdb_idl_table_class *);
|
2009-12-02 11:26:15 -08:00
|
|
|
|
|
2010-08-11 15:41:41 -07:00
|
|
|
|
void ovsdb_idl_omit(struct ovsdb_idl *, const struct ovsdb_idl_column *);
|
2010-11-16 09:14:52 -08:00
|
|
|
|
void ovsdb_idl_omit_alert(struct ovsdb_idl *, const struct ovsdb_idl_column *);
|
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
|
|
|
|
|
2016-04-22 16:35:37 -05:00
|
|
|
|
/* Change tracking.
|
|
|
|
|
*
|
|
|
|
|
* In OVSDB, change tracking is applied at each client in the IDL layer. This
|
|
|
|
|
* means that when a client makes a request to track changes on a particular
|
|
|
|
|
* table, they are essentially requesting information about the incremental
|
|
|
|
|
* changes to that table from the point in time that the request is made. Once
|
|
|
|
|
* the client clears tracked changes, that information will no longer be
|
|
|
|
|
* available.
|
|
|
|
|
*
|
|
|
|
|
* The implication of the above is that if a client requires replaying
|
|
|
|
|
* untracked history, it faces the choice of either trying to remember changes
|
|
|
|
|
* itself (which translates into a memory leak) or of being structured with a
|
|
|
|
|
* path for processing the full untracked table as well as a path that
|
|
|
|
|
* processes incremental changes. */
|
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
|
|
|
|
enum ovsdb_idl_change {
|
|
|
|
|
OVSDB_IDL_CHANGE_INSERT,
|
|
|
|
|
OVSDB_IDL_CHANGE_MODIFY,
|
|
|
|
|
OVSDB_IDL_CHANGE_DELETE,
|
|
|
|
|
OVSDB_IDL_CHANGE_MAX
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Row, table sequence numbers */
|
|
|
|
|
unsigned int ovsdb_idl_table_get_seqno(
|
|
|
|
|
const struct ovsdb_idl *idl,
|
|
|
|
|
const struct ovsdb_idl_table_class *table_class);
|
|
|
|
|
unsigned int ovsdb_idl_row_get_seqno(
|
|
|
|
|
const struct ovsdb_idl_row *row,
|
|
|
|
|
enum ovsdb_idl_change change);
|
|
|
|
|
|
|
|
|
|
void ovsdb_idl_track_add_column(struct ovsdb_idl *idl,
|
|
|
|
|
const struct ovsdb_idl_column *column);
|
|
|
|
|
void ovsdb_idl_track_add_all(struct ovsdb_idl *idl);
|
|
|
|
|
const struct ovsdb_idl_row *ovsdb_idl_track_get_first(
|
|
|
|
|
const struct ovsdb_idl *, const struct ovsdb_idl_table_class *);
|
|
|
|
|
const struct ovsdb_idl_row *ovsdb_idl_track_get_next(const struct ovsdb_idl_row *);
|
2015-12-10 01:12:31 -08:00
|
|
|
|
bool ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row,
|
|
|
|
|
const struct ovsdb_idl_column *column);
|
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
|
|
|
|
void ovsdb_idl_track_clear(const struct ovsdb_idl *);
|
|
|
|
|
|
2010-11-16 09:14:52 -08:00
|
|
|
|
|
|
|
|
|
/* Reading the database replica. */
|
2010-08-11 15:41:41 -07:00
|
|
|
|
|
2010-01-25 10:15:17 -08:00
|
|
|
|
const struct ovsdb_idl_row *ovsdb_idl_get_row_for_uuid(
|
|
|
|
|
const struct ovsdb_idl *, const struct ovsdb_idl_table_class *,
|
|
|
|
|
const struct uuid *);
|
|
|
|
|
const struct ovsdb_idl_row *ovsdb_idl_first_row(
|
|
|
|
|
const struct ovsdb_idl *, const struct ovsdb_idl_table_class *);
|
|
|
|
|
const struct ovsdb_idl_row *ovsdb_idl_next_row(const struct ovsdb_idl_row *);
|
|
|
|
|
|
2010-06-16 14:35:48 -07:00
|
|
|
|
const struct ovsdb_datum *ovsdb_idl_read(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *);
|
|
|
|
|
const struct ovsdb_datum *ovsdb_idl_get(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
enum ovsdb_atomic_type key_type,
|
|
|
|
|
enum ovsdb_atomic_type value_type);
|
2014-09-26 16:00:44 -07:00
|
|
|
|
bool ovsdb_idl_is_mutable(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *);
|
2011-04-13 11:10:44 -07:00
|
|
|
|
|
|
|
|
|
bool ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *);
|
2010-11-16 09:14:52 -08:00
|
|
|
|
|
2012-04-12 08:27:56 -07:00
|
|
|
|
/* Transactions.
|
|
|
|
|
*
|
|
|
|
|
* A transaction may modify the contents of a database by modifying the values
|
|
|
|
|
* of columns, deleting rows, inserting rows, or adding checks that columns in
|
|
|
|
|
* the database have not changed ("verify" operations), through
|
|
|
|
|
* ovsdb_idl_txn_*() functions. (The OVSDB IDL code generator produces helper
|
|
|
|
|
* functions that internally call the ovsdb_idl_txn_*() functions. These are
|
|
|
|
|
* likely to be more convenient.)
|
|
|
|
|
*
|
|
|
|
|
* Reading and writing columns and inserting and deleting rows are all
|
|
|
|
|
* straightforward. The reasons to verify columns are less obvious.
|
|
|
|
|
* Verification is the key to maintaining transactional integrity. Because
|
|
|
|
|
* OVSDB handles multiple clients, it can happen that between the time that
|
|
|
|
|
* OVSDB client A reads a column and writes a new value, OVSDB client B has
|
|
|
|
|
* written that column. Client A's write should not ordinarily overwrite
|
|
|
|
|
* client B's, especially if the column in question is a "map" column that
|
|
|
|
|
* contains several more or less independent data items. If client A adds a
|
|
|
|
|
* "verify" operation before it writes the column, then the transaction fails
|
|
|
|
|
* in case client B modifies it first. Client A will then see the new value of
|
|
|
|
|
* the column and compose a new transaction based on the new contents written
|
|
|
|
|
* by client B.
|
|
|
|
|
*
|
|
|
|
|
* When a transaction is complete, which must be before the next call to
|
|
|
|
|
* ovsdb_idl_run() on 'idl', call ovsdb_idl_txn_commit() or
|
|
|
|
|
* ovsdb_idl_txn_abort().
|
|
|
|
|
*
|
|
|
|
|
* The life-cycle of a transaction looks like this:
|
|
|
|
|
*
|
|
|
|
|
* 1. Create the transaction and record the initial sequence number:
|
|
|
|
|
*
|
|
|
|
|
* seqno = ovsdb_idl_get_seqno(idl);
|
|
|
|
|
* txn = ovsdb_idl_txn_create(idl);
|
|
|
|
|
*
|
|
|
|
|
* 2. Modify the database with ovsdb_idl_txn_*() functions directly or
|
|
|
|
|
* indirectly.
|
|
|
|
|
*
|
|
|
|
|
* 3. Commit the transaction by calling ovsdb_idl_txn_commit(). The first call
|
|
|
|
|
* to this function probably returns TXN_INCOMPLETE. The client must keep
|
|
|
|
|
* calling again along as this remains true, calling ovsdb_idl_run() in
|
|
|
|
|
* between to let the IDL do protocol processing. (If the client doesn't
|
|
|
|
|
* have anything else to do in the meantime, it can use
|
|
|
|
|
* ovsdb_idl_txn_commit_block() to avoid having to loop itself.)
|
|
|
|
|
*
|
|
|
|
|
* 4. If the final status is TXN_TRY_AGAIN, wait for ovsdb_idl_get_seqno() to
|
|
|
|
|
* change from the saved 'seqno' (it's possible that it's already changed,
|
|
|
|
|
* in which case the client should not wait at all), then start over from
|
|
|
|
|
* step 1. Only a call to ovsdb_idl_run() will change the return value of
|
|
|
|
|
* ovsdb_idl_get_seqno(). (ovsdb_idl_txn_commit_block() calls
|
|
|
|
|
* ovsdb_idl_run().)
|
|
|
|
|
*/
|
2010-06-16 14:35:48 -07:00
|
|
|
|
|
2009-12-07 17:08:04 -08:00
|
|
|
|
enum ovsdb_idl_txn_status {
|
2011-06-20 16:17:44 -07:00
|
|
|
|
TXN_UNCOMMITTED, /* Not yet committed or aborted. */
|
2009-12-16 16:26:17 -08:00
|
|
|
|
TXN_UNCHANGED, /* Transaction didn't include any changes. */
|
2009-12-07 17:08:04 -08:00
|
|
|
|
TXN_INCOMPLETE, /* Commit in progress, please wait. */
|
|
|
|
|
TXN_ABORTED, /* ovsdb_idl_txn_abort() called. */
|
|
|
|
|
TXN_SUCCESS, /* Commit successful. */
|
2012-03-27 10:16:52 -07:00
|
|
|
|
TXN_TRY_AGAIN, /* Commit failed because a "verify" operation
|
2009-12-07 17:08:04 -08:00
|
|
|
|
* reported an inconsistency, due to a network
|
2011-10-31 09:15:14 -07:00
|
|
|
|
* problem, or other transient failure. Wait
|
|
|
|
|
* for a change, then try again. */
|
2011-07-26 16:49:03 -07:00
|
|
|
|
TXN_NOT_LOCKED, /* Server hasn't given us the lock yet. */
|
2009-12-07 17:08:04 -08:00
|
|
|
|
TXN_ERROR /* Commit failed due to a hard error. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status);
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_txn *ovsdb_idl_txn_create(struct ovsdb_idl *);
|
2010-03-08 14:18:44 -08:00
|
|
|
|
void ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *, const char *, ...)
|
2014-12-15 14:10:38 +01:00
|
|
|
|
OVS_PRINTF_FORMAT (2, 3);
|
2009-12-11 11:28:36 -08:00
|
|
|
|
void ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *);
|
2012-04-12 08:25:10 -07:00
|
|
|
|
void ovsdb_idl_txn_increment(struct ovsdb_idl_txn *,
|
|
|
|
|
const struct ovsdb_idl_row *,
|
2016-08-07 20:44:51 -07:00
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
bool force);
|
2009-12-07 17:08:04 -08:00
|
|
|
|
void ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *);
|
2009-12-09 13:29:02 -08:00
|
|
|
|
void ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *);
|
2009-12-07 17:08:04 -08:00
|
|
|
|
enum ovsdb_idl_txn_status ovsdb_idl_txn_commit(struct ovsdb_idl_txn *);
|
2010-03-03 12:55:39 -08:00
|
|
|
|
enum ovsdb_idl_txn_status ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *);
|
2009-12-07 17:08:04 -08:00
|
|
|
|
void ovsdb_idl_txn_abort(struct ovsdb_idl_txn *);
|
|
|
|
|
|
2010-02-05 14:11:12 -08:00
|
|
|
|
const char *ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *);
|
|
|
|
|
|
2010-01-28 13:23:30 -08:00
|
|
|
|
int64_t ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *);
|
|
|
|
|
const struct uuid *ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *,
|
|
|
|
|
const struct uuid *);
|
|
|
|
|
|
2010-01-25 10:15:17 -08:00
|
|
|
|
void ovsdb_idl_txn_write(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
struct ovsdb_datum *);
|
2013-03-05 15:30:33 -08:00
|
|
|
|
void ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
const struct ovsdb_datum *);
|
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
|
|
|
|
void ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
struct ovsdb_datum *);
|
|
|
|
|
void ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
struct ovsdb_datum *);
|
2016-08-06 17:46:29 -05:00
|
|
|
|
void ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
struct ovsdb_datum *);
|
|
|
|
|
void ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *,
|
|
|
|
|
const struct ovsdb_idl_column *,
|
|
|
|
|
struct ovsdb_datum *);
|
2010-01-27 13:04:56 -08:00
|
|
|
|
void ovsdb_idl_txn_delete(const struct ovsdb_idl_row *);
|
|
|
|
|
const struct ovsdb_idl_row *ovsdb_idl_txn_insert(
|
2010-06-02 11:08:03 -07:00
|
|
|
|
struct ovsdb_idl_txn *, const struct ovsdb_idl_table_class *,
|
|
|
|
|
const struct uuid *);
|
2010-01-25 10:15:17 -08:00
|
|
|
|
|
2010-03-03 14:27:53 -08:00
|
|
|
|
struct ovsdb_idl *ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *);
|
2015-08-04 14:49:11 -07:00
|
|
|
|
void ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *);
|
2015-08-04 09:52:26 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ovsdb_idl_loop provides an easy way to manage the transactions related
|
|
|
|
|
* to 'idl' and to cope with different status during transaction. */
|
|
|
|
|
struct ovsdb_idl_loop {
|
|
|
|
|
struct ovsdb_idl *idl;
|
|
|
|
|
unsigned int skip_seqno;
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_txn *committing_txn;
|
|
|
|
|
unsigned int precommit_seqno;
|
|
|
|
|
|
|
|
|
|
struct ovsdb_idl_txn *open_txn;
|
2016-07-24 13:14:59 -07:00
|
|
|
|
|
|
|
|
|
/* These members allow a client a simple, stateless way to keep track of
|
|
|
|
|
* transactions that commit: when a transaction commits successfully,
|
|
|
|
|
* ovsdb_idl_loop_commit_and_wait() copies 'next_cfg' to 'cur_cfg'. Thus,
|
|
|
|
|
* the client can set 'next_cfg' to a value that indicates a successful
|
|
|
|
|
* commit and check 'cur_cfg' on each iteration. */
|
|
|
|
|
int64_t cur_cfg;
|
|
|
|
|
int64_t next_cfg;
|
2015-08-04 09:52:26 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define OVSDB_IDL_LOOP_INITIALIZER(IDL) { .idl = (IDL) }
|
|
|
|
|
|
|
|
|
|
void ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *);
|
|
|
|
|
struct ovsdb_idl_txn *ovsdb_idl_loop_run(struct ovsdb_idl_loop *);
|
|
|
|
|
void ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *);
|
2016-08-13 21:52:27 -07:00
|
|
|
|
|
|
|
|
|
/* Conditional Replication
|
|
|
|
|
* =======================
|
|
|
|
|
*
|
|
|
|
|
* By default, when the IDL replicates a particular table in the database, it
|
|
|
|
|
* replicates every row in the table. These functions allow the client to
|
|
|
|
|
* specify that only selected rows should be replicated, by constructing a
|
|
|
|
|
* per-table condition that specifies the rows to replicate.
|
|
|
|
|
*/
|
2016-07-18 11:45:58 +03:00
|
|
|
|
|
|
|
|
|
void ovsdb_idl_condition_reset(struct ovsdb_idl *idl,
|
|
|
|
|
const struct ovsdb_idl_table_class *tc);
|
|
|
|
|
void ovsdb_idl_condition_add_clause(struct ovsdb_idl *idl,
|
|
|
|
|
const struct ovsdb_idl_table_class *tc,
|
|
|
|
|
enum ovsdb_function function,
|
|
|
|
|
const struct ovsdb_idl_column *column,
|
2016-08-13 21:52:27 -07:00
|
|
|
|
const struct ovsdb_datum *arg);
|
2016-07-18 11:45:58 +03:00
|
|
|
|
void ovsdb_idl_condition_remove_clause(struct ovsdb_idl *idl,
|
|
|
|
|
const struct ovsdb_idl_table_class *tc,
|
|
|
|
|
enum ovsdb_function function,
|
|
|
|
|
const struct ovsdb_idl_column *column,
|
2016-08-13 21:52:27 -07:00
|
|
|
|
const struct ovsdb_datum *arg);
|
2016-07-18 11:45:58 +03:00
|
|
|
|
|
2009-12-02 11:26:15 -08:00
|
|
|
|
#endif /* ovsdb-idl.h */
|