X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fovsdb-data.c;h=20d333eff177f6b93633f4b81d3bd627350d7acf;hb=f915f1a8ca180828983ef22cf2fd21b8f010b972;hp=d08128f52b1916378c8adcb36121c84aa9a6d1d4;hpb=5413de95bec046cff2cf72482d65f7fa435aa10e;p=openvswitch diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c index d08128f5..20d333ef 100644 --- a/lib/ovsdb-data.c +++ b/lib/ovsdb-data.c @@ -84,6 +84,31 @@ ovsdb_atom_init_default(union ovsdb_atom *atom, enum ovsdb_atomic_type type) } } +/* Returns a read-only atom of the given 'type' that has the default value for + * 'type'. The caller must not modify or free the returned atom. + * + * See ovsdb_atom_init_default() for an explanation of the default value of an + * atom. */ +const union ovsdb_atom * +ovsdb_atom_default(enum ovsdb_atomic_type type) +{ + static union ovsdb_atom default_atoms[OVSDB_N_TYPES]; + static bool inited; + + if (!inited) { + int i; + + for (i = 0; i < OVSDB_N_TYPES; i++) { + if (i != OVSDB_TYPE_VOID) { + ovsdb_atom_init_default(&default_atoms[i], i); + } + } + inited = true; + } + + assert(ovsdb_atomic_type_is_valid(type)); + return &default_atoms[type]; +} /* Returns true if 'atom', which must have the given 'type', has the default * value for that type. @@ -239,6 +264,7 @@ unwrap_json(const struct json *json, const char *name, || (name && strcmp(json->u.array.elems[0]->u.string, name)) || json->u.array.elems[1]->type != value_type) { + *value = NULL; return ovsdb_syntax_error(json, NULL, "expected [\"%s\", <%s>]", name, json_type_to_string(value_type)); } @@ -349,8 +375,11 @@ ovsdb_atom_from_json__(union ovsdb_atom *atom, enum ovsdb_atomic_type type, * returns an error and the contents of 'atom' are indeterminate. The caller * is responsible for freeing the error or the atom that is returned. * + * 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 information about this and other syntactical details. */ + * ovsdb/SPECS for information about this, and for the syntax that this + * function accepts. */ struct ovsdb_error * ovsdb_atom_from_json(union ovsdb_atom *atom, const struct ovsdb_base_type *base, @@ -372,7 +401,10 @@ 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. */ + * JSON. The caller is responsible for freeing the returned JSON. + * + * Refer to ovsdb/SPECS 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) { @@ -776,6 +808,39 @@ ovsdb_datum_init_default(struct ovsdb_datum *datum, datum->values = alloc_default_atoms(type->value.type, datum->n); } +/* Returns a read-only datum of the given 'type' that has the default value for + * 'type'. The caller must not modify or free the returned datum. + * + * See ovsdb_datum_init_default() for an explanation of the default value of a + * datum. */ +const struct ovsdb_datum * +ovsdb_datum_default(const struct ovsdb_type *type) +{ + if (type->n_min == 0) { + static const struct ovsdb_datum empty; + return ∅ + } else if (type->n_min == 1) { + static struct ovsdb_datum default_data[OVSDB_N_TYPES][OVSDB_N_TYPES]; + struct ovsdb_datum *d; + int kt = type->key.type; + int vt = type->value.type; + + assert(ovsdb_type_is_valid(type)); + + d = &default_data[kt][vt]; + if (!d->n) { + d->n = 1; + d->keys = (union ovsdb_atom *) ovsdb_atom_default(kt); + if (vt != OVSDB_TYPE_VOID) { + d->values = (union ovsdb_atom *) ovsdb_atom_default(vt); + } + } + return d; + } else { + NOT_REACHED(); + } +} + /* Returns true if 'datum', which must have the given 'type', has the default * value for that type. * @@ -871,6 +936,7 @@ ovsdb_datum_swap(struct ovsdb_datum *a, struct ovsdb_datum *b) struct ovsdb_datum_sort_cbdata { enum ovsdb_atomic_type key_type; + enum ovsdb_atomic_type value_type; struct ovsdb_datum *datum; }; @@ -878,10 +944,18 @@ static int ovsdb_datum_sort_compare_cb(size_t a, size_t b, void *cbdata_) { struct ovsdb_datum_sort_cbdata *cbdata = cbdata_; + int retval; + + retval = ovsdb_atom_compare_3way(&cbdata->datum->keys[a], + &cbdata->datum->keys[b], + cbdata->key_type); + if (retval || cbdata->value_type == OVSDB_TYPE_VOID) { + return retval; + } - return ovsdb_atom_compare_3way(&cbdata->datum->keys[a], - &cbdata->datum->keys[b], - cbdata->key_type); + return ovsdb_atom_compare_3way(&cbdata->datum->values[a], + &cbdata->datum->values[b], + cbdata->value_type); } static void @@ -895,6 +969,19 @@ ovsdb_datum_sort_swap_cb(size_t a, size_t b, void *cbdata_) } } +static void +ovsdb_datum_sort__(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type, + enum ovsdb_atomic_type value_type) +{ + struct ovsdb_datum_sort_cbdata cbdata; + + cbdata.key_type = key_type; + cbdata.value_type = value_type; + cbdata.datum = datum; + sort(datum->n, ovsdb_datum_sort_compare_cb, ovsdb_datum_sort_swap_cb, + &cbdata); +} + /* The keys in an ovsdb_datum must be unique and in sorted order. Most * functions that modify an ovsdb_datum maintain these invariants. For those * that don't, this function checks and restores these invariants for 'datum', @@ -906,30 +993,25 @@ ovsdb_datum_sort_swap_cb(size_t a, size_t b, void *cbdata_) struct ovsdb_error * ovsdb_datum_sort(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type) { + size_t i; + if (datum->n < 2) { return NULL; - } else { - struct ovsdb_datum_sort_cbdata cbdata; - size_t i; + } - cbdata.key_type = key_type; - cbdata.datum = datum; - sort(datum->n, ovsdb_datum_sort_compare_cb, ovsdb_datum_sort_swap_cb, - &cbdata); - - for (i = 0; i < datum->n - 1; i++) { - if (ovsdb_atom_equals(&datum->keys[i], &datum->keys[i + 1], - key_type)) { - if (datum->values) { - return ovsdb_error(NULL, "map contains duplicate key"); - } else { - return ovsdb_error(NULL, "set contains duplicate"); - } + ovsdb_datum_sort__(datum, key_type, OVSDB_TYPE_VOID); + + for (i = 0; i < datum->n - 1; i++) { + if (ovsdb_atom_equals(&datum->keys[i], &datum->keys[i + 1], + key_type)) { + if (datum->values) { + return ovsdb_error(NULL, "map contains duplicate key"); + } else { + return ovsdb_error(NULL, "set contains duplicate"); } } - - return NULL; } + return NULL; } /* This function is the same as ovsdb_datum_sort(), except that the caller @@ -945,6 +1027,46 @@ ovsdb_datum_sort_assert(struct ovsdb_datum *datum, } } +/* This is similar to ovsdb_datum_sort(), except that it drops duplicate keys + * instead of reporting an error. In a map type, the smallest value among a + * group of duplicate pairs is retained and the others are dropped. + * + * Returns the number of keys (or pairs) that were dropped. */ +size_t +ovsdb_datum_sort_unique(struct ovsdb_datum *datum, + enum ovsdb_atomic_type key_type, + enum ovsdb_atomic_type value_type) +{ + size_t src, dst; + + if (datum->n < 2) { + return 0; + } + + ovsdb_datum_sort__(datum, key_type, value_type); + + dst = 1; + for (src = 1; src < datum->n; src++) { + if (ovsdb_atom_equals(&datum->keys[src], &datum->keys[dst - 1], + key_type)) { + ovsdb_atom_destroy(&datum->keys[src], key_type); + if (value_type != OVSDB_TYPE_VOID) { + ovsdb_atom_destroy(&datum->values[src], value_type); + } + } else { + if (src != dst) { + datum->keys[dst] = datum->keys[src]; + if (value_type != OVSDB_TYPE_VOID) { + datum->values[dst] = datum->values[src]; + } + } + dst++; + } + } + datum->n = dst; + return datum->n - src; +} + /* Checks that each of the atoms in 'datum' conforms to the constraints * specified by its 'type'. Returns an error if a constraint is violated, * otherwise a null pointer. @@ -979,11 +1101,11 @@ ovsdb_datum_check_constraints(const struct ovsdb_datum *datum, return NULL; } -struct ovsdb_error * -ovsdb_datum_from_json(struct ovsdb_datum *datum, - const struct ovsdb_type *type, - const struct json *json, - struct ovsdb_symbol_table *symtab) +static struct ovsdb_error * +ovsdb_datum_from_json__(struct ovsdb_datum *datum, + const struct ovsdb_type *type, + const struct json *json, + struct ovsdb_symbol_table *symtab) { struct ovsdb_error *error; @@ -1044,12 +1166,6 @@ ovsdb_datum_from_json(struct ovsdb_datum *datum, datum->n++; } - - error = ovsdb_datum_sort(datum, type->key.type); - if (error) { - goto error; - } - return NULL; error: @@ -1069,12 +1185,47 @@ ovsdb_datum_from_json(struct ovsdb_datum *datum, } } +/* Parses 'json' as a datum of the type described by 'type'. If successful, + * returns NULL and initializes 'datum' with the parsed datum. On failure, + * returns an error and the contents of 'datum' are indeterminate. The caller + * is responsible for freeing the error or the datum that is returned. + * + * 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. */ +struct ovsdb_error * +ovsdb_datum_from_json(struct ovsdb_datum *datum, + const struct ovsdb_type *type, + const struct json *json, + struct ovsdb_symbol_table *symtab) +{ + struct ovsdb_error *error; + + error = ovsdb_datum_from_json__(datum, type, json, symtab); + if (error) { + return error; + } + + error = ovsdb_datum_sort(datum, type->key.type); + if (error) { + ovsdb_datum_destroy(datum, type); + } + return error; +} + +/* 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. */ struct json * ovsdb_datum_to_json(const struct ovsdb_datum *datum, const struct ovsdb_type *type) { - /* These tests somewhat tolerate a 'datum' that does not exactly match - * 'type', in particular a datum with 'n' not in the allowed range. */ if (datum->n == 1 && !ovsdb_type_is_map(type)) { return ovsdb_atom_to_json(&datum->keys[0], type->key.type); } else if (type->value.type == OVSDB_TYPE_VOID) { @@ -1294,6 +1445,31 @@ ovsdb_datum_to_string(const struct ovsdb_datum *datum, } } +/* Initializes 'datum' as a string-to-string map whose contents are taken from + * 'sh'. Destroys 'sh'. */ +void +ovsdb_datum_from_shash(struct ovsdb_datum *datum, struct shash *sh) +{ + struct shash_node *node, *next; + size_t i; + + datum->n = shash_count(sh); + datum->keys = xmalloc(datum->n * sizeof *datum->keys); + datum->values = xmalloc(datum->n * sizeof *datum->values); + + i = 0; + SHASH_FOR_EACH_SAFE (node, next, sh) { + datum->keys[i].string = node->name; + datum->values[i].string = node->data; + shash_steal(sh, node); + i++; + } + assert(i == datum->n); + + shash_destroy(sh); + ovsdb_datum_sort_unique(datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING); +} + static uint32_t hash_atoms(enum ovsdb_atomic_type type, const union ovsdb_atom *atoms, unsigned int n, uint32_t basis)