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 "dynamic-string.h"
24 #include "ovsdb-error.h"
29 static struct ovsdb_row
*
30 allocate_row(const struct ovsdb_table
*table
)
32 size_t n_fields
= shash_count(&table
->schema
->columns
);
33 size_t n_indexes
= table
->schema
->n_indexes
;
34 size_t row_size
= (offsetof(struct ovsdb_row
, fields
)
35 + sizeof(struct ovsdb_datum
) * n_fields
36 + sizeof(struct hmap_node
) * n_indexes
);
37 struct ovsdb_row
*row
= xmalloc(row_size
);
38 row
->table
= CONST_CAST(struct ovsdb_table
*, table
);
40 list_init(&row
->src_refs
);
41 list_init(&row
->dst_refs
);
47 ovsdb_row_create(const struct ovsdb_table
*table
)
49 struct shash_node
*node
;
50 struct ovsdb_row
*row
;
52 row
= allocate_row(table
);
53 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
54 const struct ovsdb_column
*column
= node
->data
;
55 ovsdb_datum_init_default(&row
->fields
[column
->index
], &column
->type
);
61 ovsdb_row_clone(const struct ovsdb_row
*old
)
63 const struct ovsdb_table
*table
= old
->table
;
64 const struct shash_node
*node
;
65 struct ovsdb_row
*new;
67 new = allocate_row(table
);
68 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
69 const struct ovsdb_column
*column
= node
->data
;
70 ovsdb_datum_clone(&new->fields
[column
->index
],
71 &old
->fields
[column
->index
],
77 /* The caller is responsible for ensuring that 'row' has been removed from its
78 * table and that it is not participating in a transaction. */
80 ovsdb_row_destroy(struct ovsdb_row
*row
)
83 const struct ovsdb_table
*table
= row
->table
;
84 struct ovsdb_weak_ref
*weak
, *next
;
85 const struct shash_node
*node
;
87 LIST_FOR_EACH_SAFE (weak
, next
, dst_node
, &row
->dst_refs
) {
88 list_remove(&weak
->src_node
);
89 list_remove(&weak
->dst_node
);
93 LIST_FOR_EACH_SAFE (weak
, next
, src_node
, &row
->src_refs
) {
94 list_remove(&weak
->src_node
);
95 list_remove(&weak
->dst_node
);
99 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
100 const struct ovsdb_column
*column
= node
->data
;
101 ovsdb_datum_destroy(&row
->fields
[column
->index
], &column
->type
);
108 ovsdb_row_hash_columns(const struct ovsdb_row
*row
,
109 const struct ovsdb_column_set
*columns
,
114 for (i
= 0; i
< columns
->n_columns
; i
++) {
115 const struct ovsdb_column
*column
= columns
->columns
[i
];
116 basis
= ovsdb_datum_hash(&row
->fields
[column
->index
], &column
->type
,
124 ovsdb_row_compare_columns_3way(const struct ovsdb_row
*a
,
125 const struct ovsdb_row
*b
,
126 const struct ovsdb_column_set
*columns
)
130 for (i
= 0; i
< columns
->n_columns
; i
++) {
131 const struct ovsdb_column
*column
= columns
->columns
[i
];
132 int cmp
= ovsdb_datum_compare_3way(&a
->fields
[column
->index
],
133 &b
->fields
[column
->index
],
144 ovsdb_row_equal_columns(const struct ovsdb_row
*a
,
145 const struct ovsdb_row
*b
,
146 const struct ovsdb_column_set
*columns
)
150 for (i
= 0; i
< columns
->n_columns
; i
++) {
151 const struct ovsdb_column
*column
= columns
->columns
[i
];
152 if (!ovsdb_datum_equals(&a
->fields
[column
->index
],
153 &b
->fields
[column
->index
],
163 ovsdb_row_update_columns(struct ovsdb_row
*dst
,
164 const struct ovsdb_row
*src
,
165 const struct ovsdb_column_set
*columns
)
169 for (i
= 0; i
< columns
->n_columns
; i
++) {
170 const struct ovsdb_column
*column
= columns
->columns
[i
];
171 ovsdb_datum_destroy(&dst
->fields
[column
->index
], &column
->type
);
172 ovsdb_datum_clone(&dst
->fields
[column
->index
],
173 &src
->fields
[column
->index
],
178 /* Appends the string form of the value in 'row' of each of the columns in
179 * 'columns' to 'out', e.g. "1, \"xyz\", and [1, 2, 3]". */
181 ovsdb_row_columns_to_string(const struct ovsdb_row
*row
,
182 const struct ovsdb_column_set
*columns
,
187 for (i
= 0; i
< columns
->n_columns
; i
++) {
188 const struct ovsdb_column
*column
= columns
->columns
[i
];
190 ds_put_cstr(out
, english_list_delimiter(i
, columns
->n_columns
));
191 ovsdb_datum_to_string(&row
->fields
[column
->index
], &column
->type
, out
);
196 ovsdb_row_from_json(struct ovsdb_row
*row
, const struct json
*json
,
197 struct ovsdb_symbol_table
*symtab
,
198 struct ovsdb_column_set
*included
)
200 struct ovsdb_table_schema
*schema
= row
->table
->schema
;
201 struct ovsdb_error
*error
;
202 struct shash_node
*node
;
204 if (json
->type
!= JSON_OBJECT
) {
205 return ovsdb_syntax_error(json
, NULL
, "row must be JSON object");
208 SHASH_FOR_EACH (node
, json_object(json
)) {
209 const char *column_name
= node
->name
;
210 const struct ovsdb_column
*column
;
211 struct ovsdb_datum datum
;
213 column
= ovsdb_table_schema_get_column(schema
, column_name
);
215 return ovsdb_syntax_error(json
, "unknown column",
216 "No column %s in table %s.",
217 column_name
, schema
->name
);
220 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
225 ovsdb_datum_swap(&row
->fields
[column
->index
], &datum
);
226 ovsdb_datum_destroy(&datum
, &column
->type
);
228 ovsdb_column_set_add(included
, column
);
236 put_json_column(struct json
*object
, const struct ovsdb_row
*row
,
237 const struct ovsdb_column
*column
)
239 json_object_put(object
, column
->name
,
240 ovsdb_datum_to_json(&row
->fields
[column
->index
],
245 ovsdb_row_to_json(const struct ovsdb_row
*row
,
246 const struct ovsdb_column_set
*columns
)
251 json
= json_object_create();
252 for (i
= 0; i
< columns
->n_columns
; i
++) {
253 put_json_column(json
, row
, columns
->columns
[i
]);
259 ovsdb_row_set_init(struct ovsdb_row_set
*set
)
262 set
->n_rows
= set
->allocated_rows
= 0;
266 ovsdb_row_set_destroy(struct ovsdb_row_set
*set
)
272 ovsdb_row_set_add_row(struct ovsdb_row_set
*set
, const struct ovsdb_row
*row
)
274 if (set
->n_rows
>= set
->allocated_rows
) {
275 set
->rows
= x2nrealloc(set
->rows
, &set
->allocated_rows
,
278 set
->rows
[set
->n_rows
++] = row
;
282 ovsdb_row_set_to_json(const struct ovsdb_row_set
*rows
,
283 const struct ovsdb_column_set
*columns
)
285 struct json
**json_rows
;
288 json_rows
= xmalloc(rows
->n_rows
* sizeof *json_rows
);
289 for (i
= 0; i
< rows
->n_rows
; i
++) {
290 json_rows
[i
] = ovsdb_row_to_json(rows
->rows
[i
], columns
);
292 return json_array_create(json_rows
, rows
->n_rows
);
295 struct ovsdb_row_set_sort_cbdata
{
296 struct ovsdb_row_set
*set
;
297 const struct ovsdb_column_set
*columns
;
301 ovsdb_row_set_sort_compare_cb(size_t a
, size_t b
, void *cbdata_
)
303 struct ovsdb_row_set_sort_cbdata
*cbdata
= cbdata_
;
304 return ovsdb_row_compare_columns_3way(cbdata
->set
->rows
[a
],
305 cbdata
->set
->rows
[b
],
310 ovsdb_row_set_sort_swap_cb(size_t a
, size_t b
, void *cbdata_
)
312 struct ovsdb_row_set_sort_cbdata
*cbdata
= cbdata_
;
313 const struct ovsdb_row
*tmp
= cbdata
->set
->rows
[a
];
314 cbdata
->set
->rows
[a
] = cbdata
->set
->rows
[b
];
315 cbdata
->set
->rows
[b
] = tmp
;
319 ovsdb_row_set_sort(struct ovsdb_row_set
*set
,
320 const struct ovsdb_column_set
*columns
)
322 if (columns
&& columns
->n_columns
&& set
->n_rows
> 1) {
323 struct ovsdb_row_set_sort_cbdata cbdata
;
325 cbdata
.columns
= columns
;
327 ovsdb_row_set_sort_compare_cb
,
328 ovsdb_row_set_sort_swap_cb
,
334 ovsdb_row_hash_init(struct ovsdb_row_hash
*rh
,
335 const struct ovsdb_column_set
*columns
)
337 hmap_init(&rh
->rows
);
338 ovsdb_column_set_clone(&rh
->columns
, columns
);
342 ovsdb_row_hash_destroy(struct ovsdb_row_hash
*rh
, bool destroy_rows
)
344 struct ovsdb_row_hash_node
*node
, *next
;
346 HMAP_FOR_EACH_SAFE (node
, next
, hmap_node
, &rh
->rows
) {
347 hmap_remove(&rh
->rows
, &node
->hmap_node
);
349 ovsdb_row_destroy(CONST_CAST(struct ovsdb_row
*, node
->row
));
353 hmap_destroy(&rh
->rows
);
354 ovsdb_column_set_destroy(&rh
->columns
);
358 ovsdb_row_hash_count(const struct ovsdb_row_hash
*rh
)
360 return hmap_count(&rh
->rows
);
364 ovsdb_row_hash_contains(const struct ovsdb_row_hash
*rh
,
365 const struct ovsdb_row
*row
)
367 size_t hash
= ovsdb_row_hash_columns(row
, &rh
->columns
, 0);
368 return ovsdb_row_hash_contains__(rh
, row
, hash
);
371 /* Returns true if every row in 'b' has an equal row in 'a'. */
373 ovsdb_row_hash_contains_all(const struct ovsdb_row_hash
*a
,
374 const struct ovsdb_row_hash
*b
)
376 struct ovsdb_row_hash_node
*node
;
378 ovs_assert(ovsdb_column_set_equals(&a
->columns
, &b
->columns
));
379 HMAP_FOR_EACH (node
, hmap_node
, &b
->rows
) {
380 if (!ovsdb_row_hash_contains__(a
, node
->row
, node
->hmap_node
.hash
)) {
388 ovsdb_row_hash_insert(struct ovsdb_row_hash
*rh
, const struct ovsdb_row
*row
)
390 size_t hash
= ovsdb_row_hash_columns(row
, &rh
->columns
, 0);
391 return ovsdb_row_hash_insert__(rh
, row
, hash
);
395 ovsdb_row_hash_contains__(const struct ovsdb_row_hash
*rh
,
396 const struct ovsdb_row
*row
, size_t hash
)
398 struct ovsdb_row_hash_node
*node
;
399 HMAP_FOR_EACH_WITH_HASH (node
, hmap_node
, hash
, &rh
->rows
) {
400 if (ovsdb_row_equal_columns(row
, node
->row
, &rh
->columns
)) {
408 ovsdb_row_hash_insert__(struct ovsdb_row_hash
*rh
, const struct ovsdb_row
*row
,
411 if (!ovsdb_row_hash_contains__(rh
, row
, hash
)) {
412 struct ovsdb_row_hash_node
*node
= xmalloc(sizeof *node
);
414 hmap_insert(&rh
->rows
, &node
->hmap_node
, hash
);