ovsdb: Get rid of "declare" operation.
[cascardo/ovs.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     row->n_refs = 0;
39     return row;
40 }
41
42 struct ovsdb_row *
43 ovsdb_row_create(const struct ovsdb_table *table)
44 {
45     struct shash_node *node;
46     struct ovsdb_row *row;
47
48     row = allocate_row(table);
49     SHASH_FOR_EACH (node, &table->schema->columns) {
50         const struct ovsdb_column *column = node->data;
51         ovsdb_datum_init_default(&row->fields[column->index], &column->type);
52     }
53     return row;
54 }
55
56 struct ovsdb_row *
57 ovsdb_row_clone(const struct ovsdb_row *old)
58 {
59     const struct ovsdb_table *table = old->table;
60     const struct shash_node *node;
61     struct ovsdb_row *new;
62
63     new = allocate_row(table);
64     SHASH_FOR_EACH (node, &table->schema->columns) {
65         const struct ovsdb_column *column = node->data;
66         ovsdb_datum_clone(&new->fields[column->index],
67                           &old->fields[column->index],
68                           &column->type);
69     }
70     return new;
71 }
72
73 /* The caller is responsible for ensuring that 'row' has been removed from its
74  * table and that it is not participating in a transaction. */
75 void
76 ovsdb_row_destroy(struct ovsdb_row *row)
77 {
78     if (row) {
79         const struct ovsdb_table *table = row->table;
80         const struct shash_node *node;
81
82         SHASH_FOR_EACH (node, &table->schema->columns) {
83             const struct ovsdb_column *column = node->data;
84             ovsdb_datum_destroy(&row->fields[column->index], &column->type);
85         }
86         free(row);
87     }
88 }
89
90 uint32_t
91 ovsdb_row_hash_columns(const struct ovsdb_row *row,
92                        const struct ovsdb_column_set *columns,
93                        uint32_t basis)
94 {
95     size_t i;
96
97     for (i = 0; i < columns->n_columns; i++) {
98         const struct ovsdb_column *column = columns->columns[i];
99         basis = ovsdb_datum_hash(&row->fields[column->index], &column->type,
100                                  basis);
101     }
102
103     return basis;
104 }
105
106 int
107 ovsdb_row_compare_columns_3way(const struct ovsdb_row *a,
108                                const struct ovsdb_row *b,
109                                const struct ovsdb_column_set *columns)
110 {
111     size_t i;
112
113     for (i = 0; i < columns->n_columns; i++) {
114         const struct ovsdb_column *column = columns->columns[i];
115         int cmp = ovsdb_datum_compare_3way(&a->fields[column->index],
116                                            &b->fields[column->index],
117                                            &column->type);
118         if (cmp) {
119             return cmp;
120         }
121     }
122
123     return 0;
124 }
125
126 bool
127 ovsdb_row_equal_columns(const struct ovsdb_row *a,
128                         const struct ovsdb_row *b,
129                         const struct ovsdb_column_set *columns)
130 {
131     size_t i;
132
133     for (i = 0; i < columns->n_columns; i++) {
134         const struct ovsdb_column *column = columns->columns[i];
135         if (!ovsdb_datum_equals(&a->fields[column->index],
136                                 &b->fields[column->index],
137                                 &column->type)) {
138             return false;
139         }
140     }
141
142     return true;
143 }
144
145 void
146 ovsdb_row_update_columns(struct ovsdb_row *dst,
147                          const struct ovsdb_row *src,
148                          const struct ovsdb_column_set *columns)
149 {
150     size_t i;
151
152     for (i = 0; i < columns->n_columns; i++) {
153         const struct ovsdb_column *column = columns->columns[i];
154         ovsdb_datum_destroy(&dst->fields[column->index], &column->type);
155         ovsdb_datum_clone(&dst->fields[column->index],
156                           &src->fields[column->index],
157                           &column->type);
158     }
159 }
160
161 struct ovsdb_error *
162 ovsdb_row_from_json(struct ovsdb_row *row, const struct json *json,
163                     struct ovsdb_symbol_table *symtab,
164                     struct ovsdb_column_set *included)
165 {
166     struct ovsdb_table_schema *schema = row->table->schema;
167     struct ovsdb_error *error;
168     struct shash_node *node;
169
170     if (json->type != JSON_OBJECT) {
171         return ovsdb_syntax_error(json, NULL, "row must be JSON object");
172     }
173
174     SHASH_FOR_EACH (node, json_object(json)) {
175         const char *column_name = node->name;
176         const struct ovsdb_column *column;
177         struct ovsdb_datum datum;
178
179         column = ovsdb_table_schema_get_column(schema, column_name);
180         if (!column) {
181             return ovsdb_syntax_error(json, "unknown column",
182                                       "No column %s in table %s.",
183                                       column_name, schema->name);
184         }
185
186         error = ovsdb_datum_from_json(&datum, &column->type, node->data,
187                                       symtab);
188         if (error) {
189             return error;
190         }
191         ovsdb_datum_swap(&row->fields[column->index], &datum);
192         ovsdb_datum_destroy(&datum, &column->type);
193         if (included) {
194             ovsdb_column_set_add(included, column);
195         }
196     }
197
198     return NULL;
199 }
200
201 static void
202 put_json_column(struct json *object, const struct ovsdb_row *row,
203                 const struct ovsdb_column *column)
204 {
205     json_object_put(object, column->name,
206                     ovsdb_datum_to_json(&row->fields[column->index],
207                                         &column->type));
208 }
209
210 struct json *
211 ovsdb_row_to_json(const struct ovsdb_row *row,
212                   const struct ovsdb_column_set *columns)
213 {
214     struct json *json;
215     size_t i;
216
217     json = json_object_create();
218     for (i = 0; i < columns->n_columns; i++) {
219         put_json_column(json, row, columns->columns[i]);
220     }
221     return json;
222 }
223 \f
224 void
225 ovsdb_row_set_init(struct ovsdb_row_set *set)
226 {
227     set->rows = NULL;
228     set->n_rows = set->allocated_rows = 0;
229 }
230
231 void
232 ovsdb_row_set_destroy(struct ovsdb_row_set *set)
233 {
234     free(set->rows);
235 }
236
237 void
238 ovsdb_row_set_add_row(struct ovsdb_row_set *set, const struct ovsdb_row *row)
239 {
240     if (set->n_rows >= set->allocated_rows) {
241         set->rows = x2nrealloc(set->rows, &set->allocated_rows,
242                                sizeof *set->rows);
243     }
244     set->rows[set->n_rows++] = row;
245 }
246
247 struct json *
248 ovsdb_row_set_to_json(const struct ovsdb_row_set *rows,
249                       const struct ovsdb_column_set *columns)
250 {
251     struct json **json_rows;
252     size_t i;
253
254     json_rows = xmalloc(rows->n_rows * sizeof *json_rows);
255     for (i = 0; i < rows->n_rows; i++) {
256         json_rows[i] = ovsdb_row_to_json(rows->rows[i], columns);
257     }
258     return json_array_create(json_rows, rows->n_rows);
259 }
260
261 struct ovsdb_row_set_sort_cbdata {
262     struct ovsdb_row_set *set;
263     const struct ovsdb_column_set *columns;
264 };
265
266 static int
267 ovsdb_row_set_sort_compare_cb(size_t a, size_t b, void *cbdata_)
268 {
269     struct ovsdb_row_set_sort_cbdata *cbdata = cbdata_;
270     return ovsdb_row_compare_columns_3way(cbdata->set->rows[a],
271                                           cbdata->set->rows[b],
272                                           cbdata->columns);
273 }
274
275 static void
276 ovsdb_row_set_sort_swap_cb(size_t a, size_t b, void *cbdata_)
277 {
278     struct ovsdb_row_set_sort_cbdata *cbdata = cbdata_;
279     const struct ovsdb_row *tmp = cbdata->set->rows[a];
280     cbdata->set->rows[a] = cbdata->set->rows[b];
281     cbdata->set->rows[b] = tmp;
282 }
283
284 void
285 ovsdb_row_set_sort(struct ovsdb_row_set *set,
286                    const struct ovsdb_column_set *columns)
287 {
288     if (columns && columns->n_columns && set->n_rows > 1) {
289         struct ovsdb_row_set_sort_cbdata cbdata;
290         cbdata.set = set;
291         cbdata.columns = columns;
292         sort(set->n_rows,
293              ovsdb_row_set_sort_compare_cb,
294              ovsdb_row_set_sort_swap_cb,
295              &cbdata);
296     }
297 }
298 \f
299 void
300 ovsdb_row_hash_init(struct ovsdb_row_hash *rh,
301                     const struct ovsdb_column_set *columns)
302 {
303     hmap_init(&rh->rows);
304     ovsdb_column_set_clone(&rh->columns, columns);
305 }
306
307 void
308 ovsdb_row_hash_destroy(struct ovsdb_row_hash *rh, bool destroy_rows)
309 {
310     struct ovsdb_row_hash_node *node, *next;
311
312     HMAP_FOR_EACH_SAFE (node, next, struct ovsdb_row_hash_node, hmap_node,
313                         &rh->rows) {
314         hmap_remove(&rh->rows, &node->hmap_node);
315         if (destroy_rows) {
316             ovsdb_row_destroy((struct ovsdb_row *) node->row);
317         }
318         free(node);
319     }
320     hmap_destroy(&rh->rows);
321     ovsdb_column_set_destroy(&rh->columns);
322 }
323
324 size_t
325 ovsdb_row_hash_count(const struct ovsdb_row_hash *rh)
326 {
327     return hmap_count(&rh->rows);
328 }
329
330 bool
331 ovsdb_row_hash_contains(const struct ovsdb_row_hash *rh,
332                         const struct ovsdb_row *row)
333 {
334     size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
335     return ovsdb_row_hash_contains__(rh, row, hash);
336 }
337
338 /* Returns true if every row in 'b' has an equal row in 'a'. */
339 bool
340 ovsdb_row_hash_contains_all(const struct ovsdb_row_hash *a,
341                             const struct ovsdb_row_hash *b)
342 {
343     struct ovsdb_row_hash_node *node;
344
345     assert(ovsdb_column_set_equals(&a->columns, &b->columns));
346     HMAP_FOR_EACH (node, struct ovsdb_row_hash_node, hmap_node, &b->rows) {
347         if (!ovsdb_row_hash_contains__(a, node->row, node->hmap_node.hash)) {
348             return false;
349         }
350     }
351     return true;
352 }
353
354 bool
355 ovsdb_row_hash_insert(struct ovsdb_row_hash *rh, const struct ovsdb_row *row)
356 {
357     size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
358     return ovsdb_row_hash_insert__(rh, row, hash);
359 }
360
361 bool
362 ovsdb_row_hash_contains__(const struct ovsdb_row_hash *rh,
363                           const struct ovsdb_row *row, size_t hash)
364 {
365     struct ovsdb_row_hash_node *node;
366     HMAP_FOR_EACH_WITH_HASH (node, struct ovsdb_row_hash_node, hmap_node,
367                              hash, &rh->rows) {
368         if (ovsdb_row_equal_columns(row, node->row, &rh->columns)) {
369             return true;
370         }
371     }
372     return false;
373 }
374
375 bool
376 ovsdb_row_hash_insert__(struct ovsdb_row_hash *rh, const struct ovsdb_row *row,
377                         size_t hash)
378 {
379     if (!ovsdb_row_hash_contains__(rh, row, hash)) {
380         struct ovsdb_row_hash_node *node = xmalloc(sizeof *node);
381         node->row = row;
382         hmap_insert(&rh->rows, &node->hmap_node, hash);
383         return true;
384     } else {
385         return false;
386     }
387 }