ovsdb-idl: Add "safe" iterator macro to generated code.
[sliver-openvswitch.git] / ovsdb / row.c
1 /* Copyright (c) 2009, 2010 Nicira Networks
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
20 #include <assert.h>
21 #include <stddef.h>
22
23 #include "json.h"
24 #include "ovsdb-error.h"
25 #include "shash.h"
26 #include "sort.h"
27 #include "table.h"
28
29 static struct ovsdb_row *
30 allocate_row(const struct ovsdb_table *table)
31 {
32     size_t n_fields = shash_count(&table->schema->columns);
33     size_t row_size = (offsetof(struct ovsdb_row, fields)
34                        + sizeof(struct ovsdb_datum) * n_fields);
35     struct ovsdb_row *row = xmalloc(row_size);
36     row->table = (struct ovsdb_table *) table;
37     row->txn_row = NULL;
38     list_init(&row->src_refs);
39     list_init(&row->dst_refs);
40     row->n_refs = 0;
41     return row;
42 }
43
44 struct ovsdb_row *
45 ovsdb_row_create(const struct ovsdb_table *table)
46 {
47     struct shash_node *node;
48     struct ovsdb_row *row;
49
50     row = allocate_row(table);
51     SHASH_FOR_EACH (node, &table->schema->columns) {
52         const struct ovsdb_column *column = node->data;
53         ovsdb_datum_init_default(&row->fields[column->index], &column->type);
54     }
55     return row;
56 }
57
58 struct ovsdb_row *
59 ovsdb_row_clone(const struct ovsdb_row *old)
60 {
61     const struct ovsdb_table *table = old->table;
62     const struct shash_node *node;
63     struct ovsdb_row *new;
64
65     new = allocate_row(table);
66     SHASH_FOR_EACH (node, &table->schema->columns) {
67         const struct ovsdb_column *column = node->data;
68         ovsdb_datum_clone(&new->fields[column->index],
69                           &old->fields[column->index],
70                           &column->type);
71     }
72     return new;
73 }
74
75 /* The caller is responsible for ensuring that 'row' has been removed from its
76  * table and that it is not participating in a transaction. */
77 void
78 ovsdb_row_destroy(struct ovsdb_row *row)
79 {
80     if (row) {
81         const struct ovsdb_table *table = row->table;
82         struct ovsdb_weak_ref *weak, *next;
83         const struct shash_node *node;
84
85         LIST_FOR_EACH_SAFE (weak, next, struct ovsdb_weak_ref, dst_node,
86                             &row->dst_refs) {
87             list_remove(&weak->src_node);
88             list_remove(&weak->dst_node);
89             free(weak);
90         }
91
92         LIST_FOR_EACH_SAFE (weak, next, struct ovsdb_weak_ref, src_node,
93                             &row->src_refs) {
94             list_remove(&weak->src_node);
95             list_remove(&weak->dst_node);
96             free(weak);
97         }
98
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
107 uint32_t
108 ovsdb_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
123 int
124 ovsdb_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
143 bool
144 ovsdb_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
162 void
163 ovsdb_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
178 struct ovsdb_error *
179 ovsdb_row_from_json(struct ovsdb_row *row, const struct json *json,
180                     struct ovsdb_symbol_table *symtab,
181                     struct ovsdb_column_set *included)
182 {
183     struct ovsdb_table_schema *schema = row->table->schema;
184     struct ovsdb_error *error;
185     struct shash_node *node;
186
187     if (json->type != JSON_OBJECT) {
188         return ovsdb_syntax_error(json, NULL, "row must be JSON object");
189     }
190
191     SHASH_FOR_EACH (node, json_object(json)) {
192         const char *column_name = node->name;
193         const struct ovsdb_column *column;
194         struct ovsdb_datum datum;
195
196         column = ovsdb_table_schema_get_column(schema, column_name);
197         if (!column) {
198             return ovsdb_syntax_error(json, "unknown column",
199                                       "No column %s in table %s.",
200                                       column_name, schema->name);
201         }
202
203         error = ovsdb_datum_from_json(&datum, &column->type, node->data,
204                                       symtab);
205         if (error) {
206             return error;
207         }
208         ovsdb_datum_swap(&row->fields[column->index], &datum);
209         ovsdb_datum_destroy(&datum, &column->type);
210         if (included) {
211             ovsdb_column_set_add(included, column);
212         }
213     }
214
215     return NULL;
216 }
217
218 static void
219 put_json_column(struct json *object, const struct ovsdb_row *row,
220                 const struct ovsdb_column *column)
221 {
222     json_object_put(object, column->name,
223                     ovsdb_datum_to_json(&row->fields[column->index],
224                                         &column->type));
225 }
226
227 struct json *
228 ovsdb_row_to_json(const struct ovsdb_row *row,
229                   const struct ovsdb_column_set *columns)
230 {
231     struct json *json;
232     size_t i;
233
234     json = json_object_create();
235     for (i = 0; i < columns->n_columns; i++) {
236         put_json_column(json, row, columns->columns[i]);
237     }
238     return json;
239 }
240 \f
241 void
242 ovsdb_row_set_init(struct ovsdb_row_set *set)
243 {
244     set->rows = NULL;
245     set->n_rows = set->allocated_rows = 0;
246 }
247
248 void
249 ovsdb_row_set_destroy(struct ovsdb_row_set *set)
250 {
251     free(set->rows);
252 }
253
254 void
255 ovsdb_row_set_add_row(struct ovsdb_row_set *set, const struct ovsdb_row *row)
256 {
257     if (set->n_rows >= set->allocated_rows) {
258         set->rows = x2nrealloc(set->rows, &set->allocated_rows,
259                                sizeof *set->rows);
260     }
261     set->rows[set->n_rows++] = row;
262 }
263
264 struct json *
265 ovsdb_row_set_to_json(const struct ovsdb_row_set *rows,
266                       const struct ovsdb_column_set *columns)
267 {
268     struct json **json_rows;
269     size_t i;
270
271     json_rows = xmalloc(rows->n_rows * sizeof *json_rows);
272     for (i = 0; i < rows->n_rows; i++) {
273         json_rows[i] = ovsdb_row_to_json(rows->rows[i], columns);
274     }
275     return json_array_create(json_rows, rows->n_rows);
276 }
277
278 struct ovsdb_row_set_sort_cbdata {
279     struct ovsdb_row_set *set;
280     const struct ovsdb_column_set *columns;
281 };
282
283 static int
284 ovsdb_row_set_sort_compare_cb(size_t a, size_t b, void *cbdata_)
285 {
286     struct ovsdb_row_set_sort_cbdata *cbdata = cbdata_;
287     return ovsdb_row_compare_columns_3way(cbdata->set->rows[a],
288                                           cbdata->set->rows[b],
289                                           cbdata->columns);
290 }
291
292 static void
293 ovsdb_row_set_sort_swap_cb(size_t a, size_t b, void *cbdata_)
294 {
295     struct ovsdb_row_set_sort_cbdata *cbdata = cbdata_;
296     const struct ovsdb_row *tmp = cbdata->set->rows[a];
297     cbdata->set->rows[a] = cbdata->set->rows[b];
298     cbdata->set->rows[b] = tmp;
299 }
300
301 void
302 ovsdb_row_set_sort(struct ovsdb_row_set *set,
303                    const struct ovsdb_column_set *columns)
304 {
305     if (columns && columns->n_columns && set->n_rows > 1) {
306         struct ovsdb_row_set_sort_cbdata cbdata;
307         cbdata.set = set;
308         cbdata.columns = columns;
309         sort(set->n_rows,
310              ovsdb_row_set_sort_compare_cb,
311              ovsdb_row_set_sort_swap_cb,
312              &cbdata);
313     }
314 }
315 \f
316 void
317 ovsdb_row_hash_init(struct ovsdb_row_hash *rh,
318                     const struct ovsdb_column_set *columns)
319 {
320     hmap_init(&rh->rows);
321     ovsdb_column_set_clone(&rh->columns, columns);
322 }
323
324 void
325 ovsdb_row_hash_destroy(struct ovsdb_row_hash *rh, bool destroy_rows)
326 {
327     struct ovsdb_row_hash_node *node, *next;
328
329     HMAP_FOR_EACH_SAFE (node, next, struct ovsdb_row_hash_node, hmap_node,
330                         &rh->rows) {
331         hmap_remove(&rh->rows, &node->hmap_node);
332         if (destroy_rows) {
333             ovsdb_row_destroy((struct ovsdb_row *) node->row);
334         }
335         free(node);
336     }
337     hmap_destroy(&rh->rows);
338     ovsdb_column_set_destroy(&rh->columns);
339 }
340
341 size_t
342 ovsdb_row_hash_count(const struct ovsdb_row_hash *rh)
343 {
344     return hmap_count(&rh->rows);
345 }
346
347 bool
348 ovsdb_row_hash_contains(const struct ovsdb_row_hash *rh,
349                         const struct ovsdb_row *row)
350 {
351     size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
352     return ovsdb_row_hash_contains__(rh, row, hash);
353 }
354
355 /* Returns true if every row in 'b' has an equal row in 'a'. */
356 bool
357 ovsdb_row_hash_contains_all(const struct ovsdb_row_hash *a,
358                             const struct ovsdb_row_hash *b)
359 {
360     struct ovsdb_row_hash_node *node;
361
362     assert(ovsdb_column_set_equals(&a->columns, &b->columns));
363     HMAP_FOR_EACH (node, struct ovsdb_row_hash_node, hmap_node, &b->rows) {
364         if (!ovsdb_row_hash_contains__(a, node->row, node->hmap_node.hash)) {
365             return false;
366         }
367     }
368     return true;
369 }
370
371 bool
372 ovsdb_row_hash_insert(struct ovsdb_row_hash *rh, const struct ovsdb_row *row)
373 {
374     size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
375     return ovsdb_row_hash_insert__(rh, row, hash);
376 }
377
378 bool
379 ovsdb_row_hash_contains__(const struct ovsdb_row_hash *rh,
380                           const struct ovsdb_row *row, size_t hash)
381 {
382     struct ovsdb_row_hash_node *node;
383     HMAP_FOR_EACH_WITH_HASH (node, struct ovsdb_row_hash_node, hmap_node,
384                              hash, &rh->rows) {
385         if (ovsdb_row_equal_columns(row, node->row, &rh->columns)) {
386             return true;
387         }
388     }
389     return false;
390 }
391
392 bool
393 ovsdb_row_hash_insert__(struct ovsdb_row_hash *rh, const struct ovsdb_row *row,
394                         size_t hash)
395 {
396     if (!ovsdb_row_hash_contains__(rh, row, hash)) {
397         struct ovsdb_row_hash_node *node = xmalloc(sizeof *node);
398         node->row = row;
399         hmap_insert(&rh->rows, &node->hmap_node, hash);
400         return true;
401     } else {
402         return false;
403     }
404 }