[ovs-dev] [PATCH 2/7] ovsdb: Add extra internal tables to databases for replication purposes.

Ilya Maximets i.maximets at ovn.org
Sat May 1 00:55:43 UTC 2021


New flag for ovsdb table schema 'copyForReplication'.  It's needed to
enable replication of a _Server database in later commits.

With this option ovsdb-server will create a new _synced_<table-name>
table where it will store data received from the replication source
while keeping the original table for data of the local server.
This way ovsdb-server will be able to keep state of local databases
while replicating state of databases from the active server.

Signed-off-by: Ilya Maximets <i.maximets at ovn.org>
---
 Documentation/ref/ovsdb-server.7.rst |  7 +++++++
 ovsdb/ovsdb-doc                      |  3 ++-
 ovsdb/ovsdb.c                        | 19 ++++++++++++++++++-
 ovsdb/table.c                        | 20 ++++++++++++++++----
 ovsdb/table.h                        |  4 +++-
 python/ovs/db/schema.py              | 20 +++++++++++++++++---
 6 files changed, 63 insertions(+), 10 deletions(-)

diff --git a/Documentation/ref/ovsdb-server.7.rst b/Documentation/ref/ovsdb-server.7.rst
index 04414350a..717f62d81 100644
--- a/Documentation/ref/ovsdb-server.7.rst
+++ b/Documentation/ref/ovsdb-server.7.rst
@@ -104,6 +104,13 @@ configuration and the following columns:
     The set of columns and column:key pairs for which authorized update and
     mutate operations should be permitted.
 
+Since version 2.16, database table could be copied for replication purposes
+by setting ``copyForReplication`` flag to ``true``.  For each table marked
+with this flag, ``ovsdb-server`` will create one more table with the same
+name and ``_synced_`` prefix (e.g., ``_synced_<table-name>``).  Server in a
+backup role will keep its own content in the original table and will put
+data, received from the active server, to this special table.
+
 4 Wire Protocol
 ---------------
 
diff --git a/ovsdb/ovsdb-doc b/ovsdb/ovsdb-doc
index 10d0c0c13..5513783c1 100755
--- a/ovsdb/ovsdb-doc
+++ b/ovsdb/ovsdb-doc
@@ -213,7 +213,8 @@ def docsToNroff(schemaFile, xmlFile, erFile, version=None):
             introNodes += [dbNode]
 
     documented_tables = set((name for (name, title) in summary))
-    schema_tables = set(schema.tables.keys())
+    schema_tables = set([name for name in schema.tables.keys()
+                         if not name.startswith("_")])
     undocumented_tables = schema_tables - documented_tables
     for table in undocumented_tables:
         raise error.Error("undocumented table %s" % table)
diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c
index 9042658fa..f662a0238 100644
--- a/ovsdb/ovsdb.c
+++ b/ovsdb/ovsdb.c
@@ -238,6 +238,21 @@ ovsdb_schema_from_json(const struct json *json, struct ovsdb_schema **schemap)
         }
 
         shash_add(&schema->tables, table->name, table);
