1 /* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
22 #include "openvswitch/dynamic-string.h"
23 #include "openvswitch/json.h"
24 #include "ovsdb-error.h"
25 #include "openvswitch/shash.h"
30 static struct ovsdb_row
*
31 allocate_row(const struct ovsdb_table
*table
)
33 size_t n_fields
= shash_count(&table
->schema
->columns
);
34 size_t n_indexes
= table
->schema
->n_indexes
;
35 size_t row_size
= (offsetof(struct ovsdb_row
, fields
)
36 + sizeof(struct ovsdb_datum
) * n_fields
37 + sizeof(struct hmap_node
) * n_indexes
);
38 struct ovsdb_row
*row
= xmalloc(row_size
);
39 row
->table
= CONST_CAST(struct ovsdb_table
*, table
);
41 ovs_list_init(&row
->src_refs
);
42 ovs_list_init(&row
->dst_refs
);
47 /* Creates and returns a new row suitable for insertion into 'table'. Does not
48 * actually insert the row into 'table' (use ovsdb_txn_row_insert()). The
49 * caller must assign a UUID to the row. */
51 ovsdb_row_create(const struct ovsdb_table
*table
)
53 struct shash_node
*node
;
54 struct ovsdb_row
*row
;
56 row
= allocate_row(table
);
57 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
58 const struct ovsdb_column
*column
= node
->data
;
59 ovsdb_datum_init_default(&row
->fields
[column
->index
], &column
->type
);
65 ovsdb_row_clone(const struct ovsdb_row
*old
)
67 const struct ovsdb_table
*table
= old
->table
;
68 const struct shash_node
*node
;
69 struct ovsdb_row
*new;
71 new = allocate_row(table
);
72 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
73 const struct ovsdb_column
*column
= node
->data
;
74 ovsdb_datum_clone(&new->fields
[column
->index
],
75 &old
->fields
[column
->index
],
81 /* The caller is responsible for ensuring that 'row' has been removed from its
82 * table and that it is not participating in a transaction. */
84 ovsdb_row_destroy(struct ovsdb_row
*row
)
87 const struct ovsdb_table
*table
= row
->table
;
88 struct ovsdb_weak_ref
*weak
, *next
;
89 const struct shash_node
*node
;
91 LIST_FOR_EACH_SAFE (weak
, next
, dst_node
, &row
->dst_refs
) {
92 ovs_list_remove(&weak
->src_node
);
93 ovs_list_remove(&weak
->dst_node
);
97 LIST_FOR_EACH_SAFE (weak
, next
, src_node
, &row
->src_refs
) {
98 ovs_list_remove(&weak
->src_node
);
99 ovs_list_remove(&weak
->dst_node
);
103 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
104 const struct ovsdb_column
*column
= node
->data
;
105 ovsdb_datum_destroy(&row
->fields
[column
->index
], &column
->type
);
112 ovsdb_row_hash_columns(const struct ovsdb_row
*row
,
113 const struct ovsdb_column_set
*columns
,
118 for (i
= 0; i
< columns
->n_columns
; i
++) {
119 const struct ovsdb_column
*column
= columns
->columns
[i
];
120 basis
= ovsdb_datum_hash(&row
->fields
[column
->index
], &column
->type
,
128 ovsdb_row_compare_columns_3way(const struct ovsdb_row
*a
,
129 const struct ovsdb_row
*b
,
130 const struct ovsdb_column_set
*columns
)
134 for (i
= 0; i
< columns
->n_columns
; i
++) {
135 const struct ovsdb_column
*column
= columns
->columns
[i
];
136 int cmp
= ovsdb_datum_compare_3way(&a
->fields
[column
->index
],
137 &b
->fields
[column
->index
],
148 ovsdb_row_equal_columns(const struct ovsdb_row
*a
,
149 const struct ovsdb_row
*b
,
150 const struct ovsdb_column_set
*columns
)
154 for (i
= 0; i
< columns
->n_columns
; i
++) {
155 const struct ovsdb_column
*column
= columns
->columns
[i
];
156 if (!ovsdb_datum_equals(&a
->fields
[column
->index
],
157 &b
->fields
[column
->index
],
167 ovsdb_row_update_columns(struct ovsdb_row
*dst
,
168 const struct ovsdb_row
*src
,
169 const struct ovsdb_column_set
*columns
)
173 for (i
= 0; i
< columns
->n_columns
; i
++) {
174 const struct ovsdb_column
*column
= columns
->columns
[i
];
175 ovsdb_datum_destroy(&dst
->fields
[column
->index
], &column
->type
);
176 ovsdb_datum_clone(&dst
->fields
[column
->index
],
177 &src
->fields
[column
->index
],
182 /* Appends the string form of the value in 'row' of each of the columns in
183 * 'columns' to 'out', e.g. "1, \"xyz\", and [1, 2, 3]". */
185 ovsdb_row_columns_to_string(const struct ovsdb_row
*row
,
186 const struct ovsdb_column_set
*columns
,
191 for (i
= 0; i
< columns
->n_columns
; i
++) {
192 const struct ovsdb_column
*column
= columns
->columns
[i
];
194 ds_put_cstr(out
, english_list_delimiter(i
, columns
->n_columns
));
195 ovsdb_datum_to_string(&row
->fields
[column
->index
], &column
->type
, out
);
200 ovsdb_row_from_json(struct ovsdb_row
*row
, const struct json
*json
,
201 struct ovsdb_symbol_table
*symtab
,
202 struct ovsdb_column_set
*included
)
204 struct ovsdb_table_schema
*schema
= row
->table
->schema
;
205 struct ovsdb_error
*error
;
206 struct shash_node
*node
;
208 if (json
->type
!= JSON_OBJECT
) {
209 return ovsdb_syntax_error(json
, NULL
, "row must be JSON object");
212 SHASH_FOR_EACH (node
, json_object(json
)) {
213 const char *column_name
= node
->name
;
214 const struct ovsdb_column
*column
;
215 struct ovsdb_datum datum
;
217 column
= ovsdb_table_schema_get_column(schema
, column_name
);
219 return ovsdb_syntax_error(json
, "unknown column",
220 "No column %s in table %s.",
221 column_name
, schema
->name
);
224 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
229 ovsdb_datum_swap(&row
->fields
[column
->index
], &datum
);
230 ovsdb_datum_destroy(&datum
, &column
->type
);
232 ovsdb_column_set_add(included
, column
);
240 put_json_column(struct json
*object
, const struct ovsdb_row
*row
,
241 const struct ovsdb_column
*column
)
243 json_object_put(object
, column
->name
,
244 ovsdb_datum_to_json(&row
->fields
[column
->index
],
249 ovsdb_row_to_json(const struct ovsdb_row
*row
,
250 const struct ovsdb_column_set
*columns
)
255 json
= json_object_create();
256 for (i
= 0; i
< columns
->n_columns
; i
++) {
257 put_json_column(json
, row
, columns
->columns
[i
]);
263 ovsdb_row_set_init(struct ovsdb_row_set
*set
)
266 set
->n_rows
= set
->allocated_rows
= 0;
270 ovsdb_row_set_destroy(struct ovsdb_row_set
*set
)
276 ovsdb_row_set_add_row(struct ovsdb_row_set
*set
, const struct ovsdb_row
*row
)
278 if (set
->n_rows
>= set
->allocated_rows
) {
279 set
->rows
= x2nrealloc(set
->rows
, &set
->allocated_rows
,
282 set
->rows
[set
->n_rows
++] = row
;
286 ovsdb_row_set_to_json(const struct ovsdb_row_set
*rows
,
287 const struct ovsdb_column_set
*columns
)
289 struct json
**json_rows
;
292 json_rows
= xmalloc(rows
->n_rows
* sizeof *json_rows
);
293 for (i
= 0; i
< rows
->n_rows
; i
++) {
294 json_rows
[i
] = ovsdb_row_to_json(rows
->rows
[i
], columns
);
296 return json_array_create(json_rows
, rows
->n_rows
);
299 struct ovsdb_row_set_sort_cbdata
{
300 struct ovsdb_row_set
*set
;
301 const struct ovsdb_column_set
*columns
;
305 ovsdb_row_set_sort_compare_cb(size_t a
, size_t b
, void *cbdata_
)
307 struct ovsdb_row_set_sort_cbdata
*cbdata
= cbdata_
;
308 return ovsdb_row_compare_columns_3way(cbdata
->set
->rows
[a
],
309 cbdata
->set
->rows
[b
],
314 ovsdb_row_set_sort_swap_cb(size_t a
, size_t b
, void *cbdata_
)
316 struct ovsdb_row_set_sort_cbdata
*cbdata
= cbdata_
;
317 const struct ovsdb_row
*tmp
= cbdata
->set
->rows
[a
];
318 cbdata
->set
->rows
[a
] = cbdata
->set
->rows
[b
];
319 cbdata
->set
->rows
[b
] = tmp
;
323 ovsdb_row_set_sort(struct ovsdb_row_set
*set
,
324 const struct ovsdb_column_set
*columns
)
326 if (columns
&& columns
->n_columns
&& set
->n_rows
> 1) {
327 struct ovsdb_row_set_sort_cbdata cbdata
;
329 cbdata
.columns
= columns
;
331 ovsdb_row_set_sort_compare_cb
,
332 ovsdb_row_set_sort_swap_cb
,
338 ovsdb_row_hash_init(struct ovsdb_row_hash
*rh
,
339 const struct ovsdb_column_set
*columns
)
341 hmap_init(&rh
->rows
);
342 ovsdb_column_set_clone(&rh
->columns
, columns
);
346 ovsdb_row_hash_destroy(struct ovsdb_row_hash
*rh
, bool destroy_rows
)
348 struct ovsdb_row_hash_node
*node
;
350 HMAP_FOR_EACH_POP (node
, hmap_node
, &rh
->rows
) {
352 ovsdb_row_destroy(CONST_CAST(struct ovsdb_row
*, node
->row
));
356 hmap_destroy(&rh
->rows
);
357 ovsdb_column_set_destroy(&rh
->columns
);
361 ovsdb_row_hash_count(const struct ovsdb_row_hash
*rh
)
363 return hmap_count(&rh
->rows
);
367 ovsdb_row_hash_contains(const struct ovsdb_row_hash
*rh
,
368 const struct ovsdb_row
*row
)
370 size_t hash
= ovsdb_row_hash_columns(row
, &rh
->columns
, 0);
371 return ovsdb_row_hash_contains__(rh
, row
, hash
);
374 /* Returns true if every row in 'b' has an equal row in 'a'. */
376 ovsdb_row_hash_contains_all(const struct ovsdb_row_hash
*a
,
377 const struct ovsdb_row_hash
*b
)
379 struct ovsdb_row_hash_node
*node
;
381 ovs_assert(ovsdb_column_set_equals(&a
->columns
, &b
->columns
));
382 HMAP_FOR_EACH (node
, hmap_node
, &b
->rows
) {
383 if (!ovsdb_row_hash_contains__(a
, node
->row
, node
->hmap_node
.hash
)) {
391 ovsdb_row_hash_insert(struct ovsdb_row_hash
*rh
, const struct ovsdb_row
*row
)
393 size_t hash
= ovsdb_row_hash_columns(row
, &rh
->columns
, 0);
394 return ovsdb_row_hash_insert__(rh
, row
, hash
);
398 ovsdb_row_hash_contains__(const struct ovsdb_row_hash
*rh
,
399 const struct ovsdb_row
*row
, size_t hash
)
401 struct ovsdb_row_hash_node
*node
;
402 HMAP_FOR_EACH_WITH_HASH (node
, hmap_node
, hash
, &rh
->rows
) {
403 if (ovsdb_row_equal_columns(row
, node
->row
, &rh
->columns
)) {
411 ovsdb_row_hash_insert__(struct ovsdb_row_hash
*rh
, const struct ovsdb_row
*row
,
414 if (!ovsdb_row_hash_contains__(rh
, row
, hash
)) {
415 struct ovsdb_row_hash_node
*node
= xmalloc(sizeof *node
);
417 hmap_insert(&rh
->rows
, &node
->hmap_node
, hash
);