Skip to content

Commit

Permalink
json: Store short strings in-place.
Browse files Browse the repository at this point in the history
Signed-off-by: Ilya Maximets <[email protected]>
  • Loading branch information
igsilya committed Aug 12, 2024
1 parent 82ed9ef commit e21abfc
Show file tree
Hide file tree
Showing 24 changed files with 121 additions and 63 deletions.
14 changes: 13 additions & 1 deletion include/openvswitch/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
};
};
};

Expand Down
8 changes: 5 additions & 3 deletions lib/db-ctl-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,17 @@ 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->s->string, record_id)) {
const char *name_str = json_string(name->s);

if (!strcmp(name_str, record_id)) {
return true;
}

struct uuid uuid;
size_t len = strlen(record_id);
if (len >= 4
&& uuid_from_string(&uuid, name->s->string)
&& !strncmp(name->s->string, record_id, len)) {
&& uuid_from_string(&uuid, name_str)
&& !strncmp(name_str, record_id, len)) {
return true;
}

Expand Down
52 changes: 38 additions & 14 deletions lib/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,29 +179,41 @@ 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_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;
}

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;
}

Expand Down Expand Up @@ -346,14 +358,16 @@ 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;
ovs_assert(json->storage_type == JSON_STRING_DYNAMIC);
return json->str_ptr;
}

struct json_array *
Expand Down Expand Up @@ -408,8 +422,13 @@ json_destroy__(struct json *json, bool yield)
break;

case 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:
Expand Down Expand Up @@ -482,7 +501,7 @@ json_deep_clone(const struct json *json)
return json_deep_clone_array(&json->array);

case JSON_STRING:
return json_string_create(json->string);
return json_string_create(json_string(json));

case JSON_SERIALIZED_OBJECT:
return json_serialized_object_create(json);
Expand Down Expand Up @@ -577,8 +596,10 @@ json_hash(const struct json *json, size_t basis)
return json_hash_array(&json->array, basis);

case JSON_STRING:
return hash_string(json_string(json), basis);

case JSON_SERIALIZED_OBJECT:
return hash_string(json->string, basis);
return hash_string(json->str_ptr, basis);

case JSON_NULL:
case JSON_FALSE:
Expand Down Expand Up @@ -653,8 +674,10 @@ json_equal(const struct json *a, const struct json *b)
return json_equal_array(&a->array, &b->array);

case JSON_STRING:
return !strcmp(json_string(a), json_string(b));

case JSON_SERIALIZED_OBJECT:
return !strcmp(a->string, b->string);
return !strcmp(a->str_ptr, b->str_ptr);

case JSON_NULL:
case JSON_FALSE:
Expand Down Expand Up @@ -989,7 +1012,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);
}
Expand Down Expand Up @@ -1053,7 +1077,7 @@ struct json *
json_from_serialized_object(const struct json *json)
{
ovs_assert(json->type == JSON_SERIALIZED_OBJECT);
return json_from_string(json->string);
return json_from_string(json->str_ptr);
}

/* Reads the file named 'file_name', parses its contents as a JSON object or
Expand Down Expand Up @@ -1645,11 +1669,11 @@ json_serialize(const struct json *json, struct json_serializer *s)
break;

case JSON_STRING:
json_serialize_string(json->string, ds);
json_serialize_string(json_string(json), ds);
break;

case JSON_SERIALIZED_OBJECT:
ds_put_cstr(ds, json->string);
ds_put_cstr(ds, json->str_ptr);
break;

case JSON_N_TYPES:
Expand Down
4 changes: 2 additions & 2 deletions lib/jsonrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ jsonrpc_msg_from_json(struct json *json, struct jsonrpc_msg **msgp)
}

msg = xzalloc(sizeof *msg);
msg->method = method ? xstrdup(method->string) : NULL;
msg->method = method ? xstrdup(json_string(method)) : NULL;
msg->params = null_from_json_null(shash_find_and_delete(object, "params"));
msg->result = null_from_json_null(shash_find_and_delete(object, "result"));
msg->error = null_from_json_null(shash_find_and_delete(object, "error"));
Expand Down Expand Up @@ -1195,7 +1195,7 @@ jsonrpc_session_recv(struct jsonrpc_session *s)
jsonrpc_session_send(s, reply);
} else if (msg->type == JSONRPC_REPLY
&& msg->id && msg->id->type == JSON_STRING
&& !strcmp(msg->id->string, "echo")) {
&& !strcmp(json_string(msg->id), "echo")) {
/* It's a reply to our echo request. Suppress it. */
} else {
return msg;
Expand Down
2 changes: 1 addition & 1 deletion lib/ovsdb-cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,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].s->string : default_value;
return d->n == 1 ? json_string(d->keys[0].s) : default_value;
}

