timeval: Only log poll intervals longer than 50 ms.
[openvswitch] / python / ovs / db / schema.py
index 189b137c78186cb9daf37becb7450fbb5166e20a..e0e0daf5ec60b7bd093c4da8247676cbeadf2fec 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2009, 2010 Nicira Networks
+# Copyright (c) 2009, 2010, 2011 Nicira Networks
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import re
 import sys
 
 from ovs.db import error
@@ -21,8 +22,9 @@ from ovs.db import types
 class DbSchema(object):
     """Schema for an OVSDB database."""
 
-    def __init__(self, name, tables):
+    def __init__(self, name, version, tables):
         self.name = name
+        self.version = version
         self.tables = tables
 
         # Validate that all ref_tables refer to the names of tables
@@ -32,13 +34,36 @@ class DbSchema(object):
                 self.__check_ref_table(column, column.type.key, "key")
                 self.__check_ref_table(column, column.type.value, "value")
 
+        # "isRoot" was not part of the original schema definition.  Before it
+        # was added, there was no support for garbage collection.  So, for
+        # backward compatibility, if the root set is empty then assume that
+        # every table is in the root set.
+        if self.__root_set_size() == 0:
+            for table in self.tables.itervalues():
+                table.is_root = True
+
+    def __root_set_size(self):
+        """Returns the number of tables in the schema's root set."""
+        n_root = 0
+        for table in self.tables.itervalues():
+            if table.is_root:
+                n_root += 1
+        return n_root
+
     @staticmethod
     def from_json(json):
         parser = ovs.db.parser.Parser(json, "database schema")
         name = parser.get("name", ['id'])
+        version = parser.get_optional("version", [unicode])
+        parser.get_optional("cksum", [unicode])
         tablesJson = parser.get("tables", [dict])
         parser.finish()
 
+        if (version is not None and
+            not re.match('[0-9]+\.[0-9]+\.[0-9]+$', version)):
+            raise error.Error("schema version \"%s\" not in format x.y.z"
+                              % version)
+
         tables = {}
         for tableName, tableJson in tablesJson.iteritems():
             if tableName.startswith('_'):
@@ -48,13 +73,22 @@ class DbSchema(object):
                 raise error.Error("name must be a valid id", json)
             tables[tableName] = TableSchema.from_json(tableJson, tableName)
 
-        return DbSchema(name, tables)
+        return DbSchema(name, version, tables)
 
     def to_json(self):
+        # "isRoot" was not part of the original schema definition.  Before it
+        # was added, there was no support for garbage collection.  So, for
+        # backward compatibility, if every table is in the root set then do not
+        # output "isRoot" in table schemas.
+        default_is_root = self.__root_set_size() == len(self.tables)
+
         tables = {}
         for table in self.tables.itervalues():
-            tables[table.name] = table.to_json()
-        return {"name": self.name, "tables": tables}
+            tables[table.name] = table.to_json(default_is_root)
+        json = {"name": self.name, "tables": tables}
+        if self.version:
+            json["version"] = self.version
+        return json
 
     def __check_ref_table(self, column, base, base_name):
         if (base and base.type == types.UuidType and base.ref_table and
@@ -64,8 +98,8 @@ class DbSchema(object):
                               tag="syntax error")
 
 class IdlSchema(DbSchema):
-    def __init__(self, name, tables, idlPrefix, idlHeader):
-        DbSchema.__init__(self, name, tables)
+    def __init__(self, name, version, tables, idlPrefix, idlHeader):
+        DbSchema.__init__(self, name, version, tables)
         self.idlPrefix = idlPrefix
         self.idlHeader = idlHeader
 
@@ -80,14 +114,17 @@ class IdlSchema(DbSchema):
         del subjson["idlHeader"]
         schema = DbSchema.from_json(subjson)
 
-        return IdlSchema(schema.name, schema.tables, idlPrefix, idlHeader)
+        return IdlSchema(schema.name, schema.version, schema.tables,
+                         idlPrefix, idlHeader)
 
 class TableSchema(object):
-    def __init__(self, name, columns, mutable=True, max_rows=sys.maxint):
+    def __init__(self, name, columns, mutable=True, max_rows=sys.maxint,
+                 is_root=True):
         self.name = name
         self.columns = columns
         self.mutable = mutable
-        self.max_rows = max_rows        
+        self.max_rows = max_rows
+        self.is_root = is_root
 
     @staticmethod
     def from_json(json, name):
@@ -95,6 +132,7 @@ class TableSchema(object):
         columnsJson = parser.get("columns", [dict])
         mutable = parser.get_optional("mutable", [bool], True)
         max_rows = parser.get_optional("maxRows", [int])
+        is_root = parser.get_optional("isRoot", [bool], False)
         parser.finish()
 
         if max_rows == None:
@@ -115,12 +153,25 @@ class TableSchema(object):
             columns[columnName] = ColumnSchema.from_json(columnJson,
                                                          columnName)
 
-        return TableSchema(name, columns, mutable, max_rows)
+        return TableSchema(name, columns, mutable, max_rows, is_root)
 
-    def to_json(self):
+    def to_json(self, default_is_root=False):
+        """Returns this table schema serialized into JSON.
+
+        The "isRoot" member is included in the JSON only if its value would
+        differ from 'default_is_root'.  Ordinarily 'default_is_root' should be
+        false, because ordinarily a table would be not be part of the root set
+        if its "isRoot" member is omitted.  However, garbage collection was not
+        orginally included in OVSDB, so in older schemas that do not include
+        any "isRoot" members, every table is implicitly part of the root set.
+        To serialize such a schema in a way that can be read by older OVSDB
+        tools, specify 'default_is_root' as True.
+        """
         json = {}
         if not self.mutable:
             json["mutable"] = False
+        if default_is_root != self.is_root:
+            json["isRoot"] = self.is_root
 
         json["columns"] = columns = {}
         for column in self.columns.itervalues():