diff --git a/include/openvswitch/json.h b/include/openvswitch/json.h index fbdb3523362..5f9b833d65d 100644 --- a/include/openvswitch/json.h +++ b/include/openvswitch/json.h @@ -31,7 +31,6 @@ */ #include -#include "openvswitch/shash.h" #include "openvswitch/util.h" #ifdef __cplusplus @@ -40,6 +39,7 @@ extern "C" { struct ds; struct uuid; +struct jsmap; /* Type of a JSON value. */ enum json_type { @@ -88,7 +88,7 @@ struct json { enum json_storage_type storage_type; size_t count; union { - struct shash *object; /* Contains "struct json *"s. */ + struct jsmap *object; /* Contains "struct json *"s. */ union { struct json *elements[JSON_ARRAY_INLINE_LEN]; struct json_array array; @@ -129,12 +129,14 @@ void json_object_put_string(struct json *, void json_object_put_format(struct json *, const char *name, const char *format, ...) OVS_PRINTF_FORMAT(3, 4); +struct json *json_object_find(const struct json *json, const char *); +struct json *json_object_find_and_delete(struct json *json, const char *); const char *json_string(const struct json *); const char *json_serialized_object(const struct json *); size_t json_array_size(const struct json *); const struct json *json_array_at(const struct json *, size_t index); -struct shash *json_object(const struct json *); +struct jsmap *json_object(const struct json *); bool json_boolean(const struct json *); double json_real(const struct json *); int64_t json_integer(const struct json *); diff --git a/lib/json.c b/lib/json.c index bbf3055cb37..76cdc7b4d35 100644 --- a/lib/json.c +++ b/lib/json.c @@ -25,10 +25,10 @@ #include #include "cooperative-multitasking.h" -#include "openvswitch/dynamic-string.h" #include "hash.h" #include "json.h" -#include "openvswitch/shash.h" +#include "openvswitch/dynamic-string.h" +#include "openvswitch/jsmap.h" #include "unicode.h" #include "util.h" #include "uuid.h" @@ -390,7 +390,7 @@ json_object_create(void) { struct json *json = json_create(JSON_OBJECT); json->object = xmalloc(sizeof *json->object); - shash_init(json->object); + jsmap_init(json->object); return json; } @@ -413,13 +413,21 @@ json_real_create(double real) void json_object_put(struct json *json, const char *name, struct json *value) { - json_destroy(shash_replace(json->object, name, value)); + struct json *key = json_string_create(name); + + jsmap_replace(json->object, key, value, false); + json_destroy(key); + json_destroy(value); } void json_object_put_nocopy(struct json *json, char *name, struct json *value) { - json_destroy(shash_replace_nocopy(json->object, name, value)); + struct json *key = json_string_create_nocopy(name); + + jsmap_replace(json->object, key, value, false); + json_destroy(key); + json_destroy(value); } void @@ -439,6 +447,26 @@ json_object_put_format(struct json *json, va_end(args); } +struct json * +json_object_find(const struct json *json, const char *name) +{ + struct json *key = json_string_create(name); + struct jsmap_node *node = jsmap_get_node(json->object, key); + + json_destroy(key); + return node ? node->value : NULL; +} + +struct json * +json_object_find_and_delete(struct json *json, const char *name) +{ + struct json *key = json_string_create(name); + struct json *value = jsmap_find_and_delete(json->object, key); + + json_destroy(key); + return value; +} + const char * json_string(const struct json *json) { @@ -483,11 +511,11 @@ json_array_at(const struct json *json, size_t index) return json->elements[index]; } -struct shash * +struct jsmap * json_object(const struct json *json) { ovs_assert(json->type == JSON_OBJECT); - return CONST_CAST(struct shash *, json->object); + return CONST_CAST(struct jsmap *, json->object); } bool @@ -511,7 +539,7 @@ json_integer(const struct json *json) return json->integer; } -static void json_destroy_object(struct shash *object, bool yield); +static void json_destroy_object(struct jsmap *object, bool yield); static void json_destroy_array(struct json *json, bool yield); /* Frees 'json' and everything it points to, recursively. */ @@ -551,25 +579,12 @@ json_destroy__(struct json *json, bool yield) } static void -json_destroy_object(struct shash *object, bool yield) +json_destroy_object(struct jsmap *object, bool yield) { - struct shash_node *node; - if (yield) { cooperative_multitasking_yield(); } - - SHASH_FOR_EACH_SAFE (node, object) { - struct json *value = node->data; - - if (yield) { - json_destroy_with_yield(value); - } else { - json_destroy(value); - } - shash_delete(object, node); - } - shash_destroy(object); + jsmap_destroy(object, yield); free(object); } @@ -595,7 +610,7 @@ json_destroy_array(struct json *json, bool yield) } } -static struct json *json_deep_clone_object(const struct shash *object); +static struct json *json_deep_clone_object(const struct jsmap *object); static struct json *json_deep_clone_array(const struct json *); /* Returns a deep copy of 'json'. */ @@ -639,16 +654,11 @@ json_nullable_clone(const struct json *json) } static struct json * -json_deep_clone_object(const struct shash *object) +json_deep_clone_object(const struct jsmap *object) { - struct shash_node *node; - struct json *json; + struct json *json = json_object_create(); - json = json_object_create(); - SHASH_FOR_EACH (node, object) { - struct json *value = node->data; - json_object_put(json, node->name, json_deep_clone(value)); - } + jsmap_clone(json->object, object, true); return json; } @@ -683,17 +693,18 @@ json_deep_clone_array(const struct json *json) } static size_t -json_hash_object(const struct shash *object, size_t basis) +json_hash_object(const struct jsmap *object, size_t basis) { - const struct shash_node **nodes; + const struct jsmap_node **nodes; size_t n, i; - nodes = shash_sort(object); - n = shash_count(object); + nodes = jsmap_sort(object); + n = jsmap_count(object); for (i = 0; i < n; i++) { - const struct shash_node *node = nodes[i]; - basis = hash_string(node->name, basis); - basis = json_hash(node->data, basis); + const struct jsmap_node *node = nodes[i]; + + basis = json_hash(node->key, basis); + basis = json_hash(node->value, basis); } free(nodes); return basis; @@ -744,25 +755,6 @@ json_hash(const struct json *json, size_t basis) } } -static bool -json_equal_object(const struct shash *a, const struct shash *b) -{ - struct shash_node *a_node; - - if (shash_count(a) != shash_count(b)) { - return false; - } - - SHASH_FOR_EACH (a_node, a) { - struct shash_node *b_node = shash_find(b, a_node->name); - if (!b_node || !json_equal(a_node->data, b_node->data)) { - return false; - } - } - - return true; -} - static bool json_equal_array(const struct json *a, const struct json *b) { @@ -794,7 +786,7 @@ json_equal(const struct json *a, const struct json *b) switch (a->type) { case JSON_OBJECT: - return json_equal_object(a->object, b->object); + return jsmap_equal(a->object, b->object); case JSON_ARRAY: return json_equal_array(a, b); @@ -1718,7 +1710,7 @@ struct json_serializer { }; static void json_serialize(const struct json *, struct json_serializer *); -static void json_serialize_object(const struct shash *object, +static void json_serialize_object(const struct jsmap *object, struct json_serializer *); static void json_serialize_array(const struct json *, struct json_serializer *); @@ -1818,7 +1810,7 @@ indent_line(struct json_serializer *s) } static void -json_serialize_object_member(size_t i, const struct shash_node *node, +json_serialize_object_member(size_t i, const struct jsmap_node *node, struct json_serializer *s) { struct ds *ds = s->ds; @@ -1828,16 +1820,16 @@ json_serialize_object_member(size_t i, const struct shash_node *node, indent_line(s); } - json_serialize_string(node->name, ds); + json_serialize(node->key, s); ds_put_char(ds, ':'); if (s->flags & JSSF_PRETTY) { ds_put_char(ds, ' '); } - json_serialize(node->data, s); + json_serialize(node->value, s); } static void -json_serialize_object(const struct shash *object, struct json_serializer *s) +json_serialize_object(const struct jsmap *object, struct json_serializer *s) { struct ds *ds = s->ds; @@ -1851,21 +1843,21 @@ json_serialize_object(const struct shash *object, struct json_serializer *s) } if (s->flags & JSSF_SORT) { - const struct shash_node **nodes; + const struct jsmap_node **nodes; size_t n, i; - nodes = shash_sort(object); - n = shash_count(object); + nodes = jsmap_sort(object); + n = jsmap_count(object); for (i = 0; i < n; i++) { json_serialize_object_member(i, nodes[i], s); } free(nodes); } else { - struct shash_node *node; + struct jsmap_node *node; size_t i; i = 0; - SHASH_FOR_EACH (node, object) { + JSMAP_FOR_EACH (node, object) { json_serialize_object_member(i++, node, s); } } diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c index d5fa7b45b13..fe275add669 100644 --- a/lib/jsonrpc.c +++ b/lib/jsonrpc.c @@ -23,6 +23,7 @@ #include "byteq.h" #include "openvswitch/dynamic-string.h" #include "fatal-signal.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "openvswitch/list.h" #include "openvswitch/ofpbuf.h" @@ -713,16 +714,14 @@ jsonrpc_msg_from_json(struct json *json, struct jsonrpc_msg **msgp) { struct json *method = NULL; struct jsonrpc_msg *msg = NULL; - struct shash *object; char *error; if (json->type != JSON_OBJECT) { error = xstrdup("message is not a JSON object"); goto exit; } - object = json_object(json); - method = shash_find_and_delete(object, "method"); + method = json_object_find_and_delete(json, "method"); if (method && method->type != JSON_STRING) { error = xstrdup("method is not a JSON string"); goto exit; @@ -730,17 +729,21 @@ jsonrpc_msg_from_json(struct json *json, struct jsonrpc_msg **msgp) msg = xzalloc(sizeof *msg); 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")); - msg->id = null_from_json_null(shash_find_and_delete(object, "id")); + msg->params = null_from_json_null( + json_object_find_and_delete(json, "params")); + msg->result = null_from_json_null( + json_object_find_and_delete(json, "result")); + msg->error = null_from_json_null( + json_object_find_and_delete(json, "error")); + msg->id = null_from_json_null( + json_object_find_and_delete(json, "id")); msg->type = (msg->result ? JSONRPC_REPLY : msg->error ? JSONRPC_ERROR : msg->id ? JSONRPC_REQUEST : JSONRPC_NOTIFY); - if (!shash_is_empty(object)) { + if (!jsmap_is_empty(json_object(json))) { error = xasprintf("message has unexpected member \"%s\"", - shash_first(object)->name); + json_string(jsmap_first(json_object(json))->key)); goto exit; } error = jsonrpc_msg_is_valid(msg); diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c index facad3793b8..57a06fa686c 100644 --- a/lib/ovsdb-cs.c +++ b/lib/ovsdb-cs.c @@ -24,6 +24,7 @@ #include "jsonrpc.h" #include "openvswitch/dynamic-string.h" #include "openvswitch/hmap.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "openvswitch/poll-loop.h" #include "openvswitch/shash.h" @@ -1370,7 +1371,7 @@ ovsdb_cs_db_parse_lock_reply(struct ovsdb_cs_db *db, if (result->type == JSON_OBJECT) { const struct json *locked; - locked = shash_find_data(json_object(result), "locked"); + locked = json_object_find(result, "locked"); got_lock = locked && locked->type == JSON_TRUE; } else { got_lock = false; @@ -1516,8 +1517,8 @@ ovsdb_cs_send_monitor_request(struct ovsdb_cs *cs, struct ovsdb_cs_db *db, struct ovsdb_cs_db_table *table; HMAP_FOR_EACH (table, hmap_node, &db->tables) { if (table->ack_cond) { - struct json *mr = shash_find_data(json_object(mrs), - table->name); + struct json *mr = json_object_find(mrs, table->name); + if (!mr) { mr = json_array_create_empty(); json_object_put(mrs, table->name, mr); @@ -1782,15 +1783,14 @@ ovsdb_cs_insert_server_row(struct ovsdb_cs *cs, const struct uuid *uuid) static void ovsdb_cs_update_server_row(struct server_row *row, - const struct shash *update, bool xor) + const struct json *update, bool xor) { for (size_t i = 0; i < N_SERVER_COLUMNS; i++) { const struct server_column *column = &server_columns[i]; - struct shash_node *node = shash_find(update, column->name); - if (!node) { + const struct json *json = json_object_find(update, column->name); + if (!json) { continue; } - const struct json *json = node->data; struct ovsdb_datum *old = &row->data[i]; struct ovsdb_datum new; @@ -2115,7 +2115,7 @@ ovsdb_cs_parse_schema(const struct json *schema_json) struct ovsdb_parser parser; const struct json *tables_json; struct ovsdb_error *error; - struct shash_node *node; + struct jsmap_node *node; struct shash *schema; ovsdb_parser_init(&parser, schema_json, "database schema"); @@ -2128,9 +2128,9 @@ ovsdb_cs_parse_schema(const struct json *schema_json) schema = xmalloc(sizeof *schema); shash_init(schema); - SHASH_FOR_EACH (node, json_object(tables_json)) { - const char *table_name = node->name; - const struct json *json = node->data; + JSMAP_FOR_EACH (node, json_object(tables_json)) { + const char *table_name = json_string(node->key); + const struct json *json = node->value; const struct json *columns_json; ovsdb_parser_init(&parser, json, "table schema for table %s", @@ -2146,9 +2146,9 @@ ovsdb_cs_parse_schema(const struct json *schema_json) struct sset *columns = xmalloc(sizeof *columns); sset_init(columns); - struct shash_node *node2; - SHASH_FOR_EACH (node2, json_object(columns_json)) { - const char *column_name = node2->name; + struct jsmap_node *node2; + JSMAP_FOR_EACH (node2, json_object(columns_json)) { + const char *column_name = json_string(node2->key); sset_add(columns, column_name); } shash_add(schema, table_name, columns); @@ -2181,8 +2181,8 @@ ovsdb_cs_parse_row_update1(const struct json *in, { const struct json *old_json, *new_json; - old_json = shash_find_data(json_object(in), "old"); - new_json = shash_find_data(json_object(in), "new"); + old_json = json_object_find(in, "old"); + new_json = json_object_find(in, "new"); if (old_json && old_json->type != JSON_OBJECT) { return ovsdb_syntax_error(old_json, NULL, "\"old\" is not object"); @@ -2190,7 +2190,7 @@ ovsdb_cs_parse_row_update1(const struct json *in, return ovsdb_syntax_error(new_json, NULL, "\"new\" is not object"); } else if ((old_json != NULL) + (new_json != NULL) - != shash_count(json_object(in))) { + != jsmap_count(json_object(in))) { return ovsdb_syntax_error(in, NULL, " contains " "unexpected member"); @@ -2202,13 +2202,13 @@ ovsdb_cs_parse_row_update1(const struct json *in, if (!new_json) { out->type = OVSDB_CS_ROW_DELETE; - out->columns = json_object(old_json); + out->columns = old_json; } else if (!old_json) { out->type = OVSDB_CS_ROW_INSERT; - out->columns = json_object(new_json); + out->columns = new_json; } else { out->type = OVSDB_CS_ROW_UPDATE; - out->columns = json_object(new_json); + out->columns = new_json; } return NULL; } @@ -2217,20 +2217,22 @@ static struct ovsdb_error * OVS_WARN_UNUSED_RESULT ovsdb_cs_parse_row_update2(const struct json *in, struct ovsdb_cs_row_update *out) { - const struct shash *object = json_object(in); - if (shash_count(object) != 1) { + const struct jsmap *object = json_object(in); + if (jsmap_count(object) != 1) { return ovsdb_syntax_error( in, NULL, " has %"PRIuSIZE" members " - "instead of expected 1", shash_count(object)); + "instead of expected 1", jsmap_count(object)); } - struct shash_node *node = shash_first(object); - const struct json *columns = node->data; - if (!strcmp(node->name, "insert") || !strcmp(node->name, "initial")) { + struct jsmap_node *node = jsmap_first(object); + const struct json *columns = node->value; + const char *op = json_string(node->key); + + if (!strcmp(op, "insert") || !strcmp(op, "initial")) { out->type = OVSDB_CS_ROW_INSERT; - } else if (!strcmp(node->name, "modify")) { + } else if (!strcmp(op, "modify")) { out->type = OVSDB_CS_ROW_XOR; - } else if (!strcmp(node->name, "delete")) { + } else if (!strcmp(op, "delete")) { out->type = OVSDB_CS_ROW_DELETE; if (columns->type != JSON_NULL) { return ovsdb_syntax_error( @@ -2241,16 +2243,16 @@ ovsdb_cs_parse_row_update2(const struct json *in, } else { return ovsdb_syntax_error(in, NULL, " has unknown member \"%s\"", - node->name); + op); } if (columns->type != JSON_OBJECT) { return ovsdb_syntax_error( in, NULL, " \"%s\" operation has unexpected value", - node->name); + op); } - out->columns = json_object(columns); + out->columns = columns; return NULL; } @@ -2286,13 +2288,14 @@ ovsdb_cs_parse_table_update(const char *table_name, in, NULL, " for table \"%s\" is not an object", suffix, table_name); } - struct shash *in_rows = json_object(in); + struct jsmap *in_rows = json_object(in); - out->row_updates = xmalloc(shash_count(in_rows) * sizeof *out->row_updates); + out->row_updates = xmalloc( + jsmap_count(in_rows) * sizeof *out->row_updates); - const struct shash_node *node; - SHASH_FOR_EACH (node, in_rows) { - const char *row_uuid_string = node->name; + const struct jsmap_node *node; + JSMAP_FOR_EACH (node, in_rows) { + const char *row_uuid_string = json_string(node->key); struct uuid row_uuid; if (!uuid_from_string(&row_uuid, row_uuid_string)) { return ovsdb_syntax_error( @@ -2302,7 +2305,7 @@ ovsdb_cs_parse_table_update(const char *table_name, suffix, table_name, row_uuid_string); } - const struct json *in_ru = node->data; + const struct json *in_ru = node->value; struct ovsdb_cs_row_update *out_ru = &out->row_updates[out->n++]; *out_ru = (struct ovsdb_cs_row_update) { .row_uuid = row_uuid }; @@ -2338,12 +2341,12 @@ ovsdb_cs_parse_db_update(const struct json *in, int version, } struct ovsdb_cs_db_update *out = xzalloc(sizeof *out); - out->table_updates = xmalloc(shash_count(json_object(in)) + out->table_updates = xmalloc(jsmap_count(json_object(in)) * sizeof *out->table_updates); - const struct shash_node *node; - SHASH_FOR_EACH (node, json_object(in)) { - const char *table_name = node->name; - const struct json *in_tu = node->data; + const struct jsmap_node *node; + JSMAP_FOR_EACH (node, json_object(in)) { + const char *table_name = json_string(node->key); + const struct json *in_tu = node->value; struct ovsdb_cs_table_update *out_tu = &out->table_updates[out->n++]; *out_tu = (struct ovsdb_cs_table_update) { .table_name = table_name }; diff --git a/lib/ovsdb-cs.h b/lib/ovsdb-cs.h index bcc3dcd7167..ba25d39e830 100644 --- a/lib/ovsdb-cs.h +++ b/lib/ovsdb-cs.h @@ -181,7 +181,7 @@ enum ovsdb_cs_row_update_type { struct ovsdb_cs_row_update { struct uuid row_uuid; /* Row's _uuid. */ enum ovsdb_cs_row_update_type type; /* Type of change. */ - const struct shash *columns; /* Map from column name to json data. */ + const struct json *columns; /* Map (object) from column name to data. */ }; /* Partially parsed or . */ diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c index 7c4ad2581c2..2007b8444c0 100644 --- a/lib/ovsdb-idl.c +++ b/lib/ovsdb-idl.c @@ -39,6 +39,7 @@ #include "ovsdb-parser.h" #include "ovsdb-server-idl.h" #include "ovsdb-session.h" +#include "openvswitch/jsmap.h" #include "openvswitch/poll-loop.h" #include "openvswitch/shash.h" #include "skiplist.h" @@ -145,10 +146,10 @@ static void ovsdb_idl_clear(struct ovsdb_idl *); static enum update_result ovsdb_idl_process_update( struct ovsdb_idl_table *, const struct ovsdb_cs_row_update *); static void ovsdb_idl_insert_row(struct ovsdb_idl_row *, - const struct shash *values); + const struct json *values); static void ovsdb_idl_delete_row(struct ovsdb_idl_row *); static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *, - const struct shash *values, bool xor); + const struct json *values, bool xor); static void ovsdb_idl_parse_update(struct ovsdb_idl *, const struct ovsdb_cs_update_event *); static void ovsdb_idl_reparse_deleted(struct ovsdb_idl *); @@ -1699,16 +1700,16 @@ add_tracked_change_for_references(struct ovsdb_idl_row *row) * Caller needs to provide either valid 'row_json' or 'diff', but not * both. */ static bool -ovsdb_idl_row_change(struct ovsdb_idl_row *row, const struct shash *values, +ovsdb_idl_row_change(struct ovsdb_idl_row *row, const struct json *values, bool xor, enum ovsdb_idl_change change) { struct ovsdb_idl_table *table = row->table; const struct ovsdb_idl_table_class *class = table->class_; - struct shash_node *node; + struct jsmap_node *node; bool changed = false; - SHASH_FOR_EACH (node, values) { - const char *column_name = node->name; + JSMAP_FOR_EACH (node, json_object(values)) { + const char *column_name = json_string(node->key); const struct ovsdb_idl_column *column; struct ovsdb_error *error; unsigned int column_idx; @@ -1729,7 +1730,7 @@ ovsdb_idl_row_change(struct ovsdb_idl_row *row, const struct shash *values, struct ovsdb_datum diff; error = ovsdb_transient_datum_from_json(&diff, &column->type, - node->data); + node->value); if (!error) { error = ovsdb_datum_apply_diff_in_place(old, &diff, &column->type); @@ -1739,7 +1740,7 @@ ovsdb_idl_row_change(struct ovsdb_idl_row *row, const struct shash *values, } else { struct ovsdb_datum datum; - error = ovsdb_datum_from_json(&datum, &column->type, node->data, + error = ovsdb_datum_from_json(&datum, &column->type, node->value, NULL); if (!error) { if (!ovsdb_datum_equals(old, &datum, &column->type)) { @@ -2412,7 +2413,7 @@ ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl *idl) } static void -ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct shash *data) +ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *data) { const struct ovsdb_idl_table_class *class = row->table->class_; size_t i, datum_size; @@ -2448,7 +2449,7 @@ ovsdb_idl_delete_row(struct ovsdb_idl_row *row) /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false * otherwise. */ static bool -ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct shash *values, +ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *values, bool xor) { ovsdb_idl_remove_from_indexes(row); @@ -2890,10 +2891,10 @@ substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn) CONST_CAST(struct json *, json_array_at(json, i)), txn)); } } else if (json->type == JSON_OBJECT) { - struct shash_node *node; + struct jsmap_node *node; - SHASH_FOR_EACH (node, json_object(json)) { - node->data = substitute_uuids(node->data, txn); + JSMAP_FOR_EACH (node, json_object(json)) { + node->value = substitute_uuids(node->value, txn); } } return json; @@ -3359,7 +3360,7 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn) } } - if (!row->old_datum || !shash_is_empty(json_object(row_json))) { + if (!row->old_datum || !jsmap_is_empty(json_object(row_json))) { json_array_add(operations, op); } else { json_destroy(op); @@ -3910,7 +3911,7 @@ ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn, const struct json *results) { const struct json *count, *rows, *row, *column; - struct shash *mutate, *select; + const struct json *mutate, *select; if (txn->inc_index + 2 > json_array_size(results)) { VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations " @@ -3921,8 +3922,8 @@ ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn, /* We know that this is a JSON object because the loop in * ovsdb_idl_txn_process_reply() checked. */ - mutate = json_object(json_array_at(results, txn->inc_index)); - count = shash_find_data(mutate, "count"); + mutate = json_array_at(results, txn->inc_index); + count = json_object_find(mutate, "count"); if (!check_json_type(count, JSON_INTEGER, "\"mutate\" reply \"count\"")) { return false; } @@ -3933,8 +3934,8 @@ ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn, return false; } - select = json_object(json_array_at(results, txn->inc_index + 1)); - rows = shash_find_data(select, "rows"); + select = json_array_at(results, txn->inc_index + 1); + rows = json_object_find(select, "rows"); if (!check_json_type(rows, JSON_ARRAY, "\"select\" reply \"rows\"")) { return false; } @@ -3948,7 +3949,7 @@ ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn, if (!check_json_type(row, JSON_OBJECT, "\"select\" reply row")) { return false; } - column = shash_find_data(json_object(row), txn->inc_column); + column = json_object_find(row, txn->inc_column); if (!check_json_type(column, JSON_INTEGER, "\"select\" reply inc column")) { return false; @@ -3963,9 +3964,9 @@ ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert, { static const struct ovsdb_base_type uuid_type = OVSDB_BASE_UUID_INIT; struct ovsdb_error *error; + const struct json *reply; struct json *json_uuid; union ovsdb_atom uuid; - struct shash *reply; if (insert->op_index >= json_array_size(results)) { VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations " @@ -3976,8 +3977,8 @@ ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert, /* We know that this is a JSON object because the loop in * ovsdb_idl_txn_process_reply() checked. */ - reply = json_object(json_array_at(results, insert->op_index)); - json_uuid = shash_find_data(reply, "uuid"); + reply = json_array_at(results, insert->op_index); + json_uuid = json_object_find(reply, "uuid"); if (!check_json_type(json_uuid, JSON_ARRAY, "\"insert\" reply \"uuid\"")) { return false; } @@ -4038,9 +4039,9 @@ ovsdb_idl_txn_process_reply(struct ovsdb_idl *idl, * operation failed, so make sure that we know about it. */ soft_errors++; } else if (op->type == JSON_OBJECT) { - struct json *error; + const struct json *error; - error = shash_find_data(json_object(op), "error"); + error = json_object_find(op, "error"); if (error) { if (error->type == JSON_STRING) { const char *error_string = json_string(error); diff --git a/lib/ovsdb-parser.c b/lib/ovsdb-parser.c index 07a6707811b..ac800b22b85 100644 --- a/lib/ovsdb-parser.c +++ b/lib/ovsdb-parser.c @@ -20,6 +20,7 @@ #include #include +#include "openvswitch/jsmap.h" #include "ovsdb-error.h" void @@ -71,7 +72,7 @@ ovsdb_parser_member(struct ovsdb_parser *parser, const char *name, return NULL; } - value = shash_find_data(json_object(parser->json), name); + value = json_object_find(parser->json, name); if (!value) { if (!(types & OP_OPTIONAL)) { ovsdb_parser_raise_error(parser, @@ -151,26 +152,28 @@ struct ovsdb_error * ovsdb_parser_finish(struct ovsdb_parser *parser) { if (!parser->error) { - const struct shash *object = json_object(parser->json); + const struct jsmap *object = json_object(parser->json); size_t n_unused; - n_unused = shash_count(object) - sset_count(&parser->used); + n_unused = jsmap_count(object) - sset_count(&parser->used); if (n_unused) { - struct shash_node *node; + struct jsmap_node *node; - SHASH_FOR_EACH (node, object) { - if (!sset_contains(&parser->used, node->name)) { + JSMAP_FOR_EACH (node, object) { + const char *name = json_string(node->key); + + if (!sset_contains(&parser->used, name)) { if (n_unused > 1) { ovsdb_parser_raise_error( parser, "Member '%s' and %"PRIuSIZE" other member%s " "are present but not allowed here.", - node->name, n_unused - 1, n_unused > 2 ? "s" : ""); + name, n_unused - 1, n_unused > 2 ? "s" : ""); } else { ovsdb_parser_raise_error( parser, "Member '%s' is present but not allowed here.", - node->name); + name); } break; } diff --git a/lib/smap.c b/lib/smap.c index 122adca2717..393f8701156 100644 --- a/lib/smap.c +++ b/lib/smap.c @@ -18,6 +18,7 @@ #include #include "hash.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "packets.h" #include "util.h" @@ -354,11 +355,10 @@ smap_sort(const struct smap *smap) void smap_from_json(struct smap *smap, const struct json *json) { - const struct shash_node *node; + const struct jsmap_node *node; - SHASH_FOR_EACH (node, json_object(json)) { - const struct json *value = node->data; - smap_add(smap, node->name, json_string(value)); + JSMAP_FOR_EACH (node, json_object(json)) { + smap_add(smap, json_string(node->key), json_string(node->value)); } } diff --git a/ovsdb/file.c b/ovsdb/file.c index 66ef87a1f16..b0096fe2143 100644 --- a/ovsdb/file.c +++ b/ovsdb/file.c @@ -25,6 +25,7 @@ #include "column.h" #include "cooperative-multitasking.h" #include "log.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "lockfile.h" #include "ovsdb.h" @@ -87,14 +88,14 @@ ovsdb_file_update_row_from_json(struct ovsdb_row *row, struct ovsdb_row *diff, { struct ovsdb_table_schema *schema = row->table->schema; struct ovsdb_error *error; - struct shash_node *node; + struct jsmap_node *node; if (json->type != JSON_OBJECT) { return ovsdb_syntax_error(json, NULL, "row must be JSON object"); } - SHASH_FOR_EACH (node, json_object(json)) { - const char *column_name = node->name; + JSMAP_FOR_EACH (node, json_object(json)) { + const char *column_name = json_string(node->key); const struct ovsdb_column *column; struct ovsdb_datum datum; @@ -111,10 +112,10 @@ ovsdb_file_update_row_from_json(struct ovsdb_row *row, struct ovsdb_row *diff, if (row_contains_diff) { /* Diff may violate the type size rules. */ error = ovsdb_transient_datum_from_json(&datum, &column->type, - node->data); + node->value); } else { error = ovsdb_datum_from_json(&datum, &column->type, - node->data, NULL); + node->value, NULL); } if (error) { return error; @@ -145,7 +146,8 @@ ovsdb_file_update_row_from_json(struct ovsdb_row *row, struct ovsdb_row *diff, static struct ovsdb_error * ovsdb_file_txn_row_from_json(struct ovsdb_txn *txn, struct ovsdb_table *table, bool converting, bool row_contains_diff, - const struct uuid *row_uuid, struct json *json) + const struct uuid *row_uuid, + const struct json *json) { const struct ovsdb_row *row = ovsdb_table_get_row(table, row_uuid); if (json->type == JSON_NULL) { @@ -185,17 +187,17 @@ ovsdb_file_txn_table_from_json(struct ovsdb_txn *txn, struct ovsdb_table *table, bool converting, bool row_contains_diff, - struct json *json) + const struct json *json) { - struct shash_node *node; + struct jsmap_node *node; if (json->type != JSON_OBJECT) { return ovsdb_syntax_error(json, NULL, "object expected"); } - SHASH_FOR_EACH (node, json->object) { - const char *uuid_string = node->name; - struct json *txn_row_json = node->data; + JSMAP_FOR_EACH (node, json_object(json)) { + const char *uuid_string = json_string(node->key); + const struct json *txn_row_json = node->value; struct ovsdb_error *error; struct uuid row_uuid; @@ -226,7 +228,7 @@ ovsdb_file_txn_from_json(struct ovsdb *db, const struct json *json, bool converting, struct ovsdb_txn **txnp) { struct ovsdb_error *error; - struct shash_node *node; + struct jsmap_node *node; struct ovsdb_txn *txn; *txnp = NULL; @@ -235,7 +237,7 @@ ovsdb_file_txn_from_json(struct ovsdb *db, const struct json *json, return ovsdb_syntax_error(json, NULL, "object expected"); } - struct json *is_diff = shash_find_data(json->object, "_is_diff"); + const struct json *is_diff = json_object_find(json, "_is_diff"); bool row_contains_diff = false; if (is_diff && is_diff->type == JSON_TRUE) { @@ -243,9 +245,9 @@ ovsdb_file_txn_from_json(struct ovsdb *db, const struct json *json, } txn = ovsdb_txn_create(db); - SHASH_FOR_EACH (node, json->object) { - const char *table_name = node->name; - struct json *node_json = node->data; + JSMAP_FOR_EACH (node, json_object(json)) { + const char *table_name = json_string(node->key); + const struct json *node_json = node->value; struct ovsdb_table *table; table = shash_find_data(&db->tables, table_name); diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index a47c2c76cea..f2d878baa2d 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -30,6 +30,7 @@ #include "ovsdb-parser.h" #include "ovsdb.h" #include "condition.h" +#include "openvswitch/jsmap.h" #include "openvswitch/poll-loop.h" #include "reconnect.h" #include "row.h" @@ -1501,7 +1502,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db, struct ovsdb_jsonrpc_monitor *m = NULL; struct ovsdb_monitor *dbmon = NULL; struct ovsdb_error *error = NULL; - struct shash_node *node; + struct jsmap_node *node; struct json *json; if ((version == OVSDB_MONITOR_V2 && json_array_size(params) != 3) || @@ -1533,22 +1534,23 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db, hmap_insert(&s->monitors, &m->node, json_hash(monitor_id, 0)); m->monitor_id = json_clone(monitor_id); - SHASH_FOR_EACH (node, json_object(monitor_requests)) { + JSMAP_FOR_EACH (node, json_object(monitor_requests)) { const struct ovsdb_table *table; const struct json *mr_value; size_t i, n; - table = ovsdb_get_table(m->db, node->name); + table = ovsdb_get_table(m->db, json_string(node->key)); if (!table) { error = ovsdb_syntax_error(NULL, NULL, - "no table named %s", node->name); + "no table named %s", + json_string(node->key)); goto error; } ovsdb_monitor_add_table(m->dbmon, table); /* Parse columns. */ - mr_value = node->data; + mr_value = node->value; if (mr_value->type == JSON_ARRAY) { n = json_array_size(mr_value); for (i = 0; i < n; i++) { @@ -1672,7 +1674,7 @@ ovsdb_jsonrpc_monitor_cond_change(struct ovsdb_jsonrpc_session *s, const struct json *monitor_cond_change_reqs; struct ovsdb_jsonrpc_monitor *m; struct ovsdb_error *error; - struct shash_node *node; + struct jsmap_node *node; if (json_array_size(params) != 3) { error = ovsdb_syntax_error(params, NULL, "invalid parameters"); @@ -1702,25 +1704,26 @@ ovsdb_jsonrpc_monitor_cond_change(struct ovsdb_jsonrpc_session *s, goto error; } - SHASH_FOR_EACH (node, json_object(monitor_cond_change_reqs)) { + JSMAP_FOR_EACH (node, json_object(monitor_cond_change_reqs)) { + const char *table_name = json_string(node->key); const struct ovsdb_table *table; const struct json *mr_value; size_t i, n; - table = ovsdb_get_table(m->db, node->name); + table = ovsdb_get_table(m->db, table_name); if (!table) { error = ovsdb_syntax_error(NULL, NULL, - "no table named %s", node->name); + "no table named %s", table_name); goto error; } if (!ovsdb_monitor_table_exists(m->dbmon, table)) { error = ovsdb_syntax_error(NULL, NULL, "no table named %s in monitor session", - node->name); + table_name); goto error; } - mr_value = node->data; + mr_value = node->value; if (mr_value->type == JSON_ARRAY) { n = json_array_size(mr_value); for (i = 0; i < n; i++) { @@ -1734,7 +1737,7 @@ ovsdb_jsonrpc_monitor_cond_change(struct ovsdb_jsonrpc_session *s, error = ovsdb_syntax_error( NULL, NULL, "table %s no monitor-cond-change JSON array", - node->name); + table_name); goto error; } } diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c index 1639c426af0..d50bfd88cdc 100644 --- a/ovsdb/ovsdb-client.c +++ b/ovsdb/ovsdb-client.c @@ -34,6 +34,7 @@ #include "openvswitch/dynamic-string.h" #include "fatal-signal.h" #include "file.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "jsonrpc.h" #include "lib/table.h" @@ -606,14 +607,14 @@ fetch_dbs(struct jsonrpc *rpc, struct svec *dbs) static const char * parse_string_column(const struct json *row, const char *column_name) { - const struct json *column = shash_find_data(json_object(row), column_name); + const struct json *column = json_object_find(row, column_name); return column && column->type == JSON_STRING ? json_string(column) : ""; } static int parse_boolean_column(const struct json *row, const char *column_name) { - const struct json *column = shash_find_data(json_object(row), column_name); + const struct json *column = json_object_find(row, column_name); return (!column ? -1 : column->type == JSON_TRUE ? true : column->type == JSON_FALSE ? false @@ -623,7 +624,7 @@ parse_boolean_column(const struct json *row, const char *column_name) static struct uuid parse_uuid_column(const struct json *row, const char *column_name) { - const struct json *column = shash_find_data(json_object(row), column_name); + const struct json *column = json_object_find(row, column_name); if (!column) { return UUID_ZERO; } @@ -672,7 +673,7 @@ parse_database_info_reply(const struct jsonrpc_msg *reply, const char *server, } const struct json *op_result = json_array_at(result, 0); - const struct json *rows = shash_find_data(json_object(op_result), "rows"); + const struct json *rows = json_object_find(op_result, "rows"); if (!rows || rows->type != JSON_ARRAY) { VLOG_WARN("%s: missing \"rows\" member in _Server reply for %s", server, database); @@ -927,7 +928,7 @@ do_query(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED, && json_array_size(result) == abort_idx + 1 && json_array_at(result, abort_idx)->type == JSON_OBJECT) { const struct json *op_result = json_array_at(result, abort_idx); - struct json *error = shash_find_data(json_object(op_result), "error"); + struct json *error = json_object_find(op_result, "error"); if (error && error->type == JSON_STRING && !strcmp(json_string(error), "aborted")) { @@ -965,7 +966,7 @@ monitor_print_row(const struct json *row, const char *type, const char *uuid, table_add_cell(t)->text = xstrdup(type); for (i = 0; i < columns->n_columns; i++) { const struct ovsdb_column *column = columns->columns[i]; - struct json *value = shash_find_data(json_object(row), column->name); + struct json *value = json_object_find(row, column->name); struct cell *cell = table_add_cell(t); if (value) { cell->json = json_clone(value); @@ -981,7 +982,7 @@ monitor_print_table(struct json *table_update, { const struct ovsdb_table_schema *table = mt->table; const struct ovsdb_column_set *columns = &mt->columns; - struct shash_node *node; + struct jsmap_node *node; struct table t; size_t i; @@ -999,24 +1000,25 @@ monitor_print_table(struct json *table_update, for (i = 0; i < columns->n_columns; i++) { table_add_column(&t, "%s", columns->columns[i]->name); } - SHASH_FOR_EACH (node, json_object(table_update)) { - struct json *row_update = node->data; + JSMAP_FOR_EACH (node, json_object(table_update)) { + const char *name = json_string(node->key); + struct json *row_update = node->value; struct json *old, *new; if (row_update->type != JSON_OBJECT) { ovs_error(0, " is not object"); continue; } - old = shash_find_data(json_object(row_update), "old"); - new = shash_find_data(json_object(row_update), "new"); + old = json_object_find(row_update, "old"); + new = json_object_find(row_update, "new"); if (initial) { - monitor_print_row(new, "initial", node->name, columns, &t); + monitor_print_row(new, "initial", name, columns, &t); } else if (!old) { - monitor_print_row(new, "insert", node->name, columns, &t); + monitor_print_row(new, "insert", name, columns, &t); } else if (!new) { - monitor_print_row(old, "delete", node->name, columns, &t); + monitor_print_row(old, "delete", name, columns, &t); } else { - monitor_print_row(old, "old", node->name, columns, &t); + monitor_print_row(old, "old", name, columns, &t); monitor_print_row(new, "new", "", columns, &t); } } @@ -1038,8 +1040,8 @@ monitor_print(const struct json *table_updates, for (i = 0; i < n_mts; i++) { const struct monitored_table *mt = &mts[i]; - struct json *table_update = shash_find_data(json_object(table_updates), - mt->table->name); + struct json *table_update = json_object_find(table_updates, + mt->table->name); if (table_update) { monitor_print_table(table_update, mt, n_mts > 1 ? xstrdup(mt->table->name) : NULL, @@ -1076,7 +1078,7 @@ monitor2_print_table(const struct json *table_update2, { const struct ovsdb_table_schema *table = mt->table; const struct ovsdb_column_set *columns = &mt->columns; - struct shash_node *node; + struct jsmap_node *node; struct table t; if (table_update2->type != JSON_OBJECT) { @@ -1093,8 +1095,8 @@ monitor2_print_table(const struct json *table_update2, for (size_t i = 0; i < columns->n_columns; i++) { table_add_column(&t, "%s", columns->columns[i]->name); } - SHASH_FOR_EACH (node, json_object(table_update2)) { - struct json *row_update2 = node->data; + JSMAP_FOR_EACH (node, json_object(table_update2)) { + struct json *row_update2 = node->value; const char *operation; struct json *row; const char *ops[] = {"delete", "initial", "modify", "insert"}; @@ -1107,10 +1109,11 @@ monitor2_print_table(const struct json *table_update2, /* row_update2 contains one of objects indexed by ops[] */ for (int i = 0; i < ARRAY_SIZE(ops); i++) { operation = ops[i]; - row = shash_find_data(json_object(row_update2), operation); + row = json_object_find(row_update2, operation); if (row) { - monitor2_print_row(row, operation, node->name, columns, &t); + monitor2_print_row(row, operation, json_string(node->key), + columns, &t); break; } } @@ -1132,9 +1135,8 @@ monitor2_print(const struct json *table_updates2, for (i = 0; i < n_mts; i++) { const struct monitored_table *mt = &mts[i]; - struct json *table_update = shash_find_data( - json_object(table_updates2), - mt->table->name); + struct json *table_update = json_object_find(table_updates2, + mt->table->name); if (table_update) { monitor2_print_table(table_update, mt, n_mts > 1 ? xstrdup(mt->table->name) : NULL); @@ -1790,17 +1792,15 @@ dump_table(const char *table_name, const struct shash *cols, data = xmalloc(n * sizeof *data); for (y = 0; y < n; y++) { const struct json *elem = json_array_at(rows, y); - struct shash *row; if (elem->type != JSON_OBJECT) { ovs_fatal(0, "row %"PRIuSIZE" in table %s response is not a JSON object: " "%s", y, table_name, json_to_string(elem, 0)); } - row = json_object(elem); data[y] = xmalloc(n_columns * sizeof **data); for (x = 0; x < n_columns; x++) { - const struct json *json = shash_find_data(row, columns[x]->name); + const struct json *json = json_object_find(elem, columns[x]->name); if (!json) { ovs_fatal(0, "row %"PRIuSIZE" in table %s response lacks %s column", y, table_name, columns[x]->name); @@ -1926,7 +1926,7 @@ do_dump(struct jsonrpc *rpc, const char *database, struct json *rows; if (op_result->type != JSON_OBJECT - || !(rows = shash_find_data(json_object(op_result), "rows")) + || !(rows = json_object_find(op_result, "rows")) || rows->type != JSON_ARRAY) { ovs_fatal(0, "%s table reply is not an object with a \"rows\" " "member array: %s", @@ -2045,7 +2045,7 @@ do_backup(struct jsonrpc *rpc, const char *database, struct json *rows; if (op_result->type != JSON_OBJECT - || !(rows = shash_find_data(json_object(op_result), "rows")) + || !(rows = json_object_find(op_result, "rows")) || rows->type != JSON_ARRAY) { ovs_fatal(0, "%s table reply is not an object with a \"rows\" " "member array: %s", @@ -2065,8 +2065,8 @@ do_backup(struct jsonrpc *rpc, const char *database, table_name, json_to_string(row, 0)); } - struct json *uuid_json = shash_find_and_delete(json_object(row), - "_uuid"); + struct json *uuid_json = json_object_find_and_delete( + CONST_CAST(struct json *, row), "_uuid"); if (!uuid_json) { ovs_fatal(0, "%s table reply row lacks _uuid member: %s", table_name, json_to_string(row, 0)); @@ -2103,8 +2103,7 @@ check_transaction_reply(struct jsonrpc_msg *reply) if (json->type != JSON_OBJECT) { ovs_fatal(0, "result array element is not object"); } - struct shash *object = json_object(json); - if (shash_find(object, "error")) { + if (json_object_find(json, "error")) { ovs_fatal(0, "server returned error reply: %s", json_to_string(json, JSSF_SORT)); } diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 8d9249aad58..1f9f99a16fe 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -32,6 +32,7 @@ #include "fatal-signal.h" #include "file.h" #include "hash.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "jsonrpc.h" #include "jsonrpc-server.h" @@ -2966,8 +2967,8 @@ static bool remotes_from_json(struct shash *remotes, const struct json *json) { struct ovsdb_jsonrpc_options *options; - const struct shash_node *node; - const struct shash *object; + const struct jsmap_node *node; + const struct json *json_opt; free_remotes(remotes); @@ -2980,17 +2981,16 @@ remotes_from_json(struct shash *remotes, const struct json *json) return false; } - object = json_object(json); - SHASH_FOR_EACH (node, object) { - options = ovsdb_jsonrpc_default_options(node->name); - shash_add(remotes, node->name, options); + JSMAP_FOR_EACH (node, json_object(json)) { + options = ovsdb_jsonrpc_default_options(json_string(node->key)); + shash_add(remotes, json_string(node->key), options); - json = node->data; - if (json->type == JSON_OBJECT) { - ovsdb_jsonrpc_options_update_from_json(options, node->data, false); - } else if (json->type != JSON_NULL) { + json_opt = node->value; + if (json_opt->type == JSON_OBJECT) { + ovsdb_jsonrpc_options_update_from_json(options, json_opt, false); + } else if (json_opt->type != JSON_NULL) { VLOG_WARN("%s: JSON-RPC options are not a JSON object or null", - node->name); + json_string(node->key)); free_remotes(remotes); return false; } @@ -3060,16 +3060,16 @@ db_config_from_json(const char *name, const struct json *json) } source = ovsdb_parser_member(&parser, "source", type); - if (source && shash_count(json_object(source)) != 1) { + if (source && jsmap_count(json_object(source)) != 1) { ovsdb_parser_raise_error(&parser, "'source' should be an object with exactly one element"); } else if (source) { - const struct shash_node *node = shash_first(json_object(source)); + const struct jsmap_node *node = jsmap_first(json_object(source)); const struct json *options; ovs_assert(node); - conf->source = xstrdup(node->name); - options = node->data; + conf->source = xstrdup(json_string(node->key)); + options = node->value; conf->options = get_jsonrpc_options(conf->source, conf->model); @@ -3100,8 +3100,7 @@ db_config_from_json(const char *name, const struct json *json) static bool databases_from_json(struct shash *db_conf, const struct json *json) { - const struct shash_node *node; - const struct shash *object; + const struct jsmap_node *node; free_database_configs(db_conf); @@ -3113,12 +3112,12 @@ databases_from_json(struct shash *db_conf, const struct json *json) VLOG_WARN("config: 'databases' is not a JSON object or null"); } - object = json_object(json); - SHASH_FOR_EACH (node, object) { - struct db_config *conf = db_config_from_json(node->name, node->data); + JSMAP_FOR_EACH (node, json_object(json)) { + const char *db_name = json_string(node->key); + struct db_config *conf = db_config_from_json(db_name, node->value); if (conf) { - shash_add(db_conf, node->name, conf); + shash_add(db_conf, db_name, conf); } else { free_database_configs(db_conf); return false; @@ -3154,14 +3153,12 @@ load_config(FILE *config_file, struct shash *remotes, return false; } - if (!remotes_from_json(remotes, - shash_find_data(json_object(json), "remotes"))) { + if (!remotes_from_json(remotes, json_object_find(json, "remotes"))) { VLOG_WARN("config: failed to parse 'remotes'"); json_destroy(json); return false; } - if (!databases_from_json(db_conf, shash_find_data(json_object(json), - "databases"))) { + if (!databases_from_json(db_conf, json_object_find(json, "databases"))) { VLOG_WARN("config: failed to parse 'databases'"); free_remotes(remotes); json_destroy(json); @@ -3169,15 +3166,15 @@ load_config(FILE *config_file, struct shash *remotes, } struct json *string; - string = shash_find_data(json_object(json), "sync_from"); + string = json_object_find(json, "sync_from"); free(*sync_from); *sync_from = string ? xstrdup(json_string(string)) : NULL; - string = shash_find_data(json_object(json), "sync_exclude"); + string = json_object_find(json, "sync_exclude"); free(*sync_exclude); *sync_exclude = string ? xstrdup(json_string(string)) : NULL; - struct json *boolean = shash_find_data(json_object(json), "is_backup"); + struct json *boolean = json_object_find(json, "is_backup"); *is_backup = boolean ? json_boolean(boolean) : false; json_destroy(json); diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c index 368e7a5276e..009a1e85c12 100644 --- a/ovsdb/ovsdb-tool.c +++ b/ovsdb/ovsdb-tool.c @@ -33,6 +33,7 @@ #include "lockfile.h" #include "log.h" #include "openvswitch/hmap.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "ovsdb.h" #include "ovsdb-data.h" @@ -663,21 +664,21 @@ do_transact(struct ovs_cmdl_context *ctx) } static void -print_db_changes(struct shash *tables, struct smap *names, +print_db_changes(const struct json *tables, struct smap *names, const struct ovsdb_schema *schema) { - struct json *is_diff = shash_find_data(tables, "_is_diff"); + const struct json *is_diff = json_object_find(tables, "_is_diff"); bool diff = (is_diff && is_diff->type == JSON_TRUE); - struct shash_node *n1; + struct jsmap_node *n1; int i = 0; - SHASH_FOR_EACH (n1, tables) { - const char *table = n1->name; + JSMAP_FOR_EACH (n1, json_object(tables)) { + const char *table = json_string(n1->key); struct ovsdb_table_schema *table_schema; - struct json *rows = n1->data; - struct shash_node *n2; + const struct json *rows = n1->value; + struct jsmap_node *n2; - if (n1->name[0] == '_' || rows->type != JSON_OBJECT) { + if (table[0] == '_' || rows->type != JSON_OBJECT) { continue; } @@ -686,17 +687,17 @@ print_db_changes(struct shash *tables, struct smap *names, } table_schema = schema ? shash_find_data(&schema->tables, table) : NULL; - SHASH_FOR_EACH (n2, json_object(rows)) { - const char *row_uuid = n2->name; - struct json *columns = n2->data; - struct shash_node *n3; + JSMAP_FOR_EACH (n2, json_object(rows)) { + const char *row_uuid = json_string(n2->key); + const struct json *columns = n2->value; + struct jsmap_node *n3; const char *old_name = smap_get(names, row_uuid); char *new_name = NULL; if (columns->type == JSON_OBJECT) { struct json *new_name_json; - new_name_json = shash_find_data(json_object(columns), "name"); + new_name_json = json_object_find(columns, "name"); if (new_name_json) { new_name = json_to_string(new_name_json, JSSF_SORT); } @@ -717,10 +718,10 @@ print_db_changes(struct shash *tables, struct smap *names, if (columns->type == JSON_OBJECT) { if (show_log_verbosity > 1) { - SHASH_FOR_EACH (n3, json_object(columns)) { - const char *column = n3->name; + JSMAP_FOR_EACH (n3, json_object(columns)) { + const char *column = json_string(n3->key); const struct ovsdb_column *column_schema; - struct json *value = n3->data; + const struct json *value = n3->value; char *value_string = NULL; column_schema = @@ -781,7 +782,7 @@ print_change_record(const struct json *json, const struct ovsdb_schema *schema, struct json *date, *comment; - date = shash_find_data(json_object(json), "_date"); + date = json_object_find(json, "_date"); if (date && date->type == JSON_INTEGER) { long long int t = json_integer(date); char *s; @@ -796,13 +797,13 @@ print_change_record(const struct json *json, const struct ovsdb_schema *schema, free(s); } - comment = shash_find_data(json_object(json), "_comment"); + comment = json_object_find(json, "_comment"); if (comment && comment->type == JSON_STRING) { printf(" \"%s\"", json_string(comment)); } if (show_log_verbosity > 0) { - print_db_changes(json_object(json), names, schema); + print_db_changes(json, names, schema); } } @@ -845,17 +846,17 @@ print_servers(const char *name, const struct json *servers) printf(" %s: ", name); - const struct shash_node **nodes = shash_sort(json_object(servers)); - size_t n = shash_count(json_object(servers)); + const struct jsmap_node **nodes = jsmap_sort(json_object(servers)); + size_t n = jsmap_count(json_object(servers)); for (size_t i = 0; i < n; i++) { if (i > 0) { printf(", "); } - const struct shash_node *node = nodes[i]; - printf("%.4s(", node->name); + const struct jsmap_node *node = nodes[i]; + printf("%.4s(", json_string(node->key)); - const struct json *address = node->data; + const struct json *address = node->value; char *s = json_to_string(address, JSSF_SORT); fputs(s, stdout); free(s); @@ -1566,13 +1567,12 @@ do_check_cluster(struct ovs_cmdl_context *ctx) */ for (struct server *s = c.servers; s < &c.servers[c.n_servers]; s++) { - struct shash *servers_obj = json_object(s->snap->servers); char *server_id = xasprintf(SID_FMT, SID_ARGS(&s->header.sid)); bool found = false; - const struct shash_node *node; + const struct jsmap_node *node; - SHASH_FOR_EACH (node, servers_obj) { - if (!strncmp(server_id, node->name, SID_LEN)) { + JSMAP_FOR_EACH (node, json_object(s->snap->servers)) { + if (!strncmp(server_id, json_string(node->key), SID_LEN)) { found = true; } } @@ -1583,9 +1583,8 @@ do_check_cluster(struct ovs_cmdl_context *ctx) if (e->servers == NULL) { continue; } - struct shash *log_servers_obj = json_object(e->servers); - SHASH_FOR_EACH (node, log_servers_obj) { - if (!strncmp(server_id, node->name, SID_LEN)) { + JSMAP_FOR_EACH (node, json_object(e->servers)) { + if (!strncmp(server_id, json_string(node->key), SID_LEN)) { found = true; } } diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c index 298616a64d0..dd8722a4493 100644 --- a/ovsdb/ovsdb.c +++ b/ovsdb/ovsdb.c @@ -24,6 +24,7 @@ #include "column.h" #include "file.h" #include "monitor.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "openvswitch/poll-loop.h" #include "ovs-thread.h" @@ -231,8 +232,9 @@ ovsdb_schema_from_json(const struct json *json, struct ovsdb_schema **schemap) { struct ovsdb_schema *schema; const struct json *name, *tables, *version_json, *cksum; + struct shash_node *schema_node; struct ovsdb_error *error; - struct shash_node *node; + struct jsmap_node *node; struct ovsdb_parser parser; const char *version; @@ -262,17 +264,18 @@ ovsdb_schema_from_json(const struct json *json, struct ovsdb_schema **schemap) schema = ovsdb_schema_create(json_string(name), version, cksum ? json_string(cksum) : ""); - SHASH_FOR_EACH (node, json_object(tables)) { + JSMAP_FOR_EACH (node, json_object(tables)) { + const char *table_name = json_string(node->key); struct ovsdb_table_schema *table; - if (node->name[0] == '_') { + if (table_name[0] == '_') { error = ovsdb_syntax_error(json, NULL, "names beginning with " "\"_\" are reserved"); - } else if (!ovsdb_parser_is_id(node->name)) { + } else if (!ovsdb_parser_is_id(table_name)) { error = ovsdb_syntax_error(json, NULL, "name must be a valid id"); } else { - error = ovsdb_table_schema_from_json(node->data, node->name, - &table); + error = ovsdb_table_schema_from_json(node->value, + table_name, &table); } if (error) { ovsdb_schema_destroy(schema); @@ -287,8 +290,8 @@ ovsdb_schema_from_json(const struct json *json, struct ovsdb_schema **schemap) * compatibility, if the root set is empty then assume that every table is * in the root set. */ if (root_set_size(schema) == 0) { - SHASH_FOR_EACH (node, &schema->tables) { - struct ovsdb_table_schema *table = node->data; + SHASH_FOR_EACH (schema_node, &schema->tables) { + struct ovsdb_table_schema *table = schema_node->data; table->is_root = true; } @@ -299,8 +302,8 @@ ovsdb_schema_from_json(const struct json *json, struct ovsdb_schema **schemap) * Also force certain columns to be persistent, as explained in * ovsdb_schema_check_ref_table(). This requires 'is_root' to be known, so * this must follow the loop updating 'is_root' above. */ - SHASH_FOR_EACH (node, &schema->tables) { - struct ovsdb_table_schema *table = node->data; + SHASH_FOR_EACH (schema_node, &schema->tables) { + struct ovsdb_table_schema *table = schema_node->data; struct shash_node *node2; SHASH_FOR_EACH (node2, &table->columns) { diff --git a/ovsdb/raft-private.c b/ovsdb/raft-private.c index c880e32acd0..8147afd2ce3 100644 --- a/ovsdb/raft-private.c +++ b/ovsdb/raft-private.c @@ -19,6 +19,7 @@ #include "raft-private.h" #include "coverage.h" +#include "openvswitch/jsmap.h" #include "openvswitch/dynamic-string.h" #include "ovsdb-error.h" #include "ovsdb-parser.h" @@ -210,21 +211,21 @@ raft_servers_from_json__(const struct json *json, struct hmap *servers) { if (!json || json->type != JSON_OBJECT) { return ovsdb_syntax_error(json, NULL, "servers must be JSON object"); - } else if (shash_is_empty(json_object(json))) { + } else if (jsmap_is_empty(json_object(json))) { return ovsdb_syntax_error(json, NULL, "must have at least one server"); } /* Parse new servers. */ - struct shash_node *node; - SHASH_FOR_EACH (node, json_object(json)) { + struct jsmap_node *node; + JSMAP_FOR_EACH (node, json_object(json)) { /* Parse server UUID. */ struct uuid sid; - if (!uuid_from_string(&sid, node->name)) { + if (!uuid_from_string(&sid, json_string(node->key))) { return ovsdb_syntax_error(json, NULL, "%s is not a UUID", - node->name); + json_string(node->key)); } - const struct json *address = node->data; + const struct json *address = node->value; struct ovsdb_error *error = raft_address_validate_json(address); if (error) { return error; diff --git a/ovsdb/raft.c b/ovsdb/raft.c index 9c3c351b5be..a9e72502fff 100644 --- a/ovsdb/raft.c +++ b/ovsdb/raft.c @@ -519,9 +519,9 @@ raft_create_cluster(const char *file_name, const char *name, }, }; raft_entry_set_parsed_data(&h.snap, data); - shash_add_nocopy(json_object(h.snap.servers), - xasprintf(UUID_FMT, UUID_ARGS(&h.sid)), - json_string_create(local_address)); + json_object_put_nocopy(h.snap.servers, + xasprintf(UUID_FMT, UUID_ARGS(&h.sid)), + json_string_create(local_address)); error = ovsdb_log_write_and_free(log, raft_header_to_json(&h)); raft_header_uninit(&h); if (error) { diff --git a/ovsdb/relay.c b/ovsdb/relay.c index 71a5b8e1cec..53412bf5cba 100644 --- a/ovsdb/relay.c +++ b/ovsdb/relay.c @@ -198,15 +198,9 @@ ovsdb_relay_process_row_update(struct ovsdb_table *table, const struct ovsdb_cs_row_update *ru, struct ovsdb_txn *txn) { + const struct json *json_row = ru->columns; const struct uuid *uuid = &ru->row_uuid; - struct ovsdb_error * error = NULL; - - /* XXX: ovsdb-cs module returns shash which was previously part of a json - * structure and we need json row format in order to use ovsdb_row* - * functions. Creating a json object out of shash. */ - struct json *json_row = json_object_create(); - struct shash *obj = json_row->object; - json_row->object = CONST_CAST(struct shash *, ru->columns); + struct ovsdb_error *error = NULL; switch (ru->type) { case OVSDB_CS_ROW_DELETE: @@ -229,9 +223,6 @@ ovsdb_relay_process_row_update(struct ovsdb_table *table, OVS_NOT_REACHED(); } - json_row->object = obj; - json_destroy(json_row); - return error; } diff --git a/ovsdb/replication.c b/ovsdb/replication.c index bb21ff7d398..745f1f85b80 100644 --- a/ovsdb/replication.c +++ b/ovsdb/replication.c @@ -22,6 +22,7 @@ #include "jsonrpc.h" #include "openvswitch/dynamic-string.h" #include "openvswitch/hmap.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "openvswitch/vlog.h" #include "ovsdb-error.h" @@ -602,11 +603,12 @@ process_notification(const struct json *table_updates, struct ovsdb *db) txn = ovsdb_txn_create(db); /* Process each table update. */ - struct shash_node *node; - SHASH_FOR_EACH (node, json_object(table_updates)) { - struct json *table_update = node->data; + struct jsmap_node *node; + JSMAP_FOR_EACH (node, json_object(table_updates)) { + struct json *table_update = node->value; if (table_update) { - error = process_table_update(table_update, node->name, db, txn); + error = process_table_update(table_update, + json_string(node->key), db, txn); if (error) { break; } @@ -639,9 +641,9 @@ process_table_update(const struct json *table_update, const char *table_name, " for table is not object"); } - struct shash_node *node; - SHASH_FOR_EACH (node, json_object(table_update)) { - struct json *row_update = node->data; + struct jsmap_node *node; + JSMAP_FOR_EACH (node, json_object(table_update)) { + struct json *row_update = node->value; struct json *old, *new; if (row_update->type != JSON_OBJECT) { @@ -650,13 +652,13 @@ process_table_update(const struct json *table_update, const char *table_name, } struct uuid uuid; - if (!uuid_from_string(&uuid, node->name)) { + if (!uuid_from_string(&uuid, json_string(node->key))) { return ovsdb_syntax_error(table_update, "bad row UUID", " names must be UUIDs"); } - old = shash_find_data(json_object(row_update), "old"); - new = shash_find_data(json_object(row_update), "new"); + old = json_object_find(row_update, "old"); + new = json_object_find(row_update, "new"); struct ovsdb_error *error; error = (!new ? ovsdb_table_execute_delete(txn, &uuid, table) diff --git a/ovsdb/row.c b/ovsdb/row.c index 6b52509a91c..f8af7307766 100644 --- a/ovsdb/row.c +++ b/ovsdb/row.c @@ -20,6 +20,7 @@ #include #include "openvswitch/dynamic-string.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "openvswitch/shash.h" #include "ovsdb-error.h" @@ -306,7 +307,7 @@ ovsdb_row_from_json(struct ovsdb_row *row, const struct json *json, { struct ovsdb_table_schema *schema = row->table->schema; struct ovsdb_error *error; - struct shash_node *node; + struct jsmap_node *node; ovs_assert(!is_diff || !symtab); @@ -314,8 +315,8 @@ ovsdb_row_from_json(struct ovsdb_row *row, const struct json *json, return ovsdb_syntax_error(json, NULL, "row must be JSON object"); } - SHASH_FOR_EACH (node, json_object(json)) { - const char *column_name = node->name; + JSMAP_FOR_EACH (node, json_object(json)) { + const char *column_name = json_string(node->key); const struct ovsdb_column *column; struct ovsdb_datum datum; @@ -328,9 +329,9 @@ ovsdb_row_from_json(struct ovsdb_row *row, const struct json *json, if (is_diff) { error = ovsdb_transient_datum_from_json(&datum, &column->type, - node->data); + node->value); } else { - error = ovsdb_datum_from_json(&datum, &column->type, node->data, + error = ovsdb_datum_from_json(&datum, &column->type, node->value, symtab); } if (error) { diff --git a/ovsdb/table.c b/ovsdb/table.c index 589ee5e8c32..b22e69da3db 100644 --- a/ovsdb/table.c +++ b/ovsdb/table.c @@ -19,6 +19,7 @@ #include +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "column.h" #include "ovsdb-error.h" @@ -128,7 +129,7 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name, { struct ovsdb_table_schema *ts; const struct json *columns, *mutable, *max_rows, *is_root, *indexes; - struct shash_node *node; + struct jsmap_node *node; struct ovsdb_parser parser; struct ovsdb_error *error; long long int n_max_rows; @@ -158,7 +159,7 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name, n_max_rows = UINT_MAX; } - if (shash_is_empty(json_object(columns))) { + if (jsmap_is_empty(json_object(columns))) { return ovsdb_syntax_error(json, NULL, "table must have at least one column"); } @@ -167,16 +168,17 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name, mutable ? json_boolean(mutable) : true, MIN(n_max_rows, UINT_MAX), is_root ? json_boolean(is_root) : false); - SHASH_FOR_EACH (node, json_object(columns)) { + JSMAP_FOR_EACH (node, json_object(columns)) { + const char *column_name = json_string(node->key); struct ovsdb_column *column; - if (node->name[0] == '_') { + if (column_name[0] == '_') { error = ovsdb_syntax_error(json, NULL, "names beginning with " "\"_\" are reserved"); - } else if (!ovsdb_parser_is_id(node->name)) { + } else if (!ovsdb_parser_is_id(column_name)) { error = ovsdb_syntax_error(json, NULL, "name must be a valid id"); } else { - error = ovsdb_column_from_json(node->data, node->name, &column); + error = ovsdb_column_from_json(node->value, column_name, &column); } if (error) { goto error; @@ -356,7 +358,8 @@ ovsdb_table_get_row(const struct ovsdb_table *table, const struct uuid *uuid) struct ovsdb_error * ovsdb_table_execute_insert(struct ovsdb_txn *txn, const struct uuid *row_uuid, - struct ovsdb_table *table, struct json *json_row) + struct ovsdb_table *table, + const struct json *json_row) { const struct ovsdb_row *old_row = ovsdb_table_get_row(table, row_uuid); if (old_row) { @@ -398,8 +401,8 @@ ovsdb_table_execute_delete(struct ovsdb_txn *txn, const struct uuid *row_uuid, struct ovsdb_error * ovsdb_table_execute_update(struct ovsdb_txn *txn, const struct uuid *row_uuid, - struct ovsdb_table *table, struct json *json_row, - bool xor) + struct ovsdb_table *table, + const struct json *json_row, bool xor) { const struct ovsdb_row *row = ovsdb_table_get_row(table, row_uuid); if (!row) { diff --git a/ovsdb/table.h b/ovsdb/table.h index 614c4ed826a..4cb9900882f 100644 --- a/ovsdb/table.h +++ b/ovsdb/table.h @@ -79,13 +79,14 @@ const struct ovsdb_row *ovsdb_table_get_row(const struct ovsdb_table *, struct ovsdb_error *ovsdb_table_execute_insert(struct ovsdb_txn *txn, const struct uuid *row_uuid, struct ovsdb_table *table, - struct json *new); + const struct json *new); struct ovsdb_error *ovsdb_table_execute_delete(struct ovsdb_txn *txn, const struct uuid *row_uuid, struct ovsdb_table *table); struct ovsdb_error *ovsdb_table_execute_update(struct ovsdb_txn *txn, const struct uuid *row_uuid, struct ovsdb_table *table, - struct json *new, bool xor); + const struct json *new, + bool xor); #endif /* ovsdb/table.h */ diff --git a/python/ovs/_json.c b/python/ovs/_json.c index bd9f5fe1988..e83fa2c1bb6 100644 --- a/python/ovs/_json.c +++ b/python/ovs/_json.c @@ -1,4 +1,5 @@ #include "Python.h" +#include #include #include "structmember.h" @@ -88,14 +89,14 @@ json_to_python(struct json *json) case JSON_TRUE: Py_RETURN_TRUE; case JSON_OBJECT:{ - struct shash_node *node; + struct jsmap_node *node; PyObject *dict = PyDict_New(); if (dict == NULL) { return PyErr_NoMemory(); } - SHASH_FOR_EACH (node, json->object) { - PyObject *key = PyUnicode_FromString(node->name); + JSMAP_FOR_EACH (node, json->object) { + PyObject *key = PyUnicode_FromString(json_string(node->name)); PyObject *val = json_to_python(node->data); if (!(key && val) || PyDict_SetItem(dict, key, val)) { diff --git a/tests/test-json.c b/tests/test-json.c index f5b0ad3713a..c5cab4afd59 100644 --- a/tests/test-json.c +++ b/tests/test-json.c @@ -16,6 +16,7 @@ #include #undef NDEBUG +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include #include @@ -38,10 +39,10 @@ static void test_json_equal(const struct json *a, const struct json *b, bool allow_the_same); static void -test_json_equal_object(const struct shash *a, const struct shash *b, +test_json_equal_object(const struct jsmap *a, const struct jsmap *b, bool allow_the_same) { - struct shash_node *a_node; + struct jsmap_node *a_node; ovs_assert(allow_the_same || a != b); @@ -49,13 +50,13 @@ test_json_equal_object(const struct shash *a, const struct shash *b, return; } - ovs_assert(shash_count(a) == shash_count(b)); + ovs_assert(jsmap_count(a) == jsmap_count(b)); - SHASH_FOR_EACH (a_node, a) { - struct shash_node *b_node = shash_find(b, a_node->name); + JSMAP_FOR_EACH (a_node, a) { + struct jsmap_node *b_node = jsmap_get_node(b, a_node->key); ovs_assert(b_node); - test_json_equal(a_node->data, b_node->data, allow_the_same); + test_json_equal(a_node->value, b_node->value, allow_the_same); } } diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c index 5b41526937b..0d48eb9ec24 100644 --- a/tests/test-ovsdb.c +++ b/tests/test-ovsdb.c @@ -26,6 +26,7 @@ #include "byte-order.h" #include "command-line.h" #include "openvswitch/dynamic-string.h" +#include "openvswitch/jsmap.h" #include "openvswitch/json.h" #include "jsonrpc.h" #include "ovsdb-data.h" @@ -2397,10 +2398,10 @@ parse_uuids(const struct json *json, struct ovsdb_symbol_table *symtab, parse_uuids(json_array_at(json, i), symtab, n); } } else if (json->type == JSON_OBJECT) { - const struct shash_node *node; + const struct jsmap_node *node; - SHASH_FOR_EACH (node, json_object(json)) { - parse_uuids(node->data, symtab, n); + JSMAP_FOR_EACH (node, json_object(json)) { + parse_uuids(node->value, symtab, n); } } } @@ -2427,10 +2428,10 @@ substitute_uuids(struct json *json, const struct ovsdb_symbol_table *symtab) symtab); } } else if (json->type == JSON_OBJECT) { - const struct shash_node *node; + const struct jsmap_node *node; - SHASH_FOR_EACH (node, json_object(json)) { - substitute_uuids(node->data, symtab); + JSMAP_FOR_EACH (node, json_object(json)) { + substitute_uuids(node->value, symtab); } } }