diff --git a/include/openvswitch/json.h b/include/openvswitch/json.h index 097bd057d..6e747f5d9 100644 --- a/include/openvswitch/json.h +++ b/include/openvswitch/json.h @@ -63,16 +63,28 @@ struct json_array { struct json **elems; }; +/* Maximum string length that can be stored inline ('\0' is not included). */ +#define JSON_STRING_INLINE_LEN (sizeof(struct json_array) - 1) + +enum json_storage_type { + JSON_STRING_DYNAMIC = 0, /* JSON_STRING is stored via 'str_ptr'. */ + JSON_STRING_INLINE, /* JSON_STRING is stored in 'str' array. */ +}; + /* A JSON value. */ struct json { enum json_type type; + enum json_storage_type storage_type; size_t count; union { struct shash *object; /* Contains "struct json *"s. */ struct json_array array; long long int integer; double real; - char *string; /* JSON_STRING or JSON_SERIALIZED_OBJECT. */ + union { + char str[JSON_STRING_INLINE_LEN + 1]; + char *str_ptr; + }; /* JSON_STRING or JSON_SERIALIZED_OBJECT. */ }; }; diff --git a/lib/json.c b/lib/json.c index fe223d9bc..fa92d56b3 100644 --- a/lib/json.c +++ b/lib/json.c @@ -179,14 +179,26 @@ struct json * json_string_create_nocopy(char *s) { struct json *json = json_create(JSON_STRING); - json->string = s; + json->storage_type = JSON_STRING_DYNAMIC; + json->str_ptr = s; return json; } struct json * json_string_create(const char *s) { - return json_string_create_nocopy(xstrdup(s)); + struct json *json = json_create(JSON_STRING); + size_t length = strlen(s); + + if (length <= JSON_STRING_INLINE_LEN) { + json->storage_type = JSON_STRING_INLINE; + memcpy(json->str, s, length); + json->str[length] = '\0'; + } else { + json->storage_type = JSON_STRING_DYNAMIC; + json->str_ptr = xmemdup0(s, length); + } + return json; } struct json *json_string_create_uuid(const struct uuid *uuid) @@ -198,7 +210,7 @@ struct json * json_serialized_object_create(const struct json *src) { struct json *json = json_create(JSON_SERIALIZED_OBJECT); - json->string = json_to_string(src, JSSF_SORT); + json->str_ptr = json_to_string(src, JSSF_SORT); return json; } @@ -206,7 +218,7 @@ struct json * json_serialized_object_create_with_yield(const struct json *src) { struct json *json = json_create(JSON_SERIALIZED_OBJECT); - json->string = json_to_string(src, JSSF_SORT | JSSF_YIELD); + json->str_ptr = json_to_string(src, JSSF_SORT | JSSF_YIELD); return json; } @@ -357,14 +369,15 @@ const char * json_string(const struct json *json) { ovs_assert(json->type == JSON_STRING); - return json->string; + return json->storage_type == JSON_STRING_DYNAMIC + ? json->str_ptr : json->str; } const char * json_serialized_object(const struct json *json) { ovs_assert(json->type == JSON_SERIALIZED_OBJECT); - return json->string; + return json->str_ptr; } struct json_array * @@ -419,11 +432,13 @@ json_destroy__(struct json *json, bool yield) break; case JSON_STRING: - free(json->string); + if (json->storage_type == JSON_STRING_DYNAMIC) { + free(json->str_ptr); + } break; case JSON_SERIALIZED_OBJECT: - free(json->string); + free(json->str_ptr); break; case JSON_NULL: @@ -1007,7 +1022,8 @@ json_string_escape(const char *in, struct ds *out) { struct json json = { .type = JSON_STRING, - .string = CONST_CAST(char *, in), + .storage_type = JSON_STRING_DYNAMIC, + .str_ptr = CONST_CAST(char *, in), }; json_to_ds(&json, 0, out); } diff --git a/python/ovs/db/data.py b/python/ovs/db/data.py index 3e9c5049f..30a34a098 100644 --- a/python/ovs/db/data.py +++ b/python/ovs/db/data.py @@ -573,7 +573,8 @@ class Datum(object): % (name, n)] for key in sorted(self.values): s += [' { .type = JSON_STRING, ' - '.string = "%s", .count = 2 },' + '.storage_type = JSON_STRING_DYNAMIC, ' + '.str_ptr = "%s", .count = 2 },' % escapeCString(key.value)] s += ["};"] s += ["static union ovsdb_atom %s_keys[%d] = {" % (name, n)] @@ -592,7 +593,8 @@ class Datum(object): % (name, n)] for k, v in sorted(self.values): s += [' { .type = JSON_STRING, ' - '.string = "%s", .count = 2 },' + '.storage_type = JSON_STRING_DYNAMIC, ' + '.str_ptr = "%s", .count = 2 },' % escapeCString(v.value)] s += ["};"] s += ["static union ovsdb_atom %s_values[%d] = {" % (name, n)] diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c index 0511e4170..ad4ca3b42 100644 --- a/tests/test-ovsdb.c +++ b/tests/test-ovsdb.c @@ -2413,10 +2413,13 @@ substitute_uuids(struct json *json, const struct ovsdb_symbol_table *symtab) if (json->type == JSON_STRING) { const struct ovsdb_symbol *symbol; - symbol = ovsdb_symbol_table_get(symtab, json->string); + symbol = ovsdb_symbol_table_get(symtab, json_string(json)); if (symbol) { - free(json->string); - json->string = xasprintf(UUID_FMT, UUID_ARGS(&symbol->uuid)); + if (json->storage_type == JSON_STRING_DYNAMIC) { + free(json->str_ptr); + } + json->storage_type = JSON_STRING_DYNAMIC; + json->str_ptr = xasprintf(UUID_FMT, UUID_ARGS(&symbol->uuid)); } } else if (json->type == JSON_ARRAY) { size_t i;