]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/row.c
stream: Allow timeout configuration for open_block.
[mirror_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"
ee89ea7b 23#include "openvswitch/json.h"
f85f8ebb 24#include "ovsdb-error.h"
ee89ea7b 25#include "openvswitch/shash.h"
f85f8ebb
BP
26#include "sort.h"
27#include "table.h"
ee89ea7b 28#include "util.h"
f85f8ebb
BP
29
30static struct ovsdb_row *
31allocate_row(const struct ovsdb_table *table)
32{
33 size_t n_fields = shash_count(&table->schema->columns);
6910a6e6 34 size_t n_indexes = table->schema->n_indexes;
f85f8ebb 35 size_t row_size = (offsetof(struct ovsdb_row, fields)
6910a6e6
BP
36 + sizeof(struct ovsdb_datum) * n_fields
37 + sizeof(struct hmap_node) * n_indexes);
f85f8ebb 38 struct ovsdb_row *row = xmalloc(row_size);
ebc56baa 39 row->table = CONST_CAST(struct ovsdb_table *, table);
f85f8ebb 40 row->txn_row = NULL;
417e7e66
BW
41 ovs_list_init(&row->src_refs);
42 ovs_list_init(&row->dst_refs);
0d0f05b9 43 row->n_refs = 0;
f85f8ebb
BP
44 return row;
45}
46
1b1d2e6d
BP
47/* Creates and returns a new row suitable for insertion into 'table'. Does not
48 * actually insert the row into 'table' (use ovsdb_txn_row_insert()). The
49 * caller must assign a UUID to the row. */
f85f8ebb
BP
50struct ovsdb_row *
51ovsdb_row_create(const struct ovsdb_table *table)
52{
53 struct shash_node *node;
54 struct ovsdb_row *row;
55
56 row = allocate_row(table);
57 SHASH_FOR_EACH (node, &table->schema->columns) {
58 const struct ovsdb_column *column = node->data;
59 ovsdb_datum_init_default(&row->fields[column->index], &column->type);
60 }
61 return row;
62}
63
64struct ovsdb_row *
65ovsdb_row_clone(const struct ovsdb_row *old)
66{
67 const struct ovsdb_table *table = old->table;
68 const struct shash_node *node;
69 struct ovsdb_row *new;
70
71 new = allocate_row(table);
72 SHASH_FOR_EACH (node, &table->schema->columns) {
73 const struct ovsdb_column *column = node->data;
74 ovsdb_datum_clone(&new->fields[column->index],
75 &old->fields[column->index],
76 &column->type);
77 }
78 return new;
79}
80
81/* The caller is responsible for ensuring that 'row' has been removed from its
82 * table and that it is not participating in a transaction. */
83void
84ovsdb_row_destroy(struct ovsdb_row *row)
85{
86 if (row) {
87 const struct ovsdb_table *table = row->table;
7360012b 88 struct ovsdb_weak_ref *weak, *next;
f85f8ebb
BP
89 const struct shash_node *node;
90
4e8e4213 91 LIST_FOR_EACH_SAFE (weak, next, dst_node, &row->dst_refs) {
417e7e66
BW
92 ovs_list_remove(&weak->src_node);
93 ovs_list_remove(&weak->dst_node);
7360012b
BP
94 free(weak);
95 }
96
4e8e4213 97 LIST_FOR_EACH_SAFE (weak, next, src_node, &row->src_refs) {
417e7e66
BW
98 ovs_list_remove(&weak->src_node);
99 ovs_list_remove(&weak->dst_node);
7360012b
BP
100 free(weak);
101 }
102
f85f8ebb
BP
103 SHASH_FOR_EACH (node, &table->schema->columns) {
104 const struct ovsdb_column *column = node->data;
105 ovsdb_datum_destroy(&row->fields[column->index], &column->type);
106 }
107 free(row);
108 }
109}
110
111uint32_t
112ovsdb_row_hash_columns(const struct ovsdb_row *row,
113 const struct ovsdb_column_set *columns,
114 uint32_t basis)
115{
116 size_t i;
117
118 for (i = 0; i < columns->n_columns; i++) {
119 const struct ovsdb_column *column = columns->columns[i];
120 basis = ovsdb_datum_hash(&row->fields[column->index], &column->type,
121 basis);
122 }
123
124 return basis;
125}
126
127int
128ovsdb_row_compare_columns_3way(const struct ovsdb_row *a,
129 const struct ovsdb_row *b,
130 const struct ovsdb_column_set *columns)
131{
132 size_t i;
133
134 for (i = 0; i < columns->n_columns; i++) {
135 const struct ovsdb_column *column = columns->columns[i];
136 int cmp = ovsdb_datum_compare_3way(&a->fields[column->index],
137 &b->fields[column->index],
138 &column->type);
139 if (cmp) {
140 return cmp;
141 }
142 }
143
144 return 0;
145}
146
147bool
148ovsdb_row_equal_columns(const struct ovsdb_row *a,
149 const struct ovsdb_row *b,
150 const struct ovsdb_column_set *columns)
151{
152 size_t i;
153
154 for (i = 0; i < columns->n_columns; i++) {
155 const struct ovsdb_column *column = columns->columns[i];
156 if (!ovsdb_datum_equals(&a->fields[column->index],
157 &b->fields[column->index],
158 &column->type)) {
159 return false;
160 }
161 }
162
163 return true;
164}
165
166void
167ovsdb_row_update_columns(struct ovsdb_row *dst,
168 const struct ovsdb_row *src,
169 const struct ovsdb_column_set *columns)
170{
171 size_t i;
172
173 for (i = 0; i < columns->n_columns; i++) {
174 const struct ovsdb_column *column = columns->columns[i];
175 ovsdb_datum_destroy(&dst->fields[column->index], &column->type);
176 ovsdb_datum_clone(&dst->fields[column->index],
177 &src->fields[column->index],
178 &column->type);
179 }
180}
181
25d49835
BP
182/* Appends the string form of the value in 'row' of each of the columns in
183 * 'columns' to 'out', e.g. "1, \"xyz\", and [1, 2, 3]". */
184void
185ovsdb_row_columns_to_string(const struct ovsdb_row *row,
186 const struct ovsdb_column_set *columns,
187 struct ds *out)
188{
189 size_t i;
190
191 for (i = 0; i < columns->n_columns; i++) {
192 const struct ovsdb_column *column = columns->columns[i];
193
194 ds_put_cstr(out, english_list_delimiter(i, columns->n_columns));
195 ovsdb_datum_to_string(&row->fields[column->index], &column->type, out);
196 }
197}
198
f85f8ebb
BP
199struct ovsdb_error *
200ovsdb_row_from_json(struct ovsdb_row *row, const struct json *json,
fbf925e4 201 struct ovsdb_symbol_table *symtab,
f85f8ebb
BP
202 struct ovsdb_column_set *included)
203{
204 struct ovsdb_table_schema *schema = row->table->schema;
205 struct ovsdb_error *error;
206 struct shash_node *node;
207
208 if (json->type != JSON_OBJECT) {
209 return ovsdb_syntax_error(json, NULL, "row must be JSON object");
210 }
211
212 SHASH_FOR_EACH (node, json_object(json)) {
213 const char *column_name = node->name;
214 const struct ovsdb_column *column;
215 struct ovsdb_datum datum;
216
217 column = ovsdb_table_schema_get_column(schema, column_name);
218 if (!column) {
219 return ovsdb_syntax_error(json, "unknown column",
220 "No column %s in table %s.",
221 column_name, schema->name);
222 }
223
224 error = ovsdb_datum_from_json(&datum, &column->type, node->data,
225 symtab);
226 if (error) {
227 return error;
228 }
229 ovsdb_datum_swap(&row->fields[column->index], &datum);
230 ovsdb_datum_destroy(&datum, &column->type);
231 if (included) {
232 ovsdb_column_set_add(included, column);
233 }
234 }
235
236 return NULL;
237}
238
239static void
240put_json_column(struct json *object, const struct ovsdb_row *row,
241 const struct ovsdb_column *column)
242{
243 json_object_put(object, column->name,
244 ovsdb_datum_to_json(&row->fields[column->index],
245 &column->type));
246}
247
248struct json *
249ovsdb_row_to_json(const struct ovsdb_row *row,
250 const struct ovsdb_column_set *columns)
251{
252 struct json *json;
253 size_t i;
254
255 json = json_object_create();
256 for (i = 0; i < columns->n_columns; i++) {
257 put_json_column(json, row, columns->columns[i]);
258 }
259 return json;
260}
261\f
262void
263ovsdb_row_set_init(struct ovsdb_row_set *set)
264{
265 set->rows = NULL;
266 set->n_rows = set->allocated_rows = 0;
267}
268
269void
270ovsdb_row_set_destroy(struct ovsdb_row_set *set)
271{
272 free(set->rows);
273}
274
275void
276ovsdb_row_set_add_row(struct ovsdb_row_set *set, const struct ovsdb_row *row)
277{
278 if (set->n_rows >= set->allocated_rows) {
279 set->rows = x2nrealloc(set->rows, &set->allocated_rows,
280 sizeof *set->rows);
281 }
282 set->rows[set->n_rows++] = row;
283}
284
285struct json *
286ovsdb_row_set_to_json(const struct ovsdb_row_set *rows,
287 const struct ovsdb_column_set *columns)
288{
289 struct json **json_rows;
290 size_t i;
291
292 json_rows = xmalloc(rows->n_rows * sizeof *json_rows);
293 for (i = 0; i < rows->n_rows; i++) {
294 json_rows[i] = ovsdb_row_to_json(rows->rows[i], columns);
295 }
296 return json_array_create(json_rows, rows->n_rows);
297}
298
299struct ovsdb_row_set_sort_cbdata {
300 struct ovsdb_row_set *set;
301 const struct ovsdb_column_set *columns;
302};
303
304static int
305ovsdb_row_set_sort_compare_cb(size_t a, size_t b, void *cbdata_)
306{
307 struct ovsdb_row_set_sort_cbdata *cbdata = cbdata_;
308 return ovsdb_row_compare_columns_3way(cbdata->set->rows[a],
309 cbdata->set->rows[b],
310 cbdata->columns);
311}
312
313static void
314ovsdb_row_set_sort_swap_cb(size_t a, size_t b, void *cbdata_)
315{
316 struct ovsdb_row_set_sort_cbdata *cbdata = cbdata_;
317 const struct ovsdb_row *tmp = cbdata->set->rows[a];
318 cbdata->set->rows[a] = cbdata->set->rows[b];
319 cbdata->set->rows[b] = tmp;
320}
321
322void
323ovsdb_row_set_sort(struct ovsdb_row_set *set,
324 const struct ovsdb_column_set *columns)
325{
326 if (columns && columns->n_columns && set->n_rows > 1) {
327 struct ovsdb_row_set_sort_cbdata cbdata;
328 cbdata.set = set;
329 cbdata.columns = columns;
330 sort(set->n_rows,
331 ovsdb_row_set_sort_compare_cb,
332 ovsdb_row_set_sort_swap_cb,
333 &cbdata);
334 }
335}
336\f
337void
338ovsdb_row_hash_init(struct ovsdb_row_hash *rh,
339 const struct ovsdb_column_set *columns)
340{
341 hmap_init(&rh->rows);
342 ovsdb_column_set_clone(&rh->columns, columns);
343}
344
345void
346ovsdb_row_hash_destroy(struct ovsdb_row_hash *rh, bool destroy_rows)
347{
4ec3d7c7 348 struct ovsdb_row_hash_node *node;
f85f8ebb 349
4ec3d7c7 350 HMAP_FOR_EACH_POP (node, hmap_node, &rh->rows) {
f85f8ebb 351 if (destroy_rows) {
ebc56baa 352 ovsdb_row_destroy(CONST_CAST(struct ovsdb_row *, node->row));
f85f8ebb
BP
353 }
354 free(node);
355 }
356 hmap_destroy(&rh->rows);
357 ovsdb_column_set_destroy(&rh->columns);
358}
359
360size_t
361ovsdb_row_hash_count(const struct ovsdb_row_hash *rh)
362{
363 return hmap_count(&rh->rows);
364}
365
366bool
367ovsdb_row_hash_contains(const struct ovsdb_row_hash *rh,
368 const struct ovsdb_row *row)
369{
370 size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
371 return ovsdb_row_hash_contains__(rh, row, hash);
372}
373
374/* Returns true if every row in 'b' has an equal row in 'a'. */
375bool
376ovsdb_row_hash_contains_all(const struct ovsdb_row_hash *a,
377 const struct ovsdb_row_hash *b)
378{
379 struct ovsdb_row_hash_node *node;
380
cb22974d 381 ovs_assert(ovsdb_column_set_equals(&a->columns, &b->columns));
4e8e4213 382 HMAP_FOR_EACH (node, hmap_node, &b->rows) {
f85f8ebb
BP
383 if (!ovsdb_row_hash_contains__(a, node->row, node->hmap_node.hash)) {
384 return false;
385 }
386 }
387 return true;
388}
389
390bool
391ovsdb_row_hash_insert(struct ovsdb_row_hash *rh, const struct ovsdb_row *row)
392{
393 size_t hash = ovsdb_row_hash_columns(row, &rh->columns, 0);
394 return ovsdb_row_hash_insert__(rh, row, hash);
395}
396
397bool
398ovsdb_row_hash_contains__(const struct ovsdb_row_hash *rh,
399 const struct ovsdb_row *row, size_t hash)
400{
401 struct ovsdb_row_hash_node *node;
4e8e4213 402 HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash, &rh->rows) {
f85f8ebb
BP
403 if (ovsdb_row_equal_columns(row, node->row, &rh->columns)) {
404 return true;
405 }
406 }
407 return false;
408}
409
410bool
411ovsdb_row_hash_insert__(struct ovsdb_row_hash *rh, const struct ovsdb_row *row,
412 size_t hash)
413{
414 if (!ovsdb_row_hash_contains__(rh, row, hash)) {
415 struct ovsdb_row_hash_node *node = xmalloc(sizeof *node);
416 node->row = row;
417 hmap_insert(&rh->rows, &node->hmap_node, hash);
418 return true;
419 } else {
420 return false;
421 }
422}