mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
Currently, command to add one item into a large set generates the transaction with the full new content of that set plus 'wait' operation for the full old content of that set. So, if we're adding one new load-balancer into a load-balancer group in OVN using ovn-nbctl, transaction will include all the existing load-balancers from that groups twice. IDL supports partial updates for sets and maps. The problem with that is changes are not visible to the IDL user until the transaction is committed. That will cause problems for chained ctl commands. However, we still can optimize the very last command in the list. It makes sense to do, since it's a common case for manual invocations. Updating the 'add' command as well as 'set' for a case where we're actually adding one new element to the map. One downside is that we can't check the set size without examining it and checking for duplicates, so allowing the transaction to be sent and constraints to be checked on the server side in that case. Not touching 'remove' operation for now, since removals may have different type, e.g. if elements from the map are removed by the key. The function will likely need to be fully re-written to accommodate all the corner cases. Acked-by: Dumitru Ceara <dceara@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
289 lines
11 KiB
C
289 lines
11 KiB
C
/*
|
||
* Copyright (c) 2015, 2017 Nicira, 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.
|
||
*/
|
||
|
||
#ifndef DB_CTL_BASE_H
|
||
#define DB_CTL_BASE_H 1
|
||
|
||
#include "compiler.h"
|
||
#include "openvswitch/dynamic-string.h"
|
||
#include "openvswitch/shash.h"
|
||
|
||
struct ctl_context;
|
||
struct option;
|
||
struct ovsdb_idl;
|
||
struct ovsdb_idl_row;
|
||
struct ovsdb_idl_txn;
|
||
struct ovsdb_symbol_table;
|
||
struct table;
|
||
|
||
/* This library module contains the common parts for ovsdb manipulation
|
||
* (structs, commands and functions). To utilize this module, user must
|
||
* define the following:
|
||
*
|
||
* - the command syntaxes for each command. (See 'struct ctl_command_syntax'
|
||
* for more info) and regiters them using ctl_register_commands().
|
||
*
|
||
* - the *ctl command context by inheriting the 'struct ctl_context' for
|
||
* additional commands implemented by user. (See 'struct ctl_context' for
|
||
* more info)
|
||
*/
|
||
|
||
/* ctl_fatal() also logs the error, so it is preferred in this file. */
|
||
#define ovs_fatal please_use_ctl_fatal_instead_of_ovs_fatal
|
||
|
||
struct ctl_table_class;
|
||
struct ovsdb_idl_class;
|
||
struct ovsdb_idl_table_class;
|
||
struct cmd_show_table;
|
||
|
||
/* ctl_init() figures out the number of tables on its own and flags an error if
|
||
* 'ctl_classes' was defined with the wrong number of elements. */
|
||
#define ctl_init(idl_class, table_classes, ctl_classes, cmd_show_table, \
|
||
ctl_exit_func) \
|
||
(BUILD_ASSERT(ARRAY_SIZE(table_classes) == ARRAY_SIZE(ctl_classes)), \
|
||
ctl_init__(idl_class, ctl_classes, cmd_show_table, ctl_exit_func))
|
||
void ctl_init__(const struct ovsdb_idl_class *, const struct ctl_table_class *,
|
||
const struct cmd_show_table *cmd_show_tables,
|
||
void (*ctl_exit_func)(int status));
|
||
char *ctl_default_db(void);
|
||
void ctl_error(struct ctl_context *, const char *, ...)
|
||
OVS_PRINTF_FORMAT(2, 3);
|
||
OVS_NO_RETURN void ctl_fatal(const char *, ...) OVS_PRINTF_FORMAT(1, 2);
|
||
|
||
/* *ctl command syntax structure, to be defined by each command implementation.
|
||
*
|
||
* Execution Path
|
||
* ==============
|
||
*
|
||
* Three stylized functions accompany each of these data structures:
|
||
*
|
||
* "pre-run" "run" "post-run"
|
||
* --------------- ------------ -----------------
|
||
* *ctl ->prerequisites ->run ->postprocess
|
||
*
|
||
* Any *ctl command implementation should go through the following execution
|
||
* path:
|
||
*
|
||
* 1. parses user command-line input and finds the corresponding syntax
|
||
* structures.
|
||
*
|
||
* 2. calls prerequisites() for getting the columns or tables used by each
|
||
* command.
|
||
*
|
||
* 3. calls run() to execute each command and to generate output.
|
||
*
|
||
* 4. calls postprocess() after output has been committed. (Only needed
|
||
* by 'create' command sofar)
|
||
*
|
||
* Execution Context
|
||
* =================
|
||
*
|
||
* Each of the stylized functions requires the 'struct ctl_context' as input
|
||
* to provide context e.g. command-line arguments, table to be modified. User
|
||
* may define more specific context (by inheriting 'struct ctl_context') and
|
||
* write stylized functions that use it. In that case, CONTAINER_OF() can
|
||
* be used to cast the generic context to the specific one.
|
||
*
|
||
* */
|
||
struct ctl_command_syntax {
|
||
const char *name; /* e.g. "add-br" */
|
||
int min_args; /* Min number of arguments following name. */
|
||
int max_args; /* Max number of arguments following name. */
|
||
|
||
/* Names that roughly describe the arguments that the command
|
||
* uses. These should be similar to the names displayed in the
|
||
* man page or in the help output. */
|
||
const char *arguments;
|
||
|
||
/* If nonnull, calls ovsdb_idl_add_column() or ovsdb_idl_add_table() for
|
||
* each column or table in ctx->idl that it uses. */
|
||
void (*prerequisites)(struct ctl_context *ctx);
|
||
|
||
/* Does the actual work of the command and puts the command's output, if
|
||
* any, in ctx->output or ctx->table.
|
||
*
|
||
* Alternatively, if some prerequisite of the command is not met and the
|
||
* caller should wait for something to change and then retry, it may set
|
||
* ctx->try_again to true. (Only the "wait-until" command currently does
|
||
* this.) */
|
||
void (*run)(struct ctl_context *ctx);
|
||
|
||
/* If nonnull, called after the transaction has been successfully
|
||
* committed. ctx->output is the output from the "run" function, which
|
||
* this function may modify and otherwise postprocess as needed. (Only the
|
||
* "create" command currently does any postprocessing.) */
|
||
void (*postprocess)(struct ctl_context *ctx);
|
||
|
||
/* A comma-separated list of supported options, e.g. "--a,--b", or the
|
||
* empty string if the command does not support any options.
|
||
*
|
||
* Arguments are determined by appending special characters to option
|
||
* names:
|
||
*
|
||
* - Append "=" (e.g. "--id=") for a required argument.
|
||
*
|
||
* - Append "?" (e.g. "--ovs?") for an optional argument.
|
||
*
|
||
* - Otherwise an option does not accept an argument. */
|
||
const char *options;
|
||
|
||
enum { RO, RW } mode; /* Does this command modify the database? */
|
||
};
|
||
|
||
/* A command extracted from command-line input plus the structs for
|
||
* output generation. */
|
||
struct ctl_command {
|
||
/* Data that remains constant after initialization. */
|
||
const struct ctl_command_syntax *syntax;
|
||
int argc;
|
||
char **argv;
|
||
struct shash options;
|
||
|
||
/* Data modified by commands. */
|
||
struct ds output;
|
||
struct table *table;
|
||
};
|
||
|
||
bool ctl_might_write_to_db(const struct ctl_command *, size_t n);
|
||
const char *ctl_get_db_cmd_usage(void);
|
||
|
||
const char *ctl_list_db_tables_usage(void);
|
||
void ctl_print_commands(void);
|
||
void ctl_print_options(const struct option *);
|
||
void ctl_add_cmd_options(struct option **, size_t *n_options_p,
|
||
size_t *allocated_options_p, int opt_val);
|
||
void ctl_register_commands(const struct ctl_command_syntax *);
|
||
char * OVS_WARN_UNUSED_RESULT ctl_parse_commands(
|
||
int argc, char *argv[], struct shash *local_options,
|
||
struct ctl_command **commandsp, size_t *n_commandsp);
|
||
|
||
/* Sometimes, it is desirable to print the table with weak reference to
|
||
* rows in a 'cmd_show_table' table. In that case, the 'weak_ref_table'
|
||
* should be used and user must define all variables. */
|
||
struct weak_ref_table {
|
||
const struct ovsdb_idl_table_class *table;
|
||
const struct ovsdb_idl_column *name_column;
|
||
/* This colum must be a weak reference to the owning
|
||
* 'struct cmd_show_table''s table row. */
|
||
const struct ovsdb_idl_column *wref_column;
|
||
};
|
||
|
||
/* This struct is for organizing the 'show' command output where:
|
||
*
|
||
* - 'table' is the table to show.
|
||
*
|
||
* - if 'name_column' is not null, it is used as the name for each row
|
||
* in 'table'.
|
||
*
|
||
* - 'columns[]' allows user to specify the print of additional columns
|
||
* in 'table'.
|
||
*
|
||
* - if 'wref_table' is populated, print 'wref_table.name_column' for
|
||
* each row in table 'wref_table.table' that has a reference to 'table'
|
||
* in 'wref_table.wref_column'. Every field must be populated.
|
||
*
|
||
* */
|
||
struct cmd_show_table {
|
||
const struct ovsdb_idl_table_class *table;
|
||
const struct ovsdb_idl_column *name_column;
|
||
const struct ovsdb_idl_column *columns[4]; /* Seems like a good number. */
|
||
const struct weak_ref_table wref_table;
|
||
};
|
||
|
||
|
||
/* The base context struct for conducting the common database
|
||
* operations (commands listed in 'db_ctl_commands'). User should
|
||
* define the per-schema context by inheriting this struct as base.
|
||
*
|
||
* Database Caches
|
||
* ===============
|
||
*
|
||
* User may implement caches for contents of the database to facilitate
|
||
* specific commands. In that case, the common commands defined in
|
||
* 'db_ctl_commands' that may invalidate the cache must call the
|
||
* invalidate_cache().
|
||
*
|
||
**/
|
||
struct ctl_context {
|
||
/* Read-only. */
|
||
int argc;
|
||
char **argv;
|
||
struct shash options;
|
||
|
||
/* Modifiable state. */
|
||
char *error;
|
||
struct ds output;
|
||
struct table *table;
|
||
struct ovsdb_idl *idl;
|
||
struct ovsdb_idl_txn *txn;
|
||
struct ovsdb_symbol_table *symtab;
|
||
|
||
/* For implementation with a cache of the contents of the database,
|
||
* this function will be called when the database is changed and the
|
||
* change makes the cache no longer valid. */
|
||
void (*invalidate_cache_cb)(struct ctl_context *);
|
||
|
||
/* A command may set this member to true if some prerequisite is not met
|
||
* and the caller should wait for something to change and then retry. */
|
||
bool try_again;
|
||
|
||
/* If set during the context initialization, command implementation
|
||
* may use optimizations that will leave database changes invisible
|
||
* to IDL, e.g. use partial set updates. */
|
||
bool last_command;
|
||
};
|
||
|
||
void ctl_context_init_command(struct ctl_context *, struct ctl_command *,
|
||
bool last);
|
||
void ctl_context_init(struct ctl_context *, struct ctl_command *,
|
||
struct ovsdb_idl *, struct ovsdb_idl_txn *,
|
||
struct ovsdb_symbol_table *,
|
||
void (*invalidate_cache)(struct ctl_context *));
|
||
void ctl_context_done_command(struct ctl_context *, struct ctl_command *);
|
||
void ctl_context_done(struct ctl_context *, struct ctl_command *);
|
||
|
||
/* A way to identify a particular row in the database based on a user-provided
|
||
* string. If all fields are NULL, the struct is ignored. Otherwise,
|
||
* 'name_column' designates a column whose table is searched for rows that
|
||
* match with the user string. If 'key' is NULL, then 'name_column' should be
|
||
* a string or integer-valued column; otherwise it should be a map from a
|
||
* string to one of those types and the value corresponding to 'key' is what is
|
||
* matched. If a matching row is found, then:
|
||
*
|
||
* - If 'uuid_column' is NULL, the matching row is the final row.
|
||
*
|
||
* - Otherwise 'uuid_column' must designate a UUID-typed column whose value
|
||
* refers to exactly one row, which is the final row.
|
||
*/
|
||
struct ctl_row_id {
|
||
const struct ovsdb_idl_column *name_column;
|
||
const char *key;
|
||
const struct ovsdb_idl_column *uuid_column;
|
||
};
|
||
|
||
struct ctl_table_class {
|
||
struct ctl_row_id row_ids[4];
|
||
};
|
||
|
||
char *ctl_get_row(struct ctl_context *, const struct ovsdb_idl_table_class *,
|
||
const char *record_id, bool must_exist,
|
||
const struct ovsdb_idl_row **);
|
||
|
||
char *ctl_set_column(const char *table_name, const struct ovsdb_idl_row *,
|
||
const char *arg, struct ovsdb_symbol_table *);
|
||
|
||
#endif /* db-ctl-base.h */
|