On 23/09/2021 01:13, Ilya Maximets wrote: > ovsdb-server spends a lot of time cloning atoms for various reasons, > e.g. to create a diff of two rows or to clone a row to the transaction. > All atoms, except for strings, contains a simple value that could be > copied in efficient way, but duplicating strings every time has a > significant performance impact. > > Introducing a new reference-counted structure 'ovsdb_atom_string' > that allows to not copy strings every time, but just increase a > reference counter. > > Changes in ovsdb/ovsdb-idlc.in are a bit brute-force-like, but I > didn't manage to write anything better. And this part is very hard > to understand and debug, so maybe it's better to keep it in this > more or less understandable shape. > > This change allows to increase transaction throughput in benchmarks > up to 2x for standalone databases and 3x for clustered databases, i.e. > number of transactions that ovsdb-server can handle per second. > It also noticeably reduces memory consumption of ovsdb-server. >
Great! > Next step will be to consolidate this structure with json strings, > so we will not need to duplicate strings while converting database > objects to json and back. > > Signed-off-by: Ilya Maximets <i.maxim...@ovn.org> > --- > > There is a small conflict in lib/db-ctl-base.c with the 'set > optimizations' patch-set, but it can be easily resolved if > someone wants to try these patches together> > lib/db-ctl-base.c | 11 +-- > lib/ovsdb-cs.c | 2 +- > lib/ovsdb-data.c | 45 ++++++----- > lib/ovsdb-data.h | 29 ++++++- > lib/ovsdb-idl.c | 3 +- > ovsdb/ovsdb-idlc.in | 179 ++++++++++++++++++++++++++++------------- > ovsdb/ovsdb-server.c | 6 +- > ovsdb/ovsdb-util.c | 16 ++-- > ovsdb/rbac.c | 8 +- > python/ovs/db/data.py | 43 +++++++--- > python/ovs/db/types.py | 7 +- > tests/test-ovsdb.c | 14 ++-- > 12 files changed, 244 insertions(+), 119 deletions(-) > > diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c > index 77cc76a9f..713487797 100644 > --- a/lib/db-ctl-base.c > +++ b/lib/db-ctl-base.c > @@ -247,15 +247,15 @@ record_id_equals(const union ovsdb_atom *name, enum > ovsdb_atomic_type type, > const char *record_id) > { > if (type == OVSDB_TYPE_STRING) { > - if (!strcmp(name->string, record_id)) { > + if (!strcmp(name->s->string, record_id)) { > return true; > } > > struct uuid uuid; > size_t len = strlen(record_id); > if (len >= 4 > - && uuid_from_string(&uuid, name->string) > - && !strncmp(name->string, record_id, len)) { > + && uuid_from_string(&uuid, name->s->string) > + && !strncmp(name->s->string, record_id, len)) { > return true; > } > > @@ -318,11 +318,12 @@ get_row_by_id(struct ctl_context *ctx, > if (!id->key) { > name = datum->n == 1 ? &datum->keys[0] : NULL; > } else { > - const union ovsdb_atom key_atom > - = { .string = CONST_CAST(char *, id->key) }; > + union ovsdb_atom key_atom = { > + .s = ovsdb_atom_string_create(CONST_CAST(char *, id->key)) }; > unsigned int i = ovsdb_datum_find_key(datum, &key_atom, > OVSDB_TYPE_STRING); > name = i == UINT_MAX ? NULL : &datum->values[i]; > + ovsdb_atom_destroy(&key_atom, OVSDB_TYPE_STRING); > } > if (!name) { > continue; > diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c > index 659d49dbf..fcb6fe1b3 100644 > --- a/lib/ovsdb-cs.c > +++ b/lib/ovsdb-cs.c > @@ -1833,7 +1833,7 @@ server_column_get_string(const struct server_row *row, > { > ovs_assert(server_columns[index].type.key.type == OVSDB_TYPE_STRING); > const struct ovsdb_datum *d = &row->data[index]; > - return d->n == 1 ? d->keys[0].string : default_value; > + return d->n == 1 ? d->keys[0].s->string : default_value; > } > > static bool > diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c > index 1f491a98b..0ed8f01b6 100644 > --- a/lib/ovsdb-data.c > +++ b/lib/ovsdb-data.c > @@ -74,7 +74,7 @@ ovsdb_atom_init_default(union ovsdb_atom *atom, enum > ovsdb_atomic_type type) > break; > > case OVSDB_TYPE_STRING: > - atom->string = xmemdup("", 1); > + atom->s = ovsdb_atom_string_create_nocopy(xmemdup("", 1)); > break; > > case OVSDB_TYPE_UUID: > @@ -136,7 +136,7 @@ ovsdb_atom_is_default(const union ovsdb_atom *atom, > return atom->boolean == false; > > case OVSDB_TYPE_STRING: > - return atom->string[0] == '\0'; > + return atom->s->string[0] == '\0'; perhaps a helper function would allow you to hide some of this from a client. e.g. char *ovsdb_atom_string_get(struct ovsdb_atom) > > case OVSDB_TYPE_UUID: > return uuid_is_zero(&atom->uuid); > @@ -172,7 +172,8 @@ ovsdb_atom_clone(union ovsdb_atom *new, const union > ovsdb_atom *old, > break; > > case OVSDB_TYPE_STRING: > - new->string = xstrdup(old->string); > + new->s = old->s; > + new->s->n_refs++; > break; > > case OVSDB_TYPE_UUID: > @@ -214,7 +215,7 @@ ovsdb_atom_hash(const union ovsdb_atom *atom, enum > ovsdb_atomic_type type, > return hash_boolean(atom->boolean, basis); > > case OVSDB_TYPE_STRING: > - return hash_string(atom->string, basis); > + return hash_string(atom->s->string, basis); > > case OVSDB_TYPE_UUID: > return hash_int(uuid_hash(&atom->uuid), basis); > @@ -246,7 +247,7 @@ ovsdb_atom_compare_3way(const union ovsdb_atom *a, > return a->boolean - b->boolean; > > case OVSDB_TYPE_STRING: > - return strcmp(a->string, b->string); > + return a->s == b->s ? 0 : strcmp(a->s->string, b->s->string); > > case OVSDB_TYPE_UUID: > return uuid_compare_3way(&a->uuid, &b->uuid); > @@ -404,7 +405,7 @@ ovsdb_atom_from_json__(union ovsdb_atom *atom, > > case OVSDB_TYPE_STRING: > if (json->type == JSON_STRING) { > - atom->string = xstrdup(json->string); > + atom->s = ovsdb_atom_string_create(json->string); > return NULL; > } > break; > @@ -473,7 +474,7 @@ ovsdb_atom_to_json(const union ovsdb_atom *atom, enum > ovsdb_atomic_type type) > return json_boolean_create(atom->boolean); > > case OVSDB_TYPE_STRING: > - return json_string_create(atom->string); > + return json_string_create(atom->s->string); > > case OVSDB_TYPE_UUID: > return wrap_json("uuid", json_string_create_nocopy( > @@ -551,14 +552,18 @@ ovsdb_atom_from_string__(union ovsdb_atom *atom, > if (s_len < 2 || s[s_len - 1] != '"') { > return xasprintf("%s: missing quote at end of " > "quoted string", s); > - } else if (!json_string_unescape(s + 1, s_len - 2, > - &atom->string)) { > - char *error = xasprintf("%s: %s", s, atom->string); > - free(atom->string); > - return error; > + } else { > + char *res; > + if (json_string_unescape(s + 1, s_len - 2, &res)) { > + atom->s = ovsdb_atom_string_create_nocopy(res); > + } else { > + char *error = xasprintf("%s: %s", s, res); > + free(res); > + return error; > + } > } > } else { > - atom->string = xstrdup(s); > + atom->s = ovsdb_atom_string_create(s); > } > break; > > @@ -721,14 +726,14 @@ ovsdb_atom_to_string(const union ovsdb_atom *atom, enum > ovsdb_atomic_type type, > break; > > case OVSDB_TYPE_STRING: > - if (string_needs_quotes(atom->string)) { > + if (string_needs_quotes(atom->s->string)) { > struct json json; > > json.type = JSON_STRING; > - json.string = atom->string; > + json.string = atom->s->string; > json_to_ds(&json, 0, out); > } else { > - ds_put_cstr(out, atom->string); > + ds_put_cstr(out, atom->s->string); > } > break; > > @@ -750,7 +755,7 @@ ovsdb_atom_to_bare(const union ovsdb_atom *atom, enum > ovsdb_atomic_type type, > struct ds *out) > { > if (type == OVSDB_TYPE_STRING) { > - ds_put_cstr(out, atom->string); > + ds_put_cstr(out, atom->s->string); > } else { > ovsdb_atom_to_string(atom, type, out); > } > @@ -877,7 +882,7 @@ ovsdb_atom_check_constraints(const union ovsdb_atom *atom, > return NULL; > > case OVSDB_TYPE_STRING: > - return check_string_constraints(atom->string, &base->string); > + return check_string_constraints(atom->s->string, &base->string); > > case OVSDB_TYPE_UUID: > return NULL; > @@ -1691,8 +1696,8 @@ ovsdb_datum_from_smap(struct ovsdb_datum *datum, const > struct smap *smap) > struct smap_node *node; > size_t i = 0; > SMAP_FOR_EACH (node, smap) { > - datum->keys[i].string = xstrdup(node->key); > - datum->values[i].string = xstrdup(node->value); > + datum->keys[i].s = ovsdb_atom_string_create(node->key); > + datum->values[i].s = ovsdb_atom_string_create(node->value); > i++; > } > ovs_assert(i == datum->n); > diff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h > index aa035ebad..fa7e0d2fc 100644 > --- a/lib/ovsdb-data.h > +++ b/lib/ovsdb-data.h > @@ -20,6 +20,7 @@ > #include "compiler.h" > #include "ovsdb-types.h" > #include "openvswitch/shash.h" > +#include "util.h" > > #ifdef __cplusplus > extern "C" { > @@ -31,12 +32,33 @@ struct ds; > struct ovsdb_symbol_table; > struct smap; > > +struct ovsdb_atom_string { > + char *string; > + int n_refs; > +}; > + > +static inline struct ovsdb_atom_string * > +ovsdb_atom_string_create_nocopy(char *str) > +{ > + struct ovsdb_atom_string *s = xzalloc(sizeof *s); > + > + s->string = str; > + s->n_refs = 1; > + return s; > +} > + > +static inline struct ovsdb_atom_string * > +ovsdb_atom_string_create(const char *str) > +{ > + return ovsdb_atom_string_create_nocopy(xstrdup(str)); > +} > + > /* One value of an atomic type (given by enum ovs_atomic_type). */ > union ovsdb_atom { > int64_t integer; > double real; > bool boolean; > - char *string; > + struct ovsdb_atom_string *s; > struct uuid uuid; > }; > > @@ -66,8 +88,9 @@ ovsdb_atom_needs_destruction(enum ovsdb_atomic_type type) > static inline void > ovsdb_atom_destroy(union ovsdb_atom *atom, enum ovsdb_atomic_type type) > { > - if (type == OVSDB_TYPE_STRING) { > - free(atom->string); > + if (type == OVSDB_TYPE_STRING && !--atom->s->n_refs) { > + free(atom->s->string); > + free(atom->s); > } > } > > diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c > index d3caccec8..40125f234 100644 > --- a/lib/ovsdb-idl.c > +++ b/lib/ovsdb-idl.c > @@ -1951,8 +1951,7 @@ ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row > *row_) > BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) { > c = &class->columns[i]; > (c->unparse) (row); > - free(row->new_datum[i].values); > - free(row->new_datum[i].keys); > + ovsdb_datum_destroy(&row->new_datum[i], &c->type); > } > free(row->new_datum); > free(row->written); > diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in > index f19e92915..877f903cb 100755 > --- a/ovsdb/ovsdb-idlc.in > +++ b/ovsdb/ovsdb-idlc.in > @@ -577,20 +577,20 @@ static void > print(" smap_init(&row->%s);" % columnName) > print(" for (size_t i = 0; i < datum->n; i++) {") > print(" smap_add(&row->%s," % columnName) > - print(" datum->keys[i].string,") > - print(" datum->values[i].string);") > + print(" datum->keys[i].s->string,") > + print(" datum->values[i].s->string);") > print(" }") > elif (type.n_min == 1 and type.n_max == 1) or > type.is_optional_pointer(): > print("") > print(" if (datum->n >= 1) {") > if not type.key.ref_table: > - print(" %s = datum->keys[0].%s;" % (keyVar, > type.key.type.to_string())) > + print(" %s = datum->keys[0].%s;" % (keyVar, > type.key.type.to_Cvalue_string())) > else: > print(" %s = > %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_%s, &datum->keys[0].uuid));" % > (keyVar, prefix, type.key.ref_table.name.lower(), prefix, > type.key.ref_table.name.lower())) > > if valueVar: > if not type.value.ref_table: > - print(" %s = datum->values[0].%s;" % > (valueVar, type.value.type.to_string())) > + print(" %s = datum->values[0].%s;" % > (valueVar, type.value.type.to_Cvalue_string())) > else: > print(" %s = > %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_%s, &datum->values[0].uuid));" > % (valueVar, prefix, type.value.ref_table.name.lower(), prefix, > type.value.ref_table.name.lower())) > print(" } else {") > @@ -618,7 +618,7 @@ static void > """ % (prefix, type.key.ref_table.name.lower(), prefix, > type.key.ref_table.name.lower(), prefix, type.key.ref_table.name.lower())) > keySrc = "keyRow" > else: > - keySrc = "datum->keys[i].%s" % type.key.type.to_string() > + keySrc = "datum->keys[i].%s" % > type.key.type.to_Cvalue_string() > if type.value and type.value.ref_table: > print("""\ > struct %s%s *valueRow = %s%s_cast(ovsdb_idl_get_row_arc(row_, > &%stable_%s, &datum->values[i].uuid)); > @@ -628,7 +628,7 @@ static void > """ % (prefix, type.value.ref_table.name.lower(), prefix, > type.value.ref_table.name.lower(), prefix, type.value.ref_table.name.lower())) > valueSrc = "valueRow" > elif valueVar: > - valueSrc = "datum->values[i].%s" % > type.value.type.to_string() > + valueSrc = "datum->values[i].%s" % > type.value.type.to_Cvalue_string() > print(" if (!row->n_%s) {" % (columnName)) > > print(" %s = xmalloc(%s * sizeof *%s);" % ( > @@ -936,45 +936,57 @@ void > 'args': ', '.join(['%(type)s%(name)s' > % m for m in members])}) > if type.n_min == 1 and type.n_max == 1: > - print(" union ovsdb_atom key;") > + print(" union ovsdb_atom *key = xmalloc(sizeof *key);") > if type.value: > - print(" union ovsdb_atom value;") > + print(" union ovsdb_atom *value = xmalloc(sizeof > *value);") > print("") > print(" datum.n = 1;") > - print(" datum.keys = &key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key.%s" % > type.key.type.to_string(), keyVar)) > + print(" datum.keys = key;") > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(" + keyVar > + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar)) > if type.value: > - print(" datum.values = &value;") > - print(" "+ > type.value.assign_c_value_casting_away_const("value.%s" % > type.value.type.to_string(), valueVar)) > + print(" datum.values = value;") > + if type.value.type == StringType: > + print(" value->s = ovsdb_atom_string_create(" + > valueVar + ");") > + else: > + print(" "+ > type.value.assign_c_value_casting_away_const("value->%s" % > type.value.type.to_string(), valueVar)) > else: > print(" datum.values = NULL;") > - txn_write_func = "ovsdb_idl_txn_write_clone" > + txn_write_func = "ovsdb_idl_txn_write" > elif type.is_optional_pointer(): > - print(" union ovsdb_atom key;") > print("") > print(" if (%s) {" % keyVar) > + print(" union ovsdb_atom *key = xmalloc(sizeof > *key);") > print(" datum.n = 1;") > - print(" datum.keys = &key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key.%s" % > type.key.type.to_string(), keyVar)) > + print(" datum.keys = key;") > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(" + > keyVar + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar)) > print(" } else {") > print(" datum.n = 0;") > print(" datum.keys = NULL;") > print(" }") > print(" datum.values = NULL;") > - txn_write_func = "ovsdb_idl_txn_write_clone" > + txn_write_func = "ovsdb_idl_txn_write" > elif type.n_max == 1: > - print(" union ovsdb_atom key;") > print("") > print(" if (%s) {" % nVar) > + print(" union ovsdb_atom *key = xmalloc(sizeof > *key);") > print(" datum.n = 1;") > - print(" datum.keys = &key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key.%s" % > type.key.type.to_string(), "*" + keyVar)) > + print(" datum.keys = key;") > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(*" + > keyVar + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), "*" + keyVar)) > print(" } else {") > print(" datum.n = 0;") > print(" datum.keys = NULL;") > print(" }") > print(" datum.values = NULL;") > - txn_write_func = "ovsdb_idl_txn_write_clone" > + txn_write_func = "ovsdb_idl_txn_write" > else: > print("") > print(" datum.n = %s;" % nVar) > @@ -984,9 +996,15 @@ void > else: > print(" datum.values = NULL;") > print(" for (size_t i = 0; i < %s; i++) {" % nVar) > - print(" " + type.key.copyCValue("datum.keys[i].%s" % > type.key.type.to_string(), "%s[i]" % keyVar)) > + if type.key.type == StringType: > + print(" datum.keys[i].s = > ovsdb_atom_string_create(" + keyVar + "[i]);") > + else: > + print(" " + > type.key.copyCValue("datum.keys[i].%s" % type.key.type.to_string(), "%s[i]" % > keyVar)) > if type.value: > - print(" " + > type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), > "%s[i]" % valueVar)) > + if type.value.type == StringType: > + print(" datum.values[i].s = > ovsdb_atom_string_create(" + valueVar + "[i]);") > + else: > + print(" " + > type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), > "%s[i]" % valueVar)) > print(" }") > if type.value: > valueType = type.value.toAtomicType() > @@ -1022,9 +1040,14 @@ void > ''' % {'s': structName, 'c': > columnName,'coltype':column.type.key.to_const_c_type(prefix), > 'valtype':column.type.value.to_const_c_type(prefix), 'S': > structName.upper(), > 'C': columnName.upper(), 't': tableName}) > - > - print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "new_key")) > - print(" "+ type.value.copyCValue("datum->values[0].%s" % > type.value.type.to_string(), "new_value")) > + if type.key.type == StringType: > + print(" datum->keys[0].s = > ovsdb_atom_string_create(new_key);") > + else: > + print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "new_key")) > + if type.value.type == StringType: > + print(" datum->values[0].s = > ovsdb_atom_string_create(new_value);") > + else: > + print(" "+ > type.value.copyCValue("datum->values[0].%s" % type.value.type.to_string(), > "new_value")) > print(''' > ovsdb_idl_txn_write_partial_map(&row->header_, > &%(s)s_col_%(c)s, > @@ -1048,8 +1071,10 @@ void > ''' % {'s': structName, 'c': > columnName,'coltype':column.type.key.to_const_c_type(prefix), > 'valtype':column.type.value.to_const_c_type(prefix), 'S': > structName.upper(), > 'C': columnName.upper(), 't': tableName}) > - > - print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "delete_key")) > + if type.key.type == StringType: > + print(" datum->keys[0].s = > ovsdb_atom_string_create(delete_key);") > + else: > + print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "delete_key")) > print(''' > ovsdb_idl_txn_delete_partial_map(&row->header_, > &%(s)s_col_%(c)s, > @@ -1075,8 +1100,10 @@ void > datum->values = NULL; > ''' % {'s': structName, 'c': columnName, > 'valtype':column.type.key.to_const_c_type(prefix), 't': tableName}) > - > - print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "new_value")) > + if type.key.type == StringType: > + print(" datum->keys[0].s = > ovsdb_atom_string_create(new_value);") > + else: > + print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "new_value")) > print(''' > ovsdb_idl_txn_write_partial_set(&row->header_, > &%(s)s_col_%(c)s, > @@ -1100,8 +1127,10 @@ void > ''' % {'s': structName, 'c': > columnName,'coltype':column.type.key.to_const_c_type(prefix), > 'valtype':column.type.key.to_const_c_type(prefix), 'S': > structName.upper(), > 'C': columnName.upper(), 't': tableName}) > - > - print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "delete_value")) > + if type.key.type == StringType: > + print(" datum->keys[0].s = > ovsdb_atom_string_create(delete_value);") > + else: > + print(" "+ type.key.copyCValue("datum->keys[0].%s" % > type.key.type.to_string(), "delete_value")) > print(''' > ovsdb_idl_txn_delete_partial_set(&row->header_, > &%(s)s_col_%(c)s, > @@ -1169,37 +1198,49 @@ void > print(" struct ovsdb_datum datum;") > free = [] > if type.n_min == 1 and type.n_max == 1: > - print(" union ovsdb_atom key;") > + print(" union ovsdb_atom *key = xmalloc(sizeof *key);") > if type.value: > - print(" union ovsdb_atom value;") > + print(" union ovsdb_atom *value = xmalloc(sizeof > *value);") > print("") > print(" datum.n = 1;") > - print(" datum.keys = &key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key.%s" % > type.key.type.to_string(), keyVar, refTable=False)) > + print(" datum.keys = key;") > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(" + keyVar > + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar, refTable=False)) > if type.value: > - print(" datum.values = &value;") > - print(" "+ > type.value.assign_c_value_casting_away_const("value.%s" % > type.value.type.to_string(), valueVar, refTable=False)) > + print(" datum.values = value;") > + if type.value.type == StringType: > + print(" value->s = ovsdb_atom_string_create(" + > valueVar + ");") > + else: > + print(" "+ > type.value.assign_c_value_casting_away_const("value.%s" % > type.value.type.to_string(), valueVar, refTable=False)) > else: > print(" datum.values = NULL;") > elif type.is_optional_pointer(): > - print(" union ovsdb_atom key;") > print("") > print(" if (%s) {" % keyVar) > + print(" union ovsdb_atom *key = xmalloc(sizeof > *key);") > print(" datum.n = 1;") > - print(" datum.keys = &key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key.%s" % > type.key.type.to_string(), keyVar, refTable=False)) > + print(" datum.keys = key;") > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(" + > keyVar + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar, refTable=False)) > print(" } else {") > print(" datum.n = 0;") > print(" datum.keys = NULL;") > print(" }") > print(" datum.values = NULL;") > elif type.n_max == 1: > - print(" union ovsdb_atom key;") > print("") > print(" if (%s) {" % nVar) > + print(" union ovsdb_atom *key = xmalloc(sizeof > *key);") > print(" datum.n = 1;") > - print(" datum.keys = &key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key.%s" % > type.key.type.to_string(), "*" + keyVar, refTable=False)) > + print(" datum.keys = key;") > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(*" + > keyVar + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), "*" + keyVar, refTable=False)) > print(" } else {") > print(" datum.n = 0;") > print(" datum.keys = NULL;") > @@ -1208,16 +1249,20 @@ void > else: > print(" datum.n = %s;" % nVar) > print(" datum.keys = %s ? xmalloc(%s * sizeof > *datum.keys) : NULL;" % (nVar, nVar)) > - free += ['datum.keys'] > if type.value: > print(" datum.values = xmalloc(%s * sizeof > *datum.values);" % nVar) > - free += ['datum.values'] > else: > print(" datum.values = NULL;") > print(" for (size_t i = 0; i < %s; i++) {" % nVar) > - print(" " + > type.key.assign_c_value_casting_away_const("datum.keys[i].%s" % > type.key.type.to_string(), "%s[i]" % keyVar, refTable=False)) > + if type.key.type == StringType: > + print(" datum.keys[i].s = > ovsdb_atom_string_create(" + keyVar + "[i]);") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("datum.keys[i].%s" % > type.key.type.to_string(), "%s[i]" % keyVar, refTable=False)) > if type.value: > - print(" " + > type.value.assign_c_value_casting_away_const("datum.values[i].%s" % > type.value.type.to_string(), "%s[i]" % valueVar, refTable=False)) > + if type.value.type == StringType: > + print(" datum.values[i].s = > ovsdb_atom_string_create(" + valueVar + "[i]);") > + else: > + print(" " + > type.value.assign_c_value_casting_away_const("datum.values[i].%s" % > type.value.type.to_string(), "%s[i]" % valueVar, refTable=False)) > print(" }") > if type.value: > valueType = type.value.toAtomicType() > @@ -1237,8 +1282,8 @@ void > 's': structName, > 'S': structName.upper(), > 'c': columnName}) > - for var in free: > - print(" free(%s);" % var) > + print(" ovsdb_datum_destroy(&datum, &%(s)s_col_%(c)s.type);" \ > + % {'s': structName, 'c': columnName}) > print("}") > > # Index table related functions > @@ -1335,8 +1380,8 @@ struct %(s)s * > > i = 0; > SMAP_FOR_EACH (node, %(c)s) { > - datum->keys[i].string = node->key; > - datum->values[i].string = node->value; > + datum->keys[i].s = ovsdb_atom_string_create(node->key); > + datum->values[i].s = ovsdb_atom_string_create(node->value); > i++; > } > ovsdb_datum_sort_unique(datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING); > @@ -1385,10 +1430,16 @@ struct %(s)s * > print() > print(" datum.n = 1;") > print(" datum.keys = key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar)) > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(" + keyVar > + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar)) > if type.value: > print(" datum.values = value;") > - print(" "+ > type.value.assign_c_value_casting_away_const("value->%s" % > type.value.type.to_string(), valueVar)) > + if type.value.type == StringType: > + print(" value->s = ovsdb_atom_string_create(" + > valueVar + ");") > + else: > + print(" " + > type.value.assign_c_value_casting_away_const("value->%s" % > type.value.type.to_string(), valueVar)) > else: > print(" datum.values = NULL;") > txn_write_func = "ovsdb_idl_index_write" > @@ -1399,7 +1450,10 @@ struct %(s)s * > print(" key = xmalloc(sizeof (union ovsdb_atom));") > print(" datum.n = 1;") > print(" datum.keys = key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar)) > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(" + > keyVar + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), keyVar)) > print(" } else {") > print(" datum.n = 0;") > print(" datum.keys = NULL;") > @@ -1413,7 +1467,10 @@ struct %(s)s * > print(" key = xmalloc(sizeof(union ovsdb_atom));") > print(" datum.n = 1;") > print(" datum.keys = key;") > - print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), "*" + keyVar)) > + if type.key.type == StringType: > + print(" key->s = ovsdb_atom_string_create(*" + > keyVar + ");") > + else: > + print(" " + > type.key.assign_c_value_casting_away_const("key->%s" % > type.key.type.to_string(), "*" + keyVar)) > print(" } else {") > print(" datum.n = 0;") > print(" datum.keys = NULL;") > @@ -1430,9 +1487,15 @@ struct %(s)s * > else: > print(" datum.values = NULL;") > print(" for (i = 0; i < %s; i++) {" % nVar) > - print(" " + type.key.copyCValue("datum.keys[i].%s" % > type.key.type.to_string(), "%s[i]" % keyVar)) > + if type.key.type == StringType: > + print(" datum.keys[i].s = > ovsdb_atom_string_create(" + keyVar + "[i]);") > + else: > + print(" " + > type.key.copyCValue("datum.keys[i].%s" % type.key.type.to_string(), "%s[i]" % > keyVar)) > if type.value: > - print(" " + > type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), > "%s[i]" % valueVar)) > + if type.value.type == StringType: > + print(" datum.values[i].s = > ovsdb_atom_string_create(" + valueVar + "[i]);") > + else: > + print(" " + > type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), > "%s[i]" % valueVar)) > print(" }") > if type.value: > valueType = type.value.toAtomicType() > diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c > index 0b3d2bb71..b34d97e29 100644 > --- a/ovsdb/ovsdb-server.c > +++ b/ovsdb/ovsdb-server.c > @@ -904,8 +904,8 @@ query_db_string(const struct shash *all_dbs, const char > *name, > > datum = &row->fields[column->index]; > for (i = 0; i < datum->n; i++) { > - if (datum->keys[i].string[0]) { > - return datum->keys[i].string; > + if (datum->keys[i].s->string[0]) { > + return datum->keys[i].s->string; > } > } > } > @@ -1018,7 +1018,7 @@ query_db_remotes(const char *name, const struct shash > *all_dbs, > > datum = &row->fields[column->index]; > for (i = 0; i < datum->n; i++) { > - add_remote(remotes, datum->keys[i].string); > + add_remote(remotes, datum->keys[i].s->string); > } > } > } else if (column->type.key.type == OVSDB_TYPE_UUID > diff --git a/ovsdb/ovsdb-util.c b/ovsdb/ovsdb-util.c > index c4075cdae..6d7be066b 100644 > --- a/ovsdb/ovsdb-util.c > +++ b/ovsdb/ovsdb-util.c > @@ -111,13 +111,13 @@ ovsdb_util_read_map_string_column(const struct > ovsdb_row *row, > > for (i = 0; i < datum->n; i++) { > atom_key = &datum->keys[i]; > - if (!strcmp(atom_key->string, key)) { > + if (!strcmp(atom_key->s->string, key)) { > atom_value = &datum->values[i]; > break; > } > } > > - return atom_value ? atom_value->string : NULL; > + return atom_value ? atom_value->s->string : NULL; > } > > /* Read string-uuid key-values from a map. Returns the row associated with > @@ -143,7 +143,7 @@ ovsdb_util_read_map_string_uuid_column(const struct > ovsdb_row *row, > const struct ovsdb_datum *datum = &row->fields[column->index]; > for (size_t i = 0; i < datum->n; i++) { > union ovsdb_atom *atom_key = &datum->keys[i]; > - if (!strcmp(atom_key->string, key)) { > + if (!strcmp(atom_key->s->string, key)) { > const union ovsdb_atom *atom_value = &datum->values[i]; > return ovsdb_table_get_row(ref_table, &atom_value->uuid); > } > @@ -181,7 +181,7 @@ ovsdb_util_read_string_column(const struct ovsdb_row *row, > const union ovsdb_atom *atom; > > atom = ovsdb_util_read_column(row, column_name, OVSDB_TYPE_STRING); > - *stringp = atom ? atom->string : NULL; > + *stringp = atom ? atom->s->string : NULL; > return atom != NULL; > } > > @@ -269,8 +269,10 @@ ovsdb_util_write_string_column(struct ovsdb_row *row, > const char *column_name, > const char *string) > { > if (string) { > - const union ovsdb_atom atom = { .string = CONST_CAST(char *, string) > }; > + union ovsdb_atom atom = { > + .s = ovsdb_atom_string_create(CONST_CAST(char *, string)) }; > ovsdb_util_write_singleton(row, column_name, &atom, > OVSDB_TYPE_STRING); > + ovsdb_atom_destroy(&atom, OVSDB_TYPE_STRING); > } else { > ovsdb_util_clear_column(row, column_name); > } > @@ -305,8 +307,8 @@ ovsdb_util_write_string_string_column(struct ovsdb_row > *row, > datum->values = xmalloc(n * sizeof *datum->values); > > for (i = 0; i < n; ++i) { > - datum->keys[i].string = keys[i]; > - datum->values[i].string = values[i]; > + datum->keys[i].s = ovsdb_atom_string_create_nocopy(keys[i]); > + datum->values[i].s = ovsdb_atom_string_create_nocopy(values[i]); > } > > /* Sort and check constraints. */ > diff --git a/ovsdb/rbac.c b/ovsdb/rbac.c > index 2986027c9..ff411675f 100644 > --- a/ovsdb/rbac.c > +++ b/ovsdb/rbac.c > @@ -53,8 +53,8 @@ ovsdb_find_row_by_string_key(const struct ovsdb_table > *table, > HMAP_FOR_EACH (row, hmap_node, &table->rows) { > const struct ovsdb_datum *datum = &row->fields[column->index]; > for (size_t i = 0; i < datum->n; i++) { > - if (datum->keys[i].string[0] && > - !strcmp(key, datum->keys[i].string)) { > + if (datum->keys[i].s->string[0] && > + !strcmp(key, datum->keys[i].s->string)) { > return row; > } > } > @@ -113,7 +113,7 @@ ovsdb_rbac_authorized(const struct ovsdb_row *perms, > } > > for (i = 0; i < datum->n; i++) { > - const char *name = datum->keys[i].string; > + const char *name = datum->keys[i].s->string; > const char *value = NULL; > bool is_map; > > @@ -271,7 +271,7 @@ rbac_column_modification_permitted(const struct > ovsdb_column *column, > size_t i; > > for (i = 0; i < modifiable->n; i++) { > - char *name = modifiable->keys[i].string; > + char *name = modifiable->keys[i].s->string; > > if (!strcmp(name, column->name)) { > return true; > diff --git a/python/ovs/db/data.py b/python/ovs/db/data.py > index 2a2102d6b..99bf80ed6 100644 > --- a/python/ovs/db/data.py > +++ b/python/ovs/db/data.py > @@ -204,7 +204,7 @@ class Atom(object): > else: > return '.boolean = false' > elif self.type == ovs.db.types.StringType: > - return '.string = "%s"' % escapeCString(self.value) > + return '.s = %s' % escapeCString(self.value) > elif self.type == ovs.db.types.UuidType: > return '.uuid = %s' % ovs.ovsuuid.to_c_assignment(self.value) > > @@ -563,16 +563,41 @@ class Datum(object): > if n == 0: > return ["static struct ovsdb_datum %s = { .n = 0 };"] > > - s = ["static union ovsdb_atom %s_keys[%d] = {" % (name, n)] > - for key in sorted(self.values): > - s += [" { %s }," % key.cInitAtom(key)] > - s += ["};"] > + s = [] > + if self.type.key.type == ovs.db.types.StringType: > + s += ["static struct ovsdb_atom_string %s_key_strings[%d] = {" > + % (name, n)] > + for key in sorted(self.values): > + s += [' { .string = "%s", .n_refs = 2 },' > + % escapeCString(key.value)] > + s += ["};"] > + s += ["static union ovsdb_atom %s_keys[%d] = {" % (name, n)] > + for i in range(n): > + s += [" { .s = &%s_key_strings[%d] }," % (name, i)] > + s += ["};"] > + else: > + s = ["static union ovsdb_atom %s_keys[%d] = {" % (name, n)] > + for key in sorted(self.values): > + s += [" { %s }," % key.cInitAtom(key)] > + s += ["};"] > > if self.type.value: > - s = ["static union ovsdb_atom %s_values[%d] = {" % (name, n)] > - for k, v in sorted(self.values.items()): > - s += [" { %s }," % v.cInitAtom(v)] > - s += ["};"] > + if self.type.value.type == ovs.db.types.StringType: > + s += ["static struct ovsdb_atom_string %s_val_strings[%d] = > {" > + % (name, n)] > + for k, v in sorted(self.values): > + s += [' { .string = "%s", .n_refs = 2 },' > + % escapeCString(v.value)] > + s += ["};"] > + s += ["static union ovsdb_atom %s_values[%d] = {" % (name, > n)] > + for i in range(n): > + s += [" { .s = &%s_val_strings[%d] }," % (name, i)] > + s += ["};"] > + else: > + s = ["static union ovsdb_atom %s_values[%d] = {" % (name, n)] > + for k, v in sorted(self.values.items()): > + s += [" { %s }," % v.cInitAtom(v)] > + s += ["};"] > > s += ["static struct ovsdb_datum %s = {" % name] > s += [" .n = %d," % n] > diff --git a/python/ovs/db/types.py b/python/ovs/db/types.py > index 626ae8fc4..18485f701 100644 > --- a/python/ovs/db/types.py > +++ b/python/ovs/db/types.py > @@ -48,6 +48,11 @@ class AtomicType(object): > def to_string(self): > return self.name > > + def to_Cvalue_string(self): > + if self == StringType: > + return 's->' + self.name > + return self.name > + > def to_json(self): > return self.name > > @@ -373,7 +378,7 @@ class BaseType(object): > return "%(dst)s = *%(src)s;" % args > return ("%(dst)s = %(src)s->header_.uuid;") % args > elif self.type == StringType: > - return "%(dst)s = xstrdup(%(src)s);" % args > + return "%(dst)s = ovsdb_atom_string_create(%(src)s);" % args > else: > return "%(dst)s = %(src)s;" % args > > diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c > index 02485b136..c3ce4f361 100644 > --- a/tests/test-ovsdb.c > +++ b/tests/test-ovsdb.c > @@ -2727,13 +2727,15 @@ print_idl_row_simple2(const struct idltest_simple2 > *s, int step) > printf("%03d: name=%s smap=[", > step, s->name); > for (i = 0; i < smap->n; i++) { > - printf("[%s : %s]%s", smap->keys[i].string, smap->values[i].string, > - i < smap->n-1? ",": ""); > + printf("[%s : %s]%s", > + smap->keys[i].s->string, smap->values[i].s->string, > + i < smap->n - 1 ? "," : ""); > } > printf("] imap=["); > for (i = 0; i < imap->n; i++) { > - printf("[%"PRId64" : %s]%s", imap->keys[i].integer, > imap->values[i].string, > - i < imap->n-1? ",":""); > + printf("[%"PRId64" : %s]%s", > + imap->keys[i].integer, imap->values[i].s->string, > + i < imap->n - 1 ? "," : ""); > } > printf("]\n"); > } > @@ -2802,8 +2804,8 @@ do_idl_partial_update_map_column(struct > ovs_cmdl_context *ctx) > myTxn = ovsdb_idl_txn_create(idl); > smap = idltest_simple2_get_smap(myRow, OVSDB_TYPE_STRING, > OVSDB_TYPE_STRING); > - strcpy(key_to_delete, smap->keys[0].string); > - idltest_simple2_update_smap_delkey(myRow, smap->keys[0].string); > + ovs_strlcpy(key_to_delete, smap->keys[0].s->string, sizeof > key_to_delete); > + idltest_simple2_update_smap_delkey(myRow, smap->keys[0].s->string); > ovsdb_idl_txn_commit_block(myTxn); > ovsdb_idl_txn_destroy(myTxn); > ovsdb_idl_get_initial_snapshot(idl); > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev