mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
Using SHORT version of the *_SAFE loops makes the code cleaner and less error prone. So, use the SHORT version and remove the extra variable when possible for hmap and all its derived types. In order to be able to use both long and short versions without changing the name of the macro for all the clients, overload the existing name and select the appropriate version depending on the number of arguments. Acked-by: Dumitru Ceara <dceara@redhat.com> Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Adrian Moreno <amorenoz@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
184 lines
5.2 KiB
C
184 lines
5.2 KiB
C
/*
|
|
* Copyright (c) 2021, Red Hat, Inc.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "transaction-forward.h"
|
|
|
|
#include "coverage.h"
|
|
#include "jsonrpc.h"
|
|
#include "openvswitch/hmap.h"
|
|
#include "openvswitch/json.h"
|
|
#include "openvswitch/list.h"
|
|
#include "openvswitch/poll-loop.h"
|
|
#include "openvswitch/vlog.h"
|
|
#include "ovsdb.h"
|
|
#include "ovsdb-cs.h"
|
|
#include "util.h"
|
|
|
|
VLOG_DEFINE_THIS_MODULE(transaction_forward);
|
|
|
|
COVERAGE_DEFINE(txn_forward_cancel);
|
|
COVERAGE_DEFINE(txn_forward_complete);
|
|
COVERAGE_DEFINE(txn_forward_create);
|
|
COVERAGE_DEFINE(txn_forward_sent);
|
|
|
|
struct ovsdb_txn_forward {
|
|
struct ovs_list new_node; /* In 'txn_forward_new' of struct ovsdb. */
|
|
struct hmap_node sent_node; /* In 'txn_forward_sent' of struct ovsdb. */
|
|
struct json *id; /* 'id' of the forwarded transaction. */
|
|
struct jsonrpc_msg *request; /* Original request. */
|
|
struct jsonrpc_msg *reply; /* Reply from the server. */
|
|
};
|
|
|
|
struct ovsdb_txn_forward *
|
|
ovsdb_txn_forward_create(struct ovsdb *db, const struct jsonrpc_msg *request)
|
|
{
|
|
struct ovsdb_txn_forward *txn_fwd = xzalloc(sizeof *txn_fwd);
|
|
|
|
COVERAGE_INC(txn_forward_create);
|
|
txn_fwd->request = jsonrpc_msg_clone(request);
|
|
ovs_list_push_back(&db->txn_forward_new, &txn_fwd->new_node);
|
|
hmap_node_nullify(&txn_fwd->sent_node);
|
|
|
|
return txn_fwd;
|
|
}
|
|
|
|
static void
|
|
ovsdb_txn_forward_unlist(struct ovsdb *db, struct ovsdb_txn_forward *txn_fwd)
|
|
{
|
|
if (!ovs_list_is_empty(&txn_fwd->new_node)) {
|
|
ovs_list_remove(&txn_fwd->new_node);
|
|
ovs_list_init(&txn_fwd->new_node);
|
|
}
|
|
if (!hmap_node_is_null(&txn_fwd->sent_node)) {
|
|
hmap_remove(&db->txn_forward_sent, &txn_fwd->sent_node);
|
|
hmap_node_nullify(&txn_fwd->sent_node);
|
|
}
|
|
}
|
|
|
|
void
|
|
ovsdb_txn_forward_destroy(struct ovsdb *db, struct ovsdb_txn_forward *txn_fwd)
|
|
{
|
|
if (!txn_fwd) {
|
|
return;
|
|
}
|
|
|
|
ovsdb_txn_forward_unlist(db, txn_fwd);
|
|
json_destroy(txn_fwd->id);
|
|
jsonrpc_msg_destroy(txn_fwd->request);
|
|
jsonrpc_msg_destroy(txn_fwd->reply);
|
|
free(txn_fwd);
|
|
}
|
|
|
|
bool
|
|
ovsdb_txn_forward_is_complete(const struct ovsdb_txn_forward *txn_fwd)
|
|
{
|
|
return txn_fwd->reply != NULL;
|
|
}
|
|
|
|
void
|
|
ovsdb_txn_forward_complete(struct ovsdb *db, const struct jsonrpc_msg *reply)
|
|
{
|
|
struct ovsdb_txn_forward *t;
|
|
size_t hash = json_hash(reply->id, 0);
|
|
|
|
HMAP_FOR_EACH_WITH_HASH (t, sent_node, hash, &db->txn_forward_sent) {
|
|
if (json_equal(reply->id, t->id)) {
|
|
COVERAGE_INC(txn_forward_complete);
|
|
t->reply = jsonrpc_msg_clone(reply);
|
|
|
|
/* Replacing id with the id of the original request. */
|
|
json_destroy(t->reply->id);
|
|
t->reply->id = json_clone(t->request->id);
|
|
|
|
hmap_remove(&db->txn_forward_sent, &t->sent_node);
|
|
hmap_node_nullify(&t->sent_node);
|
|
|
|
db->run_triggers_now = db->run_triggers = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct jsonrpc_msg *
|
|
ovsdb_txn_forward_steal_reply(struct ovsdb_txn_forward *txn_fwd)
|
|
{
|
|
struct jsonrpc_msg *reply = txn_fwd->reply;
|
|
|
|
txn_fwd->reply = NULL;
|
|
return reply;
|
|
}
|
|
|
|
void
|
|
ovsdb_txn_forward_run(struct ovsdb *db, struct ovsdb_cs *cs)
|
|
{
|
|
struct ovsdb_txn_forward *t;
|
|
|
|
/* Send all transactions that needs to be forwarded. */
|
|
LIST_FOR_EACH_SAFE (t, new_node, &db->txn_forward_new) {
|
|
if (!ovsdb_cs_may_send_transaction(cs)) {
|
|
break;
|
|
}
|
|
ovs_assert(!strcmp(t->request->method, "transact"));
|
|
t->id = ovsdb_cs_send_transaction(cs, json_clone(t->request->params));
|
|
if (t->id) {
|
|
COVERAGE_INC(txn_forward_sent);
|
|
ovs_list_remove(&t->new_node);
|
|
ovs_list_init(&t->new_node);
|
|
hmap_insert(&db->txn_forward_sent, &t->sent_node,
|
|
json_hash(t->id, 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ovsdb_txn_forward_wait(struct ovsdb *db, struct ovsdb_cs *cs)
|
|
{
|
|
if (ovsdb_cs_may_send_transaction(cs)
|
|
&& !ovs_list_is_empty(&db->txn_forward_new)) {
|
|
poll_immediate_wake();
|
|
}
|
|
}
|
|
|
|
void
|
|
ovsdb_txn_forward_cancel(struct ovsdb *db, struct ovsdb_txn_forward *txn_fwd)
|
|
{
|
|
COVERAGE_INC(txn_forward_cancel);
|
|
jsonrpc_msg_destroy(txn_fwd->reply);
|
|
txn_fwd->reply = jsonrpc_create_error(json_string_create("canceled"),
|
|
txn_fwd->request->id);
|
|
ovsdb_txn_forward_unlist(db, txn_fwd);
|
|
}
|
|
|
|
void
|
|
ovsdb_txn_forward_cancel_all(struct ovsdb *db, bool sent_only)
|
|
{
|
|
struct ovsdb_txn_forward *t;
|
|
|
|
HMAP_FOR_EACH_SAFE (t, sent_node, &db->txn_forward_sent) {
|
|
ovsdb_txn_forward_cancel(db, t);
|
|
}
|
|
|
|
if (sent_only) {
|
|
return;
|
|
}
|
|
|
|
LIST_FOR_EACH_SAFE (t, new_node, &db->txn_forward_new) {
|
|
ovsdb_txn_forward_cancel(db, t);
|
|
}
|
|
}
|