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