2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00
ovs/ovsdb/transaction-forward.c
Adrian Moreno 9e56549c2b hmap: use short version of safe loops if possible.
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>
2022-03-30 16:59:02 +02:00

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);
}
}