2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 18:07:40 +00:00
ovs/lib/ovsdb-cs.h

210 lines
8.2 KiB
C
Raw Normal View History

/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
* Copyright (C) 2016 Hewlett Packard Enterprise Development LP
*
* 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_CS_H
#define OVSDB_CS_H 1
/* Open vSwitch Database client synchronization layer.
*
* This is a base layer for maintaining an in-memory replica of a database. It
* issues RPC requests to an OVSDB database server and passes the semantically
* meaningful parts of the stream up to a higher layer. The OVSDB IDL uses
* this as a base layer, as well as OVN's DDlog-based northd implementation.
*/
#include <stdbool.h>
#include "openvswitch/hmap.h"
#include "openvswitch/list.h"
#include "openvswitch/shash.h"
#include "openvswitch/uuid.h"
struct json;
struct ovsdb_cs;
struct ovsdb_cs_ops {
/* Returns <monitor-requests> to use for the specified <schema>. The
* implementation might find ovsdb_cs_parse_table_updates() to be a useful
* helper.
*
* The caller might actually use "monitor_cond" or "monitor_cond_since",
* rather than plain "monitor". If so, this function's implementation
* doesn't need to worry about that, because the caller will add the
* conditions itself. */
struct json *(*compose_monitor_requests)(const struct json *schema,
void *aux);
};
/* An event is a happening that is worth reporting to the CS client.
*
* Currently there are three kinds of events:
*
* - "Reconnect": The connection to the database was lost and it is now
* being reconnected. This means that any transactions submitted by the
* client will never receive a reply (although it's possible that some of
* them were actually committed). This event has no associated data.
*
* - "Locked": The server granted the lock we requested.
*
* - "Update": The server sent an update to one or more monitored tables.
* The client can use the associated data to update its idea of the
* snapshot.
*
* - "Transaction reply": The server sent a reply to a transaction sent by
* the client using ovsdb_cs_send_transaction().
*/
struct ovsdb_cs_event {
struct ovs_list list_node;
enum ovsdb_cs_event_type {
OVSDB_CS_EVENT_TYPE_RECONNECT, /* Connection lost. */
OVSDB_CS_EVENT_TYPE_LOCKED, /* Got the lock we wanted. */
OVSDB_CS_EVENT_TYPE_UPDATE, /* Received update notification. */
OVSDB_CS_EVENT_TYPE_TXN_REPLY, /* Received reply to transaction. */
} type;
union {
/* Represents a <table-updates> or <table-updates2> that contains
* either the initial data in a monitor reply or a delta received in an
* update notification. The client can use this to update its database
* replica.
*
* If 'clear' is true, then the client should first clear its idea of
* what's in the replica before applying the update; otherwise, it's an
* incremental update.
*
* If 'monitor_reply' is true, then this comes from a monitor reply.
* This doesn't have real semantic meaning, but it allows the caller
* to imitate the exact behavior of previous versions of code that
* behaved differently on updates from monitor replies vs. updates.
*
* 'table-updates' is a <table-updates> if 'version' if 1, otherwise a
* <table-updates2>. The client can use ovsdb_cs_parse_table_updates()
* to parse the update.
*/
struct ovsdb_cs_update_event {
bool clear;
bool monitor_reply;
struct json *table_updates;
int version;
ovsdb: relay: Add transaction history support. Even though relays can be scaled to the big number of servers to handle a lot more clients, lack of transaction history may cause significant load if clients are re-connecting. E.g. in case of the upgrade of a large-scale OVN deployment, relays can be taken down one by one forcing all the clients of one relay to jump to other ones. And all these clients will download the database from scratch from a new relay. Since relay itself supports monitor_cond_since connection to the main cluster, it receives the last transaction id along with each update. Since these transaction ids are 'eid's of actual transactions, they can be used by relay for a transaction history. Relay may not receive all the transaction ids, because the main cluster may combine several changes into a single monitor update. However, all relays will, likely, receive same updates with the same transaction ids, so the case where transaction id can not be found after re-connection between relays should not be very common. If some id is missing on the relay (i.e. this update was merged with some other update and newer id was used) the client will just re-download the database as if there was a normal transaction history miss. OVSDB client synchronization module updated to provide the last transaction id along with the update. Relay module updated to use these ids as a transaction id. If ids are zero, relay decides that the main server doesn't support transaction ids and disables the transaction history accordingly. Using ovsdb_txn_replay_commit() instead of ovsdb_txn_propose_commit_block(), so transactions are added to the history. This can be done, because relays has no file storage, so there is no need to write anything. Relay tests modified to test both standalone and clustered database as a main server. Checks added to ensure that all servers receive the same transaction ids in monitor updates. Acked-by: Mike Pattrick <mkp@redhat.com> Acked-by: Han Zhou <hzhou@ovn.org> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
2021-12-19 15:09:39 +01:00
struct uuid last_id;
} update;
/* The "result" member from a transaction reply. The transaction is
* one sent by the client using ovsdb_cs_send_transaction(). The
* client can match 'txn_reply->id' against the ID in a transaction it
* sent. */
struct jsonrpc_msg *txn_reply;
};
};
void ovsdb_cs_event_destroy(struct ovsdb_cs_event *);
/* Lifecycle. */
struct ovsdb_cs *ovsdb_cs_create(const char *database, int max_version,
const struct ovsdb_cs_ops *ops,
void *ops_aux);
void ovsdb_cs_destroy(struct ovsdb_cs *);
void ovsdb_cs_run(struct ovsdb_cs *, struct ovs_list *events);
void ovsdb_cs_wait(struct ovsdb_cs *);
/* Network connection. */
void ovsdb_cs_set_remote(struct ovsdb_cs *, const char *remote, bool retry);
void ovsdb_cs_enable_reconnect(struct ovsdb_cs *);
void ovsdb_cs_force_reconnect(struct ovsdb_cs *);
void ovsdb_cs_flag_inconsistency(struct ovsdb_cs *);
bool ovsdb_cs_is_alive(const struct ovsdb_cs *);
bool ovsdb_cs_is_connected(const struct ovsdb_cs *);
int ovsdb_cs_get_last_error(const struct ovsdb_cs *);
void ovsdb_cs_set_probe_interval(const struct ovsdb_cs *, int probe_interval);
/* Conditional monitoring (specifying that only rows matching particular
* criteria should be monitored).
*
* Some database servers don't support conditional monitoring; in that case,
* the client will get all the rows. */
unsigned int ovsdb_cs_set_condition(struct ovsdb_cs *, const char *table,
const struct json *condition);
unsigned int ovsdb_cs_get_condition_seqno(const struct ovsdb_cs *);
ovsdb-idl: Provide API to disable set_db_change_aware request. For ovsdb clients that are short-lived, e.g. when using ovn-nbctl/ovn-sbctl to read some metrics from the OVN NB/SB server, they don't really need to be aware of db changes, because they exit immediately after getting the initial response for the requested data. In such use cases, however, the clients still send 'set_db_change_aware' request, which results in server side error logs when the server tries to send out the response for the 'set_db_change_aware' request, because at the moment the client that is supposed to receive the request has already closed the connection and exited. E.g.: 2023-01-10T18:23:29.431Z|00007|jsonrpc|WARN|unix#3: receive error: Connection reset by peer 2023-01-10T18:23:29.431Z|00008|reconnect|WARN|unix#3: connection dropped (Connection reset by peer) To avoid such problems, this patch provides an API to allow a client to choose to not send the 'set_db_change_aware' request. There was an earlier attempt to fix this [0], but it was not accepted back then as discussed in the email [1]. It was also discussed in the emails that an alternative approach is to use notification instead of request, but that would require protocol changes and taking backward compatibility into consideration. So this patch takes a different approach and tries to keep the change small. [0] http://patchwork.ozlabs.org/project/openvswitch/patch/1594380801-32134-1-git-send-email-dceara@redhat.com/ [1] https://mail.openvswitch.org/pipermail/ovs-discuss/2021-February/050919.html Reported-by: Girish Moodalbail <gmoodalbail@nvidia.com> Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-July/050343.html Reported-by: Tobias Hofmann <tohofman@cisco.com> Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2021-February/050914.html Acked-by: Dumitru Ceara <dceara@redhat.com> Signed-off-by: Han Zhou <hzhou@ovn.org> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
2023-01-12 09:08:53 -08:00
/* Database change awareness. */
void ovsdb_cs_set_db_change_aware(struct ovsdb_cs *, bool set_db_change_aware);
/* Clustered servers. */
void ovsdb_cs_set_leader_only(struct ovsdb_cs *, bool leader_only);
void ovsdb_cs_set_shuffle_remotes(struct ovsdb_cs *, bool shuffle);
void ovsdb_cs_reset_min_index(struct ovsdb_cs *);
/* Database locks. */
void ovsdb_cs_set_lock(struct ovsdb_cs *, const char *lock_name);
const char *ovsdb_cs_get_lock(const struct ovsdb_cs *);
bool ovsdb_cs_has_lock(const struct ovsdb_cs *);
bool ovsdb_cs_is_lock_contended(const struct ovsdb_cs *);
/* Transactions. */
bool ovsdb_cs_may_send_transaction(const struct ovsdb_cs *);
struct json *ovsdb_cs_send_transaction(struct ovsdb_cs *, struct json *ops)
OVS_WARN_UNUSED_RESULT;
bool ovsdb_cs_forget_transaction(struct ovsdb_cs *, const struct json *);
/* Helper for partially parsing the <table-updates> or <table-updates2> that
* appear in struct ovsdb_cs_update_event. The helper leaves the data in JSON
* format, so it doesn't need to know column types. */
/* The kind of change to a row. */
enum ovsdb_cs_row_update_type {
OVSDB_CS_ROW_DELETE, /* Row deletion. */
OVSDB_CS_ROW_INSERT, /* Row insertion. */
OVSDB_CS_ROW_UPDATE, /* Replacement of data within a row. */
OVSDB_CS_ROW_XOR /* <table-updates2> diff application. */
};
/* Partially parsed <row-update> or <row-update2>. */
struct ovsdb_cs_row_update {
struct uuid row_uuid; /* Row's _uuid. */
enum ovsdb_cs_row_update_type type; /* Type of change. */
const struct shash *columns; /* Map from column name to json data. */
};
/* Partially parsed <table-update> or <table-update2>. */
struct ovsdb_cs_table_update {
const char *table_name;
struct ovsdb_cs_row_update *row_updates;
size_t n;
};
struct ovsdb_cs_db_update {
struct ovsdb_cs_table_update *table_updates;
size_t n;
};
struct ovsdb_error *ovsdb_cs_parse_db_update(
const struct json *table_updates, int version,
struct ovsdb_cs_db_update **db_updatep)
OVS_WARN_UNUSED_RESULT;
void ovsdb_cs_db_update_destroy(struct ovsdb_cs_db_update *);
const struct ovsdb_cs_table_update *ovsdb_cs_db_update_find_table(
const struct ovsdb_cs_db_update *, const char *table_name);
/* Simple parsing of OVSDB schemas for use by ovsdb_cs clients. */
struct shash *ovsdb_cs_parse_schema(const struct json *schema_json);
void ovsdb_cs_free_schema(struct shash *schema);
#endif /* ovsdb-cs.h */