[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