[ovs-dev] [PATCH v2 1/3] json: Add support for partially serialized json objects.
Ilya Maximets
i.maximets at ovn.org
Tue Aug 31 18:00:41 UTC 2021
On 8/31/21 2:26 AM, Han Zhou wrote:
>
>
> On Tue, Aug 24, 2021 at 12:00 PM Ilya Maximets <i.maximets at ovn.org <mailto:i.maximets at ovn.org>> wrote:
>>
>> Introducing a new json type JSON_SERIALIZED_OBJECT. It's not an
>> actual type that can be seen in a json message on a wire, but
>> internal type that is intended to hold a serialized version of
>> some other json object. For this reason it's defined after the
>> JSON_N_TYPES to not confuse parsers and other parts of the code
>> that relies on compliance with RFC 4627.
>>
>> With this JSON type internal users may construct large JSON objects,
>> parts of which are already serialized. This way, while serializing
>> the larger object, data from JSON_SERIALIZED_OBJECT can be added
>> directly to the result, without additional processing.
>>
>> This will be used by next commits to add pre-serialized JSON data
>> to the raft_header structure, that can be converted to a JSON
>> before writing the file transaction on disk or sending to other
>> servers. Same technique can also be used to pre-serialize json_cache
>> for ovsdb monitors, this should allow to not perform serialization
>> for every client and will save some more memory.
>>
>> Since serialized JSON is just a string, reusing the 'json->string'
>> pointer for it.
>>
>> Signed-off-by: Ilya Maximets <i.maximets at ovn.org <mailto:i.maximets at ovn.org>>
>> ---
>> include/openvswitch/json.h | 9 +++++++--
>> lib/json.c | 34 ++++++++++++++++++++++++++++++++++
>> 2 files changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/openvswitch/json.h b/include/openvswitch/json.h
>> index 73b562e03..b8cf49ab6 100644
>> --- a/include/openvswitch/json.h
>> +++ b/include/openvswitch/json.h
>> @@ -50,7 +50,9 @@ enum json_type {
>> JSON_INTEGER, /* 123. */
>> JSON_REAL, /* 123.456. */
>> JSON_STRING, /* "..." */
>> - JSON_N_TYPES
>> + JSON_N_TYPES,
>> + JSON_SERIALIZED_OBJECT, /* Internal type to hold serialized version of
>> + * data of other types. */
>> };
>>
>> const char *json_type_to_string(enum json_type);
>> @@ -70,7 +72,7 @@ struct json {
>> struct json_array array;
>> long long int integer;
>> double real;
>> - char *string;
>> + char *string; /* JSON_STRING or JSON_SERIALIZED_OBJECT. */
>> };
>> };
>>
>> @@ -78,6 +80,7 @@ struct json *json_null_create(void);
>> struct json *json_boolean_create(bool);
>> struct json *json_string_create(const char *);
>> struct json *json_string_create_nocopy(char *);
>> +struct json *json_serialized_object_create(const struct json *);
>> struct json *json_integer_create(long long int);
>> struct json *json_real_create(double);
>>
>> @@ -99,6 +102,7 @@ void json_object_put_format(struct json *,
>> OVS_PRINTF_FORMAT(3, 4);
>>
>> const char *json_string(const struct json *);
>> +const char *json_serialized_object(const struct json *);
>> struct json_array *json_array(const struct json *);
>> struct shash *json_object(const struct json *);
>> bool json_boolean(const struct json *);
>> @@ -125,6 +129,7 @@ struct json *json_parser_finish(struct json_parser *);
>> void json_parser_abort(struct json_parser *);
>>
>> struct json *json_from_string(const char *string);
>> +struct json *json_from_serialized_object(const struct json *);
>> struct json *json_from_file(const char *file_name);
>> struct json *json_from_stream(FILE *stream);
>>
>> diff --git a/lib/json.c b/lib/json.c
>> index 32d25003b..6bb620724 100644
>> --- a/lib/json.c
>> +++ b/lib/json.c
>> @@ -146,6 +146,7 @@ json_type_to_string(enum json_type type)
>> case JSON_STRING:
>> return "string";
>>
>> + case JSON_SERIALIZED_OBJECT:
>> case JSON_N_TYPES:
>> default:
>> return "<invalid>";
>> @@ -180,6 +181,14 @@ json_string_create(const char *s)
>> return json_string_create_nocopy(xstrdup(s));
>> }
>>
>> +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);
>> + return json;
>> +}
>> +
>> struct json *
>> json_array_create_empty(void)
>> {
>> @@ -309,6 +318,13 @@ json_string(const struct json *json)
>> return json->string;
>> }
>>
>> +const char *
>> +json_serialized_object(const struct json *json)
>> +{
>> + ovs_assert(json->type == JSON_SERIALIZED_OBJECT);
>> + return json->string;
>> +}
>> +
>> struct json_array *
>> json_array(const struct json *json)
>> {
>> @@ -362,6 +378,7 @@ json_destroy(struct json *json)
>> break;
>>
>> case JSON_STRING:
>> + case JSON_SERIALIZED_OBJECT:
>> free(json->string);
>> break;
>>
>> @@ -422,6 +439,9 @@ json_deep_clone(const struct json *json)
>> case JSON_STRING:
>> return json_string_create(json->string);
>>
>> + case JSON_SERIALIZED_OBJECT:
>> + return json_serialized_object_create(json);
>> +
>> case JSON_NULL:
>> case JSON_FALSE:
>> case JSON_TRUE:
>> @@ -521,6 +541,7 @@ json_hash(const struct json *json, size_t basis)
>> return json_hash_array(&json->array, basis);
>>
>> case JSON_STRING:
>> + case JSON_SERIALIZED_OBJECT:
>> return hash_string(json->string, basis);
>>
>> case JSON_NULL:
>> @@ -596,6 +617,7 @@ json_equal(const struct json *a, const struct json *b)
>> return json_equal_array(&a->array, &b->array);
>>
>> case JSON_STRING:
>> + case JSON_SERIALIZED_OBJECT:
>> return !strcmp(a->string, b->string);
>>
>> case JSON_NULL:
>> @@ -1072,6 +1094,14 @@ json_from_string(const char *string)
>> return json_parser_finish(p);
>> }
>>
>> +/* Parses data of JSON_SERIALIZED_OBJECT to the real JSON. */
>> +struct json *
>> +json_from_serialized_object(const struct json *json)
>> +{
>> + ovs_assert(json->type == JSON_SERIALIZED_OBJECT);
>> + return json_from_string(json->string);
>> +}
>> +
>> /* Reads the file named 'file_name', parses its contents as a JSON object or
>> * array, and returns a newly allocated 'struct json'. The caller must free
>> * the returned structure with json_destroy() when it is no longer needed.
>> @@ -1563,6 +1593,10 @@ json_serialize(const struct json *json, struct json_serializer *s)
>> json_serialize_string(json->string, ds);
>> break;
>>
>> + case JSON_SERIALIZED_OBJECT:
>> + ds_put_cstr(ds, json->string);
>> + break;
>> +
>> case JSON_N_TYPES:
>> default:
>> OVS_NOT_REACHED();
>> --
>> 2.31.1
>>
>
> Thanks Ilya. Shall we add some test cases for the JSON_SERIALIZD_OBJECT in tests/json.at <http://json.at>?
Having specialized unit tests is a good thing, you're right.
For now the functionality is covered by ovsdb tests, since it's used
in ovsdb monitor and raft communication, so it's not a big concern
that we don't have specialized unit tests.
I'll think about how to write them though. It's a bit tricky since
serialized object is not a real JSON object, so we can't re-use existing
test code. Added to my to-do list.
>
> Acked-by: Han Zhou <hzhou at ovn.org <mailto:hzhou at ovn.org>>
More information about the dev
mailing list