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.
23 #include "dynamic-string.h"
25 #include "ovsdb-error.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 list_init(&row
->src_refs
);
42 list_init(&row
->dst_refs
);
48 ovsdb_row_create(const struct ovsdb_table
*table
)
50 struct shash_node
*node
;
51 struct ovsdb_row
*row
;
53 row
= allocate_row(table
);
54 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
55 const struct ovsdb_column
*column
= node
->data
;
56 ovsdb_datum_init_default(&row
->fields
[column
->index
], &column
->type
);
62 ovsdb_row_clone(const struct ovsdb_row
*old
)
64 const struct ovsdb_table
*table
= old
->table
;
65 const struct shash_node
*node
;
66 struct ovsdb_row
*new;
68 new = allocate_row(table
);
69 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
70 const struct ovsdb_column
*column
= node
->data
;
71 ovsdb_datum_clone(&new->fields
[column
->index
],
72 &old
->fields
[column
->index
],
78 /* The caller is responsible for ensuring that 'row' has been removed from its
79 * table and that it is not participating in a transaction. */
81 ovsdb_row_destroy(struct ovsdb_row
*row
)
84 const struct ovsdb_table
*table
= row
->table
;
85 struct ovsdb_weak_ref
*weak
, *next
;
86 const struct shash_node
*node
;
88 LIST_FOR_EACH_SAFE (weak
, next
, dst_node
, &row
->dst_refs
) {
89 list_remove(&weak
->src_node
);
90 list_remove(&weak
->dst_node
);
94 LIST_FOR_EACH_SAFE (weak
, next
, src_node
, &row
->src_refs
) {
95 list_remove(&weak
->src_node
);
96 list_remove(&weak
->dst_node
);
100 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
101 const struct ovsdb_column
*column
= node
->data
;
102 ovsdb_datum_destroy(&row
->fields
[column
->index
], &column
->type
);
109 ovsdb_row_hash_columns(const struct ovsdb_row
*row
,
110 const struct ovsdb_column_set
*columns
,
115 for (i
= 0; i
< columns
->n_columns
; i
++) {
116 const struct ovsdb_column
*column
= columns
->columns
[i
];
117 basis
= ovsdb_datum_hash(&row
->fields
[column
->index
], &column
->type
,
125 ovsdb_row_compare_columns_3way(const struct ovsdb_row
*a
,
126 const struct ovsdb_row
*b
,
127 const struct ovsdb_column_set
*columns
)
131 for (i
= 0; i
< columns
->n_columns
; i
++) {
132 const struct ovsdb_column
*column
= columns
->columns
[i
];
133 int cmp
= ovsdb_datum_compare_3way(&a
->fields
[column
->index
],
134 &b
->fields
[column
->index
],
145 ovsdb_row_equal_columns(const struct ovsdb_row
*a
,
146 const struct ovsdb_row
*b
,
147 const struct ovsdb_column_set
*columns
)
151 for (i
= 0; i
< columns
->n_columns
; i
++) {
152 const struct ovsdb_column
*column
= columns
->columns
[i
];
153 if (!ovsdb_datum_equals(&a
->fields
[column
->index
],
154 &b
->fields
[column
->index
],
164 ovsdb_row_update_columns(struct ovsdb_row
*dst
,
165 const struct ovsdb_row
*src
,
166 const struct ovsdb_column_set
*columns
)
170 for (i
= 0; i
< columns
->n_columns
; i
++) {
171 const struct ovsdb_column
*column
= columns
->columns
[i
];
172 ovsdb_datum_destroy(&dst
->fields
[column
->index
], &column
->type
);
173 ovsdb_datum_clone(&dst
->fields
[column
->index
],
174 &src
->fields
[column
->index
],
179 /* Appends the string form of the value in 'row' of each of the columns in
180 * 'columns' to 'out', e.g. "1, \"xyz\", and [1, 2, 3]". */
182 ovsdb_row_columns_to_string(const struct ovsdb_row
*row
,
183 const struct ovsdb_column_set
*columns
,
188 for (i
= 0; i
< columns
->n_columns
; i
++) {
189 const struct ovsdb_column
*column
= columns
->columns
[i
];
191 ds_put_cstr(out
, english_list_delimiter(i
, columns
->n_columns
));
192 ovsdb_datum_to_string(&row
->fields
[column
->index
], &column
->type
, out
);
197 ovsdb_row_from_json(struct ovsdb_row
*row
, const struct json
*json
,
198 struct ovsdb_symbol_table
*symtab
,
199 struct ovsdb_column_set
*included
)
201 struct ovsdb_table_schema
*schema
= row
->table
->schema
;
202 struct ovsdb_error
*error
;
203 struct shash_node
*node
;
205 if (json
->type
!= JSON_OBJECT
) {
206 return ovsdb_syntax_error(json
, NULL
, "row must be JSON object");
209 SHASH_FOR_EACH (node
, json_object(json
)) {
210 const char *column_name
= node
->name
;
211 const struct ovsdb_column
*column
;
212 struct ovsdb_datum datum
;
214 column
= ovsdb_table_schema_get_column(schema
, column_name
);
216 return ovsdb_syntax_error(json
, "unknown column",
217 "No column %s in table %s.",
218 column_name
, schema
->name
);
221 error
= ovsdb_datum_from_json(&datum
, &column
->type
, node
->data
,
226 ovsdb_datum_swap(&row
->fields
[column
->index
], &datum
);
227 ovsdb_datum_destroy(&datum
, &column
->type
);
229 ovsdb_column_set_add(included
, column
);
237 put_json_column(struct json
*object
, const struct ovsdb_row
*row
,
238 const struct ovsdb_column
*column
)
240 json_object_put(object
, column
->name
,
241 ovsdb_datum_to_json(&row
->fields
[column
->index
],
246 ovsdb_row_to_json(const struct ovsdb_row
*row
,
247 const struct ovsdb_column_set
*columns
)
252 json
= json_object_create();
253 for (i
= 0; i
< columns
->n_columns
; i
++) {
254 put_json_column(json
, row
, columns
->columns
[i
]);
260 ovsdb_row_set_init(struct ovsdb_row_set
*set
)
263 set
->n_rows
= set
->allocated_rows
= 0;
267 ovsdb_row_set_destroy(struct ovsdb_row_set
*set
)
273 ovsdb_row_set_add_row(struct ovsdb_row_set
*set
, const struct ovsdb_row
*row
)
275 if (set
->n_rows
>= set
->allocated_rows
) {
276 set
->rows
= x2nrealloc(set
->rows
, &set
->allocated_rows
,
279 set
->rows
[set
->n_rows
++] = row
;
283 ovsdb_row_set_to_json(const struct ovsdb_row_set
*rows
,
284 const struct ovsdb_column_set
*columns
)
286 struct json
**json_rows
;
289 json_rows
= xmalloc(rows
->n_rows
* sizeof *json_rows
);
290 for (i
= 0; i
< rows
->n_rows
; i
++) {
291 json_rows
[i
] = ovsdb_row_to_json(rows
->rows
[i
], columns
);
293 return json_array_create(json_rows
, rows
->n_rows
);
296 struct ovsdb_row_set_sort_cbdata
{
297 struct ovsdb_row_set
*set
;
298 const struct ovsdb_column_set
*columns
;
302 ovsdb_row_set_sort_compare_cb(size_t a
, size_t b
, void *cbdata_
)
304 struct ovsdb_row_set_sort_cbdata
*cbdata
= cbdata_
;
305 return ovsdb_row_compare_columns_3way(cbdata
->set
->rows
[a
],
306 cbdata
->set
->rows
[b
],
311 ovsdb_row_set_sort_swap_cb(size_t a
, size_t b
, void *cbdata_
)
313 struct ovsdb_row_set_sort_cbdata
*cbdata
= cbdata_
;
314 const struct ovsdb_row
*tmp
= cbdata
->set
->rows
[a
];
315 cbdata
->set
->rows
[a
] = cbdata
->set
->rows
[b
];
316 cbdata
->set
->rows
[b
] = tmp
;
320 ovsdb_row_set_sort(struct ovsdb_row_set
*set
,
321 const struct ovsdb_column_set
*columns
)
323 if (columns
&& columns
->n_columns
&& set
->n_rows
> 1) {
324 struct ovsdb_row_set_sort_cbdata cbdata
;
326 cbdata
.columns
= columns
;
328 ovsdb_row_set_sort_compare_cb
,
329 ovsdb_row_set_sort_swap_cb
,
335 ovsdb_row_hash_init(struct ovsdb_row_hash
*rh
,
336 const struct ovsdb_column_set
*columns
)
338 hmap_init(&rh
->rows
);
339 ovsdb_column_set_clone(&rh
->columns
, columns
);
343 ovsdb_row_hash_destroy(struct ovsdb_row_hash
*rh
, bool destroy_rows
)
345 struct ovsdb_row_hash_node
*node
, *next
;
347 HMAP_FOR_EACH_SAFE (node
, next
, hmap_node
, &rh
->rows
) {
348 hmap_remove(&rh
->rows
, &node
->hmap_node
);
350 ovsdb_row_destroy(CONST_CAST(struct ovsdb_row
*, node
->row
));
354 hmap_destroy(&rh
->rows
);
355 ovsdb_column_set_destroy(&rh
->columns
);
359 ovsdb_row_hash_count(const struct ovsdb_row_hash
*rh
)
361 return hmap_count(&rh
->rows
);
365 ovsdb_row_hash_contains(const struct ovsdb_row_hash
*rh
,
366 const struct ovsdb_row
*row
)
368 size_t hash
= ovsdb_row_hash_columns(row
, &rh
->columns
, 0);
369 return ovsdb_row_hash_contains__(rh
, row
, hash
);
372 /* Returns true if every row in 'b' has an equal row in 'a'. */
374 ovsdb_row_hash_contains_all(const struct ovsdb_row_hash
*a
,
375 const struct ovsdb_row_hash
*b
)
377 struct ovsdb_row_hash_node
*node
;
379 assert(ovsdb_column_set_equals(&a
->columns
, &b
->columns
));
380 HMAP_FOR_EACH (node
, hmap_node
, &b
->rows
) {
381 if (!ovsdb_row_hash_contains__(a
, node
->row
, node
->hmap_node
.hash
)) {
389 ovsdb_row_hash_insert(struct ovsdb_row_hash
*rh
, const struct ovsdb_row
*row
)
391 size_t hash
= ovsdb_row_hash_columns(row
, &rh
->columns
, 0);
392 return ovsdb_row_hash_insert__(rh
, row
, hash
);
396 ovsdb_row_hash_contains__(const struct ovsdb_row_hash
*rh
,
397 const struct ovsdb_row
*row
, size_t hash
)
399 struct ovsdb_row_hash_node
*node
;
400 HMAP_FOR_EACH_WITH_HASH (node
, hmap_node
, hash
, &rh
->rows
) {
401 if (ovsdb_row_equal_columns(row
, node
->row
, &rh
->columns
)) {
409 ovsdb_row_hash_insert__(struct ovsdb_row_hash
*rh
, const struct ovsdb_row
*row
,
412 if (!ovsdb_row_hash_contains__(rh
, row
, hash
)) {
413 struct ovsdb_row_hash_node
*node
= xmalloc(sizeof *node
);
415 hmap_insert(&rh
->rows
, &node
->hmap_node
, hash
);