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