]> git.proxmox.com Git - ovs.git/blame - ovsdb/row.c
Move lib/dynamic-string.h to include/openvswitch directory
[ovs.git] / ovsdb / row.c
CommitLineData
ebc56baa 1/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
f85f8ebb
BP
2 *
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:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
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.
14 */
15
16#include <config.h>
17
18#include "row.h"
19
f85f8ebb
BP
20#include <stddef.h>
21
3e8a2ad1 22#include "openvswitch/dynamic-string.h"
f85f8ebb
BP
23#include "json.h"
24#include "ovsdb-error.h"
25#include "shash.h"
26#include "sort.h"
27#include "table.h"
28
29static struct ovsdb_row *
30allocate_row(const struct ovsdb_table *table)
31{
32 size_t n_fields = shash_count(&table->schema->columns);
6910a6e6 33 size_t n_indexes = table->schema->n_indexes;
f85f8ebb 34 size_t row_size = (offsetof(struct ovsdb_row, fields)
6910a6e6
BP
35 + sizeof(struct ovsdb_datum) * n_fields
36 + sizeof(struct hmap_node) * n_indexes);
f85f8ebb 37 struct ovsdb_row *row = xmalloc(row_size);
ebc56baa 38 row->table = CONST_CAST(struct ovsdb_table *, table);
f85f8ebb 39 row->txn_row = NULL;
7360012b
BP
40 list_init(&row->src_refs);
41 list_init(&row->dst_refs);
0d0f05b9 42 row->n_refs = 0;
f85f8ebb
BP
43 return row;
44}
45
46struct ovsdb_row *
47ovsdb_row_create(const struct ovsdb_table *table)
48{
49 struct shash_node *node;
50 struct ovsdb_row *row;
51
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);
56 }
57 return row;
58}
59
60struct ovsdb_row *
61ovsdb_row_clone(const struct ovsdb_row *old)
62{
63 const struct ovsdb_table *table = old->table;
64 const struct shash_node *node;
65 struct ovsdb_row *new;
66
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],
72 &column->type);
73 }
74 return new;
75}
76
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. */
79void
80ovsdb_row_destroy(struct ovsdb_row *row)
81{
82 if (row) {
83 const struct ovsdb_table *table = row->table;
7360012b 84 struct ovsdb_weak_ref *weak, *next;
f85f8ebb
BP
85 const struct shash_node *node;
86
4e8e4213 87 LIST_FOR_EACH_SAFE (weak, next, dst_node, &row->dst_refs) {
7360012b
BP
88 list_remove(&weak->src_node);
89 list_remove(&weak->dst_node);
90 free(weak);
91 }
92
4e8e4213 93 LIST_FOR_EACH_SAFE (weak, next, src_node, &row->src_refs) {
7360012b
BP
94 list_remove(&weak->src_node);
95 list_remove(&weak->dst_node);
96 free(weak);
97 }
98
f85f8ebb
BP
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);
102 }
103 free(row);
104 }
105}
106
107uint32_t
108ovsdb_row_hash_columns(const struct ovsdb_row *row,
109 const struct ovsdb_column_set *columns,
110 uint32_t basis)
111{
112 size_t i;
113
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,
117 basis);
118 }
119
120 return basis;
121}
122
123int
124ovsdb_row_compare_columns_3way(const struct ovsdb_row *a,
125 const struct ovsdb_row *b,
126 const struct ovsdb_column_set *columns)
127{
128 size_t i;
129
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],
134 &column->type);
135 if (cmp) {
136 return cmp;
137 }
138 }
139
140 return 0;
141}
142
143bool
144ovsdb_row_equal_columns(const struct ovsdb_row *a,
145 const struct ovsdb_row *b,
146 const struct ovsdb_column_set *columns)
147{
148 size_t i;
149
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],
154 &column->type)) {
155 return false;
156 }
157 }
158
159 return true;
160}
161
162void
163ovsdb_row_update_columns(struct ovsdb_row *dst,
164 const struct ovsdb_row *src,
165 const struct ovsdb_column_set *columns)
166{
167 size_t i;
168
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],
174 &column->type);
175 }
176}
177
25d49835
BP
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]". */
180void
181ovsdb_row_columns_to_string(const struct ovsdb_row *row,
182 const struct ovsdb_column_set *columns,
183 struct ds *out)
184{
185 size_t i;
186
187 for (i = 0; i < columns->n_columns; i++) {
188 const struct ovsdb_column *column = columns->columns[i];
189
190 ds_put_cstr(out, english_list_delimiter(i, columns->n_columns));
191 ovsdb_datum_to_string(&row->fields[column->index], &column->type, out);
192 }
193}
194
f85f8ebb
BP
195struct ovsdb_error *
196ovsdb_row_from_json(struct ovsdb_row *row, const struct json *json,
fbf925e4 197 struct ovsdb_symbol_table *symtab,
f85f8ebb
BP
198 struct ovsdb_column_set *included)
199{
200 struct ovsdb_table_schema *schema = row->table->schema;
201 struct ovsdb_error *error;
202 struct shash_node *node;
203
204 if (json->type != JSON_OBJECT) {
205 return ovsdb_syntax_error(json, NULL, "row must be JSON object");
206 }
207
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;
212
213 column = ovsdb_table_schema_get_column(schema, column_name);
214 if (!column) {
215 return ovsdb_syntax_error(json, "unknown column",
216 "No column %s in table %s.",
217 column_name, schema->name);
218 }
219
220 error = ovsdb_datum_from_json(&datum, &column->type, node->data,
221 symtab);
222 if (error) {
223 return error;
224 }
225 ovsdb_datum_swap(&row->fields[column->index], &datum);
226 ovsdb_datum_destroy(&datum, &column->type);
227 if (included) {
228 ovsdb_column_set_add(included, column);
229 }
230 }
231
232 return NULL;
233}
234
235static void
236put_json_column(struct json *object, const struct ovsdb_row *row,
237 const struct ovsdb_column *column)
238{
239 json_object_put(object, column->name,
240 ovsdb_datum_to_json(&row->fields[column->index],
241 &column->type));
242}
243
244struct json *
245ovsdb_row_to_json(const struct ovsdb_row *row,
246 const struct ovsdb_column_set *columns)
247{
248 struct json *json;
249 size_t i;
250
251 json = json_object_create();
252 for (i = 0; i < columns->n_columns; i++) {
253 put_json_column(json, row, columns->columns[i]);
254 }
255 return json;
256}
257\f
258void
259ovsdb_row_set_init(struct ovsdb_row_set *set)
260{
261 set->rows = NULL;
262 set->n_rows = set->allocated_rows = 0;
263}
264
265void
266ovsdb_row_set_destroy(struct ovsdb_row_set *set)
267{
268 free(set->rows);
269}
270
271void
272ovsdb_row_set_add_row(struct ovsdb_row_set *set, const struct ovsdb_row *row)
273{
274 if (set->n_rows >= set->allocated_rows) {
275 set->rows = x2nrealloc(set->rows, &set->allocated_rows,
276 sizeof *set->rows);
277 }
278 set->rows[set->n_rows++] = row;
279}
280
281struct json *
282ovsdb_row_set_to_json(const struct ovsdb_row_set *rows,
283 const struct ovsdb_column_set *columns)
284{
285 struct json **json_rows;
286 size_t i;
287
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);
291 }
292 return json_array_create(json_rows, rows->n_rows);
293}
294
295struct ovsdb_row_set_sort_cbdata {
296 struct ovsdb_row_set *set;
297 const struct ovsdb_column_set *columns;
298};
299
300static int
301ovsdb_row_set_sort_compare_cb(size_t a, size_t b, void *cbdata_)
302{
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],
306 cbdata->columns);
307}
308
309static void
310ovsdb_row_set_sort_swap_cb(size_t a, size_t b, void *cbdata_)
311{
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;
316}
317
318void
319ovsdb_row_set_sort(struct ovsdb_row_set *set,
320 const struct ovsdb_column_set *columns)
321{
322 if (columns && columns->n_columns && set->n_rows > 1) {
323 struct ovsdb_row_set_sort_cbdata cbdata;
324 cbdata.set = set;
325 cbdata.columns = columns;
326 sort(set->n_rows,
327 ovsdb_row_set_sort_compare_cb,
328 ovsdb_row_set_sort_swap_cb,
329 &cbdata);
330 }
331}
332\f
333void
334ovsdb_row_hash_init(struct ovsdb_row_hash *rh,
335 const struct ovsdb_column_set *columns)
336{
337 hmap_init(&rh->rows);
338 ovsdb_column_set_clone(&rh->columns, columns);
339}
340
341void
342ovsdb_row_hash_destroy(struct ovsdb_row_hash *rh, bool destroy_rows)
343{
344 struct ovsdb_row_hash_node *node, *next;
345
4e8e4213 346 HMAP_FOR_EACH_SAFE (node, next, hmap_node, &rh->rows) {
f85f8ebb
BP
347 hmap_remove(&rh->rows, &node->hmap_node);
348 if (destroy_rows) {
ebc56baa 349 ovsdb_row_destroy(CONST_CAST(struct ovsdb_row *, node->row));
f85f8ebb
BP
350 }
351 free(node);
352 }
353 hmap_destroy(&rh->rows);
354 ovsdb_column_set_destroy(&rh->columns);
355}
356
357size_t
358ovsdb_row_hash_count(const struct ovsdb_row_hash *rh)
359{
360 return hmap_count(&rh->rows);
361}
362
363bool
364ovsdb_row_hash_contains(const struct ovsdb_row_hash *rh,
365 const struct ovsdb_row *row)
366{
367 size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
368 return ovsdb_row_hash_contains__(rh, row, hash);
369}
370
371/* Returns true if every row in 'b' has an equal row in 'a'. */
372bool
373ovsdb_row_hash_contains_all(const struct ovsdb_row_hash *a,
374 const struct ovsdb_row_hash *b)
375{
376 struct ovsdb_row_hash_node *node;
377
cb22974d 378 ovs_assert(ovsdb_column_set_equals(&a->columns, &b->columns));
4e8e4213 379 HMAP_FOR_EACH (node, hmap_node, &b->rows) {
f85f8ebb
BP
380 if (!ovsdb_row_hash_contains__(a, node->row, node->hmap_node.hash)) {
381 return false;
382 }
383 }
384 return true;
385}
386
387bool
388ovsdb_row_hash_insert(struct ovsdb_row_hash *rh, const struct ovsdb_row *row)
389{
390 size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
391 return ovsdb_row_hash_insert__(rh, row, hash);
392}
393
394bool
395ovsdb_row_hash_contains__(const struct ovsdb_row_hash *rh,
396 const struct ovsdb_row *row, size_t hash)
397{
398 struct ovsdb_row_hash_node *node;
4e8e4213 399 HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash, &rh->rows) {
f85f8ebb
BP
400 if (ovsdb_row_equal_columns(row, node->row, &rh->columns)) {
401 return true;
402 }
403 }
404 return false;
405}
406
407bool
408ovsdb_row_hash_insert__(struct ovsdb_row_hash *rh, const struct ovsdb_row *row,
409 size_t hash)
410{
411 if (!ovsdb_row_hash_contains__(rh, row, hash)) {
412 struct ovsdb_row_hash_node *node = xmalloc(sizeof *node);
413 node->row = row;
414 hmap_insert(&rh->rows, &node->hmap_node, hash);
415 return true;
416 } else {
417 return false;
418 }
419}