static bool
Expand Down
4 changes: 2 additions & 2 deletions lib/ovsdb-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ unwrap_json(const struct json *json, const char *name,
if (json->type != JSON_ARRAY
|| json->array.n != 2
|| json->array.elems[0]->type != JSON_STRING
|| (name && strcmp(json->array.elems[0]->string, name))
|| (name && strcmp(json_string(json->array.elems[0]), name))
|| json->array.elems[1]->type != value_type)
{
*value = NULL;
Expand Down Expand Up @@ -1279,7 +1279,7 @@ ovsdb_datum_from_json__(struct ovsdb_datum *datum,
|| (json->type == JSON_ARRAY
&& json->array.n > 0
&& json->array.elems[0]->type == JSON_STRING
&& !strcmp(json->array.elems[0]->string, "set"))) {
&& !strcmp(json_string(json->array.elems[0]), "set"))) {
bool is_map = ovsdb_type_is_map(type);
const char *class = is_map ? "map" : "set";
const struct json *inner;
Expand Down
16 changes: 9 additions & 7 deletions lib/ovsdb-idl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2864,8 +2864,8 @@ substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)
if (json->array.n == 2
&& json->array.elems[0]->type == JSON_STRING
&& json->array.elems[1]->type == JSON_STRING
&& !strcmp(json->array.elems[0]->string, "uuid")
&& uuid_from_string(&uuid, json->array.elems[1]->string)) {
&& !strcmp(json_string(json->array.elems[0]), "uuid")
&& uuid_from_string(&uuid, json_string(json->array.elems[1]))) {
const struct ovsdb_idl_row *row;

row = ovsdb_idl_txn_get_row(txn, &uuid);
Expand Down Expand Up @@ -4036,18 +4036,20 @@ ovsdb_idl_txn_process_reply(struct ovsdb_idl *idl,
error = shash_find_data(json_object(op), "error");
if (error) {
if (error->type == JSON_STRING) {
if (!strcmp(error->string, "timed out")) {
const char *error_string = json_string(error);

if (!strcmp(error_string, "timed out")) {
soft_errors++;
} else if (!strcmp(error->string,
} else if (!strcmp(error_string,
"unknown database")) {
ovsdb_cs_flag_inconsistency(idl->cs);
soft_errors++;
} else if (!strcmp(error->string, "not owner")) {
} else if (!strcmp(error_string, "not owner")) {
lock_errors++;
} else if (!strcmp(error->string, "not allowed")) {
} else if (!strcmp(error_string, "not allowed")) {
hard_errors++;
ovsdb_idl_txn_set_error_json(txn, op);
} else if (strcmp(error->string, "aborted")) {
} else if (strcmp(error_string, "aborted")) {
hard_errors++;
ovsdb_idl_txn_set_error_json(txn, op);
VLOG_WARN_RL(&other_rl,
Expand Down
2 changes: 1 addition & 1 deletion lib/ovsdb-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ ovsdb_parser_member(struct ovsdb_parser *parser, const char *name,
if (((int) value->type >= 0 && value->type < JSON_N_TYPES
&& types & (1u << value->type))
|| (types & OP_ID && value->type == JSON_STRING
&& ovsdb_parser_is_id(value->string)))
&& ovsdb_parser_is_id(json_string(value))))
{
sset_add(&parser->used, name);
return value;
Expand Down
4 changes: 2 additions & 2 deletions lib/ovsdb-types.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ ovsdb_base_type_from_json(struct ovsdb_base_type *base,
if (refTable) {
const struct json *refType;

base->uuid.refTableName = xstrdup(refTable->string);
base->uuid.refTableName = xstrdup(json_string(refTable));

/* We can't set base->uuid.refTable here because we don't have
* enough context (we might not even be running in ovsdb-server).
Expand Down Expand Up @@ -717,7 +717,7 @@ ovsdb_type_from_json(struct ovsdb_type *type, const struct json *json)
}

if (max && max->type == JSON_STRING
&& !strcmp(max->string, "unlimited")) {
&& !strcmp(json_string(max), "unlimited")) {
type->n_max = UINT_MAX;
} else {
error = n_from_json(max, &type->n_max);
Expand Down
2 changes: 1 addition & 1 deletion ovsdb/column.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ ovsdb_column_set_from_json(const struct json *json,
goto error;
}

s = json->array.elems[i]->string;
s = json_string(json->array.elems[i]);
column = shash_find_data(&schema->columns, s);
if (!column) {
error = ovsdb_syntax_error(json, NULL, "%s is not a valid "
Expand Down
2 changes: 1 addition & 1 deletion ovsdb/execution.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ ovsdb_execute_compose(struct ovsdb *db, const struct ovsdb_session *session,
if (params->type != JSON_ARRAY
|| !params->array.n
|| params->array.elems[0]->type != JSON_STRING
|| strcmp(params->array.elems[0]->string, db->schema->name)) {
|| strcmp(json_string(params->array.elems[0]), db->schema->name)) {
if (params->type != JSON_ARRAY) {
error = ovsdb_syntax_error(params, NULL, "array expected");
} else {
Expand Down
6 changes: 3 additions & 3 deletions ovsdb/jsonrpc-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ ovsdb_jsonrpc_lookup_db(const struct ovsdb_jsonrpc_session *s,
goto error;
}

db_name = params->elems[0]->string;
db_name = json_string(params->elems[0]);
db = shash_find_data(&s->up.server->dbs, db_name);
if (!db) {
error = ovsdb_syntax_error(
Expand Down Expand Up @@ -1448,7 +1448,7 @@ ovsdb_jsonrpc_parse_monitor_request(
"array of column names expected");
}

s = columns->array.elems[i]->string;
s = json_string(columns->array.elems[i]);
column = shash_find_data(&table->schema->columns, s);
if (!column) {
return ovsdb_syntax_error(columns, NULL, "%s is not a valid "
Expand Down Expand Up @@ -1591,7 +1591,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
goto error;
}
struct uuid txn_uuid;
if (!uuid_from_string(&txn_uuid, last_id->string)) {
if (!uuid_from_string(&txn_uuid, json_string(last_id))) {
error = ovsdb_syntax_error(last_id, NULL,
"last-txn-id must be UUID format.");
goto error;
Expand Down
2 changes: 1 addition & 1 deletion ovsdb/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ ovsdb_log_read(struct ovsdb_log *file, struct json **jsonp)
"offset %lld are not valid JSON (%s)",
file->display_name, data_length,
(long long int) data_offset,
json->string);
json_string(json));
goto error;
}
if (json->type != JSON_OBJECT) {
Expand Down
4 changes: 2 additions & 2 deletions ovsdb/ovsdb-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ parse_json(const char *s)
{
struct json *json = json_from_string(s);
if (json->type == JSON_STRING) {
ovs_fatal(0, "\"%s\": %s", s, json->string);
ovs_fatal(0, "\"%s\": %s", s, json_string(json));
}
return json;
}
Expand Down Expand Up @@ -596,7 +596,7 @@ fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
if (name->type != JSON_STRING) {
ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i);
}
svec_add(dbs, name->string);
svec_add(dbs, json_string(name));
}
jsonrpc_msg_destroy(reply);
svec_sort(dbs);
Expand Down
Loading

0 comments on commit e21abfc

Please sign in to comment.