summaryrefslogtreecommitdiff
path: root/lib/ovsdb-cs.h
blob: 4cf9ca2b99c10c16def086ecc96878faa16087b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/* 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;
            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 *);

/* 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 */