mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
Every transaction has RAFT log prerequisites. Even if transactions are not related (because RAFT doesn't actually know what data it is handling). When leader writes a new record to a RAFT storage, it is getting appended to the log right away and changes current 'eid', i.e., changes prerequisites. The leader will not try to write new records until the current one is committed, because until then the pre-check will be failing. However, that is different for the follower. Followers do not add records to the RAFT log until the leader sends an append request back. So, if there are multiple transactions pending on a follower, it will create a command for each of them and prerequisites will be set to the same values. All these commands will be sent to the leader, but only one can succeed at a time, because accepting one command immediately changes prerequisites and all other commands become non-applicable. So, out of N commands, 1 will succeed and N - 1 will fail. The cluster failure is a transient failure, so the follower will re-process all the failed transactions and send them again. 1 will succeed and N - 2 will fail. And so on, until there are no more transactions. In the end, instead of processing N transactions, the follower is performing N * (N - 1) / 2 transaction processing iterations. That is consuming a huge amount of CPU resources completely unnecessarily. Since there is no real chance for multiple transactions from the same follower to succeed, it's better to not send them in the first place. This also eliminates prerequisite mismatch messages on a leader in this particular case. In a test with 30 parallel shell threads executing 12K transactions total with separate ovsdb-client calls through the same follower there is about 60% performance improvement. The test takes ~100 seconds to complete without this change and ~40 seconds with this change applied. The new time is very close to what it takes to execute the same test through the cluster leader. The test can be found at the link below. Note: prerequisite failures on a leader are still possible, but mostly in a case of simultaneous transactions from different followers. It's a normal thing for a distributed database due to its nature. Link: https://mail.openvswitch.org/pipermail/ovs-dev/2024-June/415167.html Acked-by: Dumitru Ceara <dceara@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
105 lines
4.5 KiB
C
105 lines
4.5 KiB
C
/* Copyright (c) 2009, 2010, 2011, 2016, 2017 Nicira, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this storage 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_STORAGE_H
|
|
#define OVSDB_STORAGE_H 1
|
|
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
#include "compiler.h"
|
|
|
|
struct json;
|
|
struct ovsdb_schema;
|
|
struct ovsdb_storage;
|
|
struct simap;
|
|
struct uuid;
|
|
|
|
struct ovsdb_error *ovsdb_storage_open(const char *filename, bool rw,
|
|
struct ovsdb_storage **)
|
|
OVS_WARN_UNUSED_RESULT;
|
|
struct ovsdb_storage *ovsdb_storage_create_unbacked(const char *name);
|
|
void ovsdb_storage_close(struct ovsdb_storage *);
|
|
|
|
const char *ovsdb_storage_get_model(const struct ovsdb_storage *);
|
|
bool ovsdb_storage_is_clustered(const struct ovsdb_storage *);
|
|
bool ovsdb_storage_is_connected(const struct ovsdb_storage *);
|
|
bool ovsdb_storage_is_dead(const struct ovsdb_storage *);
|
|
bool ovsdb_storage_is_leader(const struct ovsdb_storage *);
|
|
const struct uuid *ovsdb_storage_get_cid(const struct ovsdb_storage *);
|
|
const struct uuid *ovsdb_storage_get_sid(const struct ovsdb_storage *);
|
|
uint64_t ovsdb_storage_get_applied_index(const struct ovsdb_storage *);
|
|
void ovsdb_storage_get_memory_usage(const struct ovsdb_storage *,
|
|
struct simap *usage);
|
|
char *ovsdb_storage_get_error(const struct ovsdb_storage *);
|
|
|
|
void ovsdb_storage_run(struct ovsdb_storage *);
|
|
void ovsdb_storage_wait(struct ovsdb_storage *);
|
|
|
|
const char *ovsdb_storage_get_name(const struct ovsdb_storage *);
|
|
|
|
struct ovsdb_error *ovsdb_storage_read(struct ovsdb_storage *,
|
|
struct ovsdb_schema **schemap,
|
|
struct json **txnp,
|
|
struct uuid *txnid)
|
|
OVS_WARN_UNUSED_RESULT;
|
|
bool ovsdb_storage_read_wait(struct ovsdb_storage *);
|
|
|
|
void ovsdb_storage_unread(struct ovsdb_storage *);
|
|
|
|
struct ovsdb_write *ovsdb_storage_write(struct ovsdb_storage *,
|
|
const struct json *,
|
|
const struct uuid *prereq,
|
|
struct uuid *result,
|
|
bool durable)
|
|
OVS_WARN_UNUSED_RESULT;
|
|
struct ovsdb_error *ovsdb_storage_write_block(struct ovsdb_storage *,
|
|
const struct json *,
|
|
const struct uuid *prereq,
|
|
struct uuid *result,
|
|
bool durable);
|
|
|
|
bool ovsdb_write_is_complete(const struct ovsdb_write *);
|
|
const struct ovsdb_error *ovsdb_write_get_error(const struct ovsdb_write *);
|
|
uint64_t ovsdb_write_get_commit_index(const struct ovsdb_write *);
|
|
void ovsdb_write_wait(const struct ovsdb_write *);
|
|
void ovsdb_write_destroy(struct ovsdb_write *);
|
|
|
|
bool ovsdb_storage_should_snapshot(struct ovsdb_storage *);
|
|
struct ovsdb_error *ovsdb_storage_store_snapshot(struct ovsdb_storage *storage,
|
|
const struct json *schema,
|
|
const struct json *snapshot,
|
|
uint64_t applied_index)
|
|
OVS_WARN_UNUSED_RESULT;
|
|
|
|
struct ovsdb_write *ovsdb_storage_write_schema_change(
|
|
struct ovsdb_storage *,
|
|
const struct ovsdb_schema *, const struct json *data,
|
|
const struct uuid *prereq, struct uuid *result)
|
|
OVS_WARN_UNUSED_RESULT;
|
|
|
|
/* Convenience functions for ovsdb-tool and other command-line utilities,
|
|
* for use with standalone database files only, which terminate the process
|
|
* on error. */
|
|
struct ovsdb_storage *ovsdb_storage_open_standalone(const char *filename,
|
|
bool rw);
|
|
struct ovsdb_schema *ovsdb_storage_read_schema(struct ovsdb_storage *);
|
|
|
|
/* Checks that there is a chance for a record with specified prerequisites
|
|
* to be successfully written to the storage. */
|
|
bool ovsdb_storage_precheck_prereq(const struct ovsdb_storage *,
|
|
const struct uuid *prereq);
|
|
|
|
#endif /* ovsdb/storage.h */
|