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