Makefile.am: Clean flake8-check too.
[cascardo/ovs.git] / lib / ovsdb-data.c
index 4e918a6..75febad 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ wrap_json(const char *name, struct json *wrapped)
 
 /* Initializes 'atom' with the default value of the given 'type'.
  *
- * The default value for an atom is as defined in ovsdb/SPECS:
+ * The default value for an atom is as defined in RFC 7047:
  *
  *      - "integer" or "real": 0
  *
@@ -58,7 +58,7 @@ ovsdb_atom_init_default(union ovsdb_atom *atom, enum ovsdb_atomic_type type)
 {
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         atom->integer = 0;
@@ -82,7 +82,7 @@ ovsdb_atom_init_default(union ovsdb_atom *atom, enum ovsdb_atomic_type type)
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -123,7 +123,7 @@ ovsdb_atom_is_default(const union ovsdb_atom *atom,
 {
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         return atom->integer == 0;
@@ -142,7 +142,7 @@ ovsdb_atom_is_default(const union ovsdb_atom *atom,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -156,7 +156,7 @@ ovsdb_atom_clone(union ovsdb_atom *new, const union ovsdb_atom *old,
 {
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         new->integer = old->integer;
@@ -180,7 +180,7 @@ ovsdb_atom_clone(union ovsdb_atom *new, const union ovsdb_atom *old,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -201,7 +201,7 @@ ovsdb_atom_hash(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
 {
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         return hash_int(atom->integer, basis);
@@ -220,7 +220,7 @@ ovsdb_atom_hash(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -233,7 +233,7 @@ ovsdb_atom_compare_3way(const union ovsdb_atom *a,
 {
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         return a->integer < b->integer ? -1 : a->integer > b->integer;
@@ -252,7 +252,7 @@ ovsdb_atom_compare_3way(const union ovsdb_atom *a,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -304,7 +304,7 @@ ovsdb_symbol_referenced(struct ovsdb_symbol *symbol,
     }
 }
 
-static struct ovsdb_error * WARN_UNUSED_RESULT
+static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
 ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
                       struct ovsdb_symbol_table *symtab,
                       const struct ovsdb_base_type *base)
@@ -343,7 +343,7 @@ ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
     return error0;
 }
 
-static struct ovsdb_error * WARN_UNUSED_RESULT
+static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
 ovsdb_atom_from_json__(union ovsdb_atom *atom,
                        const struct ovsdb_base_type *base,
                        const struct json *json,
@@ -353,7 +353,7 @@ ovsdb_atom_from_json__(union ovsdb_atom *atom,
 
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         if (json->type == JSON_INTEGER) {
@@ -394,7 +394,7 @@ ovsdb_atom_from_json__(union ovsdb_atom *atom,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     return ovsdb_syntax_error(json, NULL, "expected %s",
@@ -409,10 +409,9 @@ ovsdb_atom_from_json__(union ovsdb_atom *atom,
  * Violations of constraints expressed by 'base' are treated as errors.
  *
  * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted.  Refer to
- * ovsdb/SPECS for information about this, and for the syntax that this
- * function accepts.  If 'base' is a reference and a symbol is parsed, then the
- * symbol's 'strong_ref' or 'weak_ref' member is set to true, as
- * appropriate. */
+ * RFC 7047 for information about this, and for the syntax that this function
+ * accepts.  If 'base' is a reference and a symbol is parsed, then the symbol's
+ * 'strong_ref' or 'weak_ref' member is set to true, as appropriate. */
 struct ovsdb_error *
 ovsdb_atom_from_json(union ovsdb_atom *atom,
                      const struct ovsdb_base_type *base,
@@ -436,14 +435,13 @@ ovsdb_atom_from_json(union ovsdb_atom *atom,
 /* Converts 'atom', of the specified 'type', to JSON format, and returns the
  * JSON.  The caller is responsible for freeing the returned JSON.
  *
- * Refer to ovsdb/SPECS for the format of the JSON that this function
- * produces. */
+ * Refer to RFC 7047 for the format of the JSON that this function produces. */
 struct json *
 ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
 {
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         return json_integer_create(atom->integer);
@@ -463,51 +461,10 @@ ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
-/* Returns strlen(json_to_string(ovsdb_atom_to_json(atom, type), 0)). */
-size_t
-ovsdb_atom_json_length(const union ovsdb_atom *atom,
-                       enum ovsdb_atomic_type type)
-{
-    struct json json;
-
-    switch (type) {
-    case OVSDB_TYPE_VOID:
-        NOT_REACHED();
-
-    case OVSDB_TYPE_INTEGER:
-        json.type = JSON_INTEGER;
-        json.u.integer = atom->integer;
-        break;
-
-    case OVSDB_TYPE_REAL:
-        json.type = JSON_REAL;
-        json.u.real = atom->real;
-        break;
-
-    case OVSDB_TYPE_BOOLEAN:
-        json.type = atom->boolean ? JSON_TRUE : JSON_FALSE;
-        break;
-
-    case OVSDB_TYPE_STRING:
-        json.type = JSON_STRING;
-        json.u.string = atom->string;
-        break;
-
-    case OVSDB_TYPE_UUID:
-        return strlen("[\"uuid\",\"00000000-0000-0000-0000-000000000000\"]");
-
-    case OVSDB_N_TYPES:
-    default:
-        NOT_REACHED();
-    }
-
-    return json_serialized_length(&json);
-}
-
 static char *
 ovsdb_atom_from_string__(union ovsdb_atom *atom,
                          const struct ovsdb_base_type *base, const char *s,
@@ -517,7 +474,7 @@ ovsdb_atom_from_string__(union ovsdb_atom *atom,
 
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER: {
         long long int integer;
@@ -585,7 +542,7 @@ ovsdb_atom_from_string__(union ovsdb_atom *atom,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     return NULL;
@@ -671,7 +628,7 @@ ovsdb_atom_to_string(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
 {
     switch (type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         ds_put_format(out, "%"PRId64, atom->integer);
@@ -703,7 +660,7 @@ ovsdb_atom_to_string(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -784,7 +741,7 @@ ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
 
     switch (base->type) {
     case OVSDB_TYPE_VOID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_INTEGER:
         if (atom->integer >= base->u.integer.min
@@ -809,7 +766,7 @@ ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
                                "value %"PRId64,
                                atom->integer, base->u.integer.max);
         }
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_REAL:
         if (atom->real >= base->u.real.min && atom->real <= base->u.real.max) {
@@ -836,7 +793,7 @@ ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
                                DBL_DIG, atom->real,
                                DBL_DIG, base->u.real.max);
         }
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OVSDB_TYPE_BOOLEAN:
         return NULL;
@@ -849,7 +806,7 @@ ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
 
     case OVSDB_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 \f
@@ -884,7 +841,7 @@ ovsdb_datum_init_empty(struct ovsdb_datum *datum)
 
 /* Initializes 'datum' as a datum that has the default value for 'type'.
  *
- * The default value for a particular type is as defined in ovsdb/SPECS:
+ * The default value for a particular type is as defined in RFC 7047:
  *
  *    - If n_min is 0, then the default value is the empty set (or map).
  *
@@ -933,7 +890,7 @@ ovsdb_datum_default(const struct ovsdb_type *type)
         }
         return d;
     } else {
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1119,7 +1076,7 @@ ovsdb_datum_sort_assert(struct ovsdb_datum *datum,
 {
     struct ovsdb_error *error = ovsdb_datum_sort(datum, key_type);
     if (error) {
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1289,8 +1246,8 @@ ovsdb_datum_from_json__(struct ovsdb_datum *datum,
  * Violations of constraints expressed by 'type' are treated as errors.
  *
  * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted.  Refer to
- * ovsdb/SPECS for information about this, and for the syntax that this
- * function accepts. */
+ * RFC 7047 for information about this, and for the syntax that this function
+ * accepts. */
 struct ovsdb_error *
 ovsdb_datum_from_json(struct ovsdb_datum *datum,
                       const struct ovsdb_type *type,
@@ -1311,13 +1268,31 @@ ovsdb_datum_from_json(struct ovsdb_datum *datum,
     return error;
 }
 
+/* Parses 'json' as a datum of the type described by 'type' for internal
+ * use. This function is similar to 'ovsdb_datum_from_json', except the
+ * member size of set or map is not checked.
+ *
+ * The datum generated should be used then discard. It is not suitable
+ * for storing into IDL because of the possible member size violation.  */
+struct ovsdb_error *
+ovsdb_transient_datum_from_json(struct ovsdb_datum *datum,
+                                const struct ovsdb_type *type,
+                                const struct json *json)
+{
+    struct ovsdb_type relaxed_type = *type;
+
+    relaxed_type.n_min = 0;
+    relaxed_type.n_max = UINT_MAX;
+
+    return ovsdb_datum_from_json(datum, &relaxed_type, json, NULL);
+}
+
 /* Converts 'datum', of the specified 'type', to JSON format, and returns the
  * JSON.  The caller is responsible for freeing the returned JSON.
  *
  * 'type' constraints on datum->n are ignored.
  *
- * Refer to ovsdb/SPECS for the format of the JSON that this function
- * produces. */
+ * Refer to RFC 7047 for the format of the JSON that this function produces. */
 struct json *
 ovsdb_datum_to_json(const struct ovsdb_datum *datum,
                     const struct ovsdb_type *type)
@@ -1349,56 +1324,6 @@ ovsdb_datum_to_json(const struct ovsdb_datum *datum,
     }
 }
 
-/* Returns strlen(json_to_string(ovsdb_datum_to_json(datum, type), 0)). */
-size_t
-ovsdb_datum_json_length(const struct ovsdb_datum *datum,
-                        const struct ovsdb_type *type)
-{
-    if (ovsdb_type_is_map(type)) {
-        size_t length;
-
-        /* ["map",[...]]. */
-        length = 10;
-        if (datum->n > 0) {
-            size_t i;
-
-            /* Commas between pairs in the inner [...] */
-            length += datum->n - 1;
-
-            /* [,] in each pair. */
-            length += datum->n * 3;
-
-            /* Data. */
-            for (i = 0; i < datum->n; i++) {
-                length += ovsdb_atom_json_length(&datum->keys[i],
-                                                 type->key.type);
-                length += ovsdb_atom_json_length(&datum->values[i],
-                                                 type->value.type);
-            }
-        }
-        return length;
-    } else if (datum->n == 1) {
-        return ovsdb_atom_json_length(&datum->keys[0], type->key.type);
-    } else {
-        size_t length;
-        size_t i;
-
-        /* ["set",[...]]. */
-        length = 10;
-        if (datum->n > 0) {
-            /* Commas between elements in the inner [...]. */
-            length += datum->n - 1;
-
-            /* Data. */
-            for (i = 0; i < datum->n; i++) {
-                length += ovsdb_atom_json_length(&datum->keys[i],
-                                                 type->key.type);
-            }
-        }
-        return length;
-    }
-}
-
 static const char *
 skip_spaces(const char *p)
 {
@@ -1980,6 +1905,89 @@ ovsdb_symbol_table_insert(struct ovsdb_symbol_table *symtab,
     return symbol;
 }
 \f
+/* APIs for Generating and apply diffs.  */
+
+/* Generate a difference ovsdb_dataum between 'old' and 'new'.
+ * 'new' can be regenerated by applying the difference to the 'old'.
+ *
+ * The diff operation is reversible. Given 'old',
+ * 'new' can be recreated by applying diff to 'old'.
+ *
+ * Thus
+ *     Let  d = 'old' diff 'new'
+ *     then 'new' = 'old' diff d
+ *
+ * The 'diff' datum is always safe; the orders of keys are maintained
+ * since they are added in order.   */
+void
+ovsdb_datum_diff(struct ovsdb_datum *diff,
+                 const struct ovsdb_datum *old,
+                 const struct ovsdb_datum *new,
+                 const struct ovsdb_type *type)
+{
+    size_t oi, ni;
+
+    ovsdb_datum_init_empty(diff);
+    if (!ovsdb_type_is_composite(type)) {
+        ovsdb_datum_clone(diff, new, type);
+        return;
+    }
+
+    /* Generate the diff in O(n) time. */
+    for (oi = ni = 0; oi < old->n && ni < new->n; ) {
+        int c = ovsdb_atom_compare_3way(&old->keys[oi], &new->keys[ni],
+                                        type->key.type);
+        if (c < 0) {
+            ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi],
+                                   type);
+            oi++;
+        } else if (c > 0) {
+            ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
+                                   type);
+            ni++;
+        } else {
+            if (type->value.type != OVSDB_TYPE_VOID &&
+                ovsdb_atom_compare_3way(&old->values[oi], &new->values[ni],
+                                        type->value.type)) {
+                ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
+                                       type);
+            }
+            oi++; ni++;
+        }
+    }
+
+    for (; oi < old->n; oi++) {
+        ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi], type);
+    }
+
+    for (; ni < new->n; ni++) {
+        ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni], type);
+    }
+}
+
+/* Apply 'diff' to 'old' to regenerate 'new'.
+ *
+ * Return NULL if the 'new' is successfully generated, otherwise, return
+ * ovsdb_error and the stat of 'new' is indeterministic. */
+struct ovsdb_error *
+ovsdb_datum_apply_diff(struct ovsdb_datum *new,
+                       const struct ovsdb_datum *old,
+                       const struct ovsdb_datum *diff,
+                       const struct ovsdb_type *type)
+{
+    ovsdb_datum_init_empty(new);
+    ovsdb_datum_diff(new, old, diff, type);
+
+    /* Make sure member size of 'new' conforms to type. */
+    if (new->n < type->n_min || new->n > type->n_max) {
+        ovsdb_datum_destroy(new, type);
+        return ovsdb_error(NULL, "Datum crated by diff has size error");
+    }
+
+    return NULL;
+}
+
+\f
 /* Extracts a token from the beginning of 's' and returns a pointer just after
  * the token.  Stores the token itself into '*outp', which the caller is
  * responsible for freeing (with free()).