+
+        if (table->copy_for_replication) {
+            /* Need to create a copy of the table for the case it will be
+             * synced from another server. */
+            struct ovsdb_table_schema *synced_table;
+
+            synced_table = ovsdb_table_schema_clone(table);
+            free(synced_table->name);
+            synced_table->name = xasprintf("_synced_%s", node->name);
+            /* Clearing 'copy' flag to avoid accidental further copying. */
+            synced_table->copy_for_replication = false;
+
+            shash_add(&schema->tables, synced_table->name, synced_table);
+        }
+
     }
 
     /* "isRoot" was not part of the original schema definition.  Before it was
@@ -308,8 +323,10 @@ ovsdb_schema_to_json(const struct ovsdb_schema *schema)
 
     SHASH_FOR_EACH (node, &schema->tables) {
         struct ovsdb_table_schema *table = node->data;
-        json_object_put(tables, table->name,
+        if (node->name[0] != '_') {
+            json_object_put(tables, table->name,
                         ovsdb_table_schema_to_json(table, default_is_root));
+        }
     }
     json_object_put(json, "tables", tables);
 
diff --git a/ovsdb/table.c b/ovsdb/table.c
index 6cd2d886d..b46946072 100644
--- a/ovsdb/table.c
+++ b/ovsdb/table.c
@@ -36,7 +36,8 @@ add_column(struct ovsdb_table_schema *ts, struct ovsdb_column *column)
 
 struct ovsdb_table_schema *
 ovsdb_table_schema_create(const char *name, bool mutable,
-                          unsigned int max_rows, bool is_root)
+                          unsigned int max_rows, bool is_root,
+                          bool copy_for_replication)
 {
     struct ovsdb_column *uuid, *version;
     struct ovsdb_table_schema *ts;
@@ -47,6 +48,7 @@ ovsdb_table_schema_create(const char *name, bool mutable,
     shash_init(&ts->columns);
     ts->max_rows = max_rows;
     ts->is_root = is_root;
+    ts->copy_for_replication = copy_for_replication;
 
     uuid = ovsdb_column_create("_uuid", false, true, &ovsdb_type_uuid);
     add_column(ts, uuid);
@@ -70,7 +72,8 @@ ovsdb_table_schema_clone(const struct ovsdb_table_schema *old)
     size_t i;
 
     new = ovsdb_table_schema_create(old->name, old->mutable,
-                                    old->max_rows, old->is_root);
+                                    old->max_rows, old->is_root,
+                                    old->copy_for_replication);
     SHASH_FOR_EACH (node, &old->columns) {
         const struct ovsdb_column *column = node->data;
 
@@ -126,7 +129,8 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name,
                              struct ovsdb_table_schema **tsp)
 {
     struct ovsdb_table_schema *ts;
-    const struct json *columns, *mutable, *max_rows, *is_root, *indexes;
+    const struct json *columns, *mutable, *max_rows;
+    const struct json *is_root, *indexes, *copy_for_replication;
     struct shash_node *node;
     struct ovsdb_parser parser;
     struct ovsdb_error *error;
@@ -141,6 +145,8 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name,
     max_rows = ovsdb_parser_member(&parser, "maxRows",
                                    OP_INTEGER | OP_OPTIONAL);
     is_root = ovsdb_parser_member(&parser, "isRoot", OP_BOOLEAN | OP_OPTIONAL);
+    copy_for_replication = ovsdb_parser_member(&parser, "copyForReplication",
+                                               OP_BOOLEAN | OP_OPTIONAL);
     indexes = ovsdb_parser_member(&parser, "indexes", OP_ARRAY | OP_OPTIONAL);
     error = ovsdb_parser_finish(&parser);
     if (error) {
@@ -165,7 +171,10 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name,
     ts = ovsdb_table_schema_create(name,
                                    mutable ? json_boolean(mutable) : true,
                                    MIN(n_max_rows, UINT_MAX),
-                                   is_root ? json_boolean(is_root) : false);
+                                   is_root ? json_boolean(is_root) : false,
+                                   copy_for_replication
+                                   ? json_boolean(copy_for_replication)
+                                   : false);
     SHASH_FOR_EACH (node, json_object(columns)) {
         struct ovsdb_column *column;
 
@@ -249,6 +258,9 @@ ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts,
     if (default_is_root != ts->is_root) {
         json_object_put(json, "isRoot", json_boolean_create(ts->is_root));
     }
+    if (ts->copy_for_replication) {
+        json_object_put(json, "copyForReplication", json_boolean_create(true));
+    }
 
     columns = json_object_create();
 
diff --git a/ovsdb/table.h b/ovsdb/table.h
index 69dd649df..afd56f7a6 100644
--- a/ovsdb/table.h
+++ b/ovsdb/table.h
@@ -29,6 +29,7 @@ struct ovsdb_table_schema {
     char *name;
     bool mutable;
     bool is_root;               /* Part of garbage collection root set? */
+    bool copy_for_replication;  /* '_synced_' copy of the table needed? */
     unsigned int max_rows;      /* Maximum number of rows. */
     struct shash columns;       /* Contains "struct ovsdb_column *"s. */
     struct ovsdb_column_set *indexes;
@@ -36,7 +37,8 @@ struct ovsdb_table_schema {
 };
 
 struct ovsdb_table_schema *ovsdb_table_schema_create(
-    const char *name, bool mutable, unsigned int max_rows, bool is_root);
+    const char *name, bool mutable, unsigned int max_rows,
+    bool is_root, bool copy_for_replication);
 struct ovsdb_table_schema *ovsdb_table_schema_clone(
     const struct ovsdb_table_schema *);
 void ovsdb_table_schema_destroy(struct ovsdb_table_schema *);
diff --git a/python/ovs/db/schema.py b/python/ovs/db/schema.py
index 3ba844ae5..e58e81080 100644
--- a/python/ovs/db/schema.py
+++ b/python/ovs/db/schema.py
@@ -80,6 +80,13 @@ class DbSchema(object):
             _check_id(tableName, json)
             tables[tableName] = TableSchema.from_json(tableJson, tableName,
                                                       allow_extensions)
+            if tables[tableName].copy_for_replication:
+                synced_table_name = "_synced_" + tableName
+                synced_table = TableSchema.from_json(tableJson,
+                                                     synced_table_name,
+                                                     allow_extensions)
+                synced_table.copy_for_replication = False
+                tables[synced_table_name] = synced_table
 
         return DbSchema(name, version, tables)
 
@@ -92,7 +99,8 @@ class DbSchema(object):
 
         tables = {}
         for table in self.tables.values():
-            tables[table.name] = table.to_json(default_is_root)
+            if not table.name.startswith("_"):
+                tables[table.name] = table.to_json(default_is_root)
         json = {"name": self.name, "tables": tables}
         if self.version:
             json["version"] = self.version
@@ -172,7 +180,8 @@ def column_set_from_json(json, columns):
 
 class TableSchema(object):
     def __init__(self, name, columns, mutable=True, max_rows=sys.maxsize,
-                 is_root=True, indexes=[], extensions={}):
+                 is_root=True, indexes=[], extensions={},
+                 copy_for_replication=False):
         self.name = name
         self.columns = columns
         self.mutable = mutable
@@ -180,6 +189,7 @@ class TableSchema(object):
         self.is_root = is_root
         self.indexes = indexes
         self.extensions = extensions
+        self.copy_for_replication = copy_for_replication
 
     @staticmethod
     def from_json(json, name, allow_extensions=False):
@@ -188,6 +198,8 @@ class TableSchema(object):
         mutable = parser.get_optional("mutable", [bool], True)
         max_rows = parser.get_optional("maxRows", [int])
         is_root = parser.get_optional("isRoot", [bool], False)
+        copy_for_replication = parser.get_optional("copyForReplication",
+                                                   [bool], False)
         indexes_json = parser.get_optional("indexes", [list], [])
         if allow_extensions:
             extensions = parser.get_optional("extensions", [dict], {})
@@ -224,7 +236,7 @@ class TableSchema(object):
             indexes.append(index)
 
         return TableSchema(name, columns, mutable, max_rows, is_root, indexes,
-                           extensions)
+                           extensions, copy_for_replication)
 
     def to_json(self, default_is_root=False):
         """Returns this table schema serialized into JSON.
@@ -243,6 +255,8 @@ class TableSchema(object):
             json["mutable"] = False
         if default_is_root != self.is_root:
             json["isRoot"] = self.is_root
+        if self.copy_for_replication:
+            json["copyForReplication"] = True
 
         json["columns"] = columns = {}
         for column in self.columns.values():
-- 
2.26.3



More information about the dev mailing list