]>
Commit | Line | Data |
---|---|---|
c5f341ab | 1 | /* Copyright (c) 2009, 2010, 2011 Nicira Networks |
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 "table.h" | |
19 | ||
20 | #include <assert.h> | |
87ab878c | 21 | #include <limits.h> |
f85f8ebb BP |
22 | |
23 | #include "json.h" | |
24 | #include "column.h" | |
25 | #include "ovsdb-error.h" | |
26 | #include "ovsdb-parser.h" | |
27 | #include "ovsdb-types.h" | |
28 | #include "row.h" | |
29 | ||
30 | static void | |
31 | add_column(struct ovsdb_table_schema *ts, struct ovsdb_column *column) | |
32 | { | |
33 | assert(!shash_find(&ts->columns, column->name)); | |
34 | column->index = shash_count(&ts->columns); | |
35 | shash_add(&ts->columns, column->name, column); | |
36 | } | |
37 | ||
38 | struct ovsdb_table_schema * | |
87ab878c | 39 | ovsdb_table_schema_create(const char *name, bool mutable, |
c5f341ab | 40 | unsigned int max_rows, bool is_root) |
f85f8ebb BP |
41 | { |
42 | struct ovsdb_column *uuid, *version; | |
43 | struct ovsdb_table_schema *ts; | |
44 | ||
45 | ts = xzalloc(sizeof *ts); | |
46 | ts->name = xstrdup(name); | |
f85f8ebb BP |
47 | ts->mutable = mutable; |
48 | shash_init(&ts->columns); | |
87ab878c | 49 | ts->max_rows = max_rows; |
c5f341ab | 50 | ts->is_root = is_root; |
f85f8ebb | 51 | |
2e57b537 | 52 | uuid = ovsdb_column_create("_uuid", false, true, &ovsdb_type_uuid); |
f85f8ebb BP |
53 | add_column(ts, uuid); |
54 | assert(uuid->index == OVSDB_COL_UUID); | |
55 | ||
2e57b537 | 56 | version = ovsdb_column_create("_version", false, false, &ovsdb_type_uuid); |
f85f8ebb BP |
57 | add_column(ts, version); |
58 | assert(version->index == OVSDB_COL_VERSION); | |
59 | ||
60 | return ts; | |
61 | } | |
62 | ||
58985e09 BP |
63 | struct ovsdb_table_schema * |
64 | ovsdb_table_schema_clone(const struct ovsdb_table_schema *old) | |
65 | { | |
66 | struct ovsdb_table_schema *new; | |
67 | struct shash_node *node; | |
68 | ||
c5f341ab BP |
69 | new = ovsdb_table_schema_create(old->name, old->mutable, |
70 | old->max_rows, old->is_root); | |
58985e09 BP |
71 | SHASH_FOR_EACH (node, &old->columns) { |
72 | const struct ovsdb_column *column = node->data; | |
73 | ||
74 | if (column->name[0] == '_') { | |
75 | /* Added automatically by ovsdb_table_schema_create(). */ | |
76 | continue; | |
77 | } | |
78 | ||
79 | add_column(new, ovsdb_column_clone(column)); | |
80 | } | |
81 | return new; | |
82 | } | |
83 | ||
f85f8ebb BP |
84 | void |
85 | ovsdb_table_schema_destroy(struct ovsdb_table_schema *ts) | |
86 | { | |
87 | struct shash_node *node; | |
88 | ||
89 | SHASH_FOR_EACH (node, &ts->columns) { | |
90 | ovsdb_column_destroy(node->data); | |
91 | } | |
92 | shash_destroy(&ts->columns); | |
f85f8ebb BP |
93 | free(ts->name); |
94 | free(ts); | |
95 | } | |
96 | ||
97 | struct ovsdb_error * | |
98 | ovsdb_table_schema_from_json(const struct json *json, const char *name, | |
99 | struct ovsdb_table_schema **tsp) | |
100 | { | |
101 | struct ovsdb_table_schema *ts; | |
c5f341ab | 102 | const struct json *columns, *mutable, *max_rows, *is_root; |
f85f8ebb BP |
103 | struct shash_node *node; |
104 | struct ovsdb_parser parser; | |
105 | struct ovsdb_error *error; | |
87ab878c | 106 | long long int n_max_rows; |
f85f8ebb BP |
107 | |
108 | *tsp = NULL; | |
109 | ||
110 | ovsdb_parser_init(&parser, json, "table schema for table %s", name); | |
f85f8ebb BP |
111 | columns = ovsdb_parser_member(&parser, "columns", OP_OBJECT); |
112 | mutable = ovsdb_parser_member(&parser, "mutable", | |
113 | OP_TRUE | OP_FALSE | OP_OPTIONAL); | |
87ab878c BP |
114 | max_rows = ovsdb_parser_member(&parser, "maxRows", |
115 | OP_INTEGER | OP_OPTIONAL); | |
c5f341ab | 116 | is_root = ovsdb_parser_member(&parser, "isRoot", OP_BOOLEAN | OP_OPTIONAL); |
f85f8ebb BP |
117 | error = ovsdb_parser_finish(&parser); |
118 | if (error) { | |
119 | return error; | |
120 | } | |
121 | ||
87ab878c BP |
122 | if (max_rows) { |
123 | if (json_integer(max_rows) <= 0) { | |
124 | return ovsdb_syntax_error(json, NULL, | |
125 | "maxRows must be at least 1"); | |
126 | } | |
127 | n_max_rows = max_rows->u.integer; | |
128 | } else { | |
129 | n_max_rows = UINT_MAX; | |
130 | } | |
131 | ||
f85f8ebb BP |
132 | if (shash_is_empty(json_object(columns))) { |
133 | return ovsdb_syntax_error(json, NULL, | |
134 | "table must have at least one column"); | |
135 | } | |
136 | ||
137 | ts = ovsdb_table_schema_create(name, | |
87ab878c | 138 | mutable ? json_boolean(mutable) : true, |
c5f341ab BP |
139 | MIN(n_max_rows, UINT_MAX), |
140 | is_root ? json_boolean(is_root) : false); | |
f85f8ebb BP |
141 | SHASH_FOR_EACH (node, json_object(columns)) { |
142 | struct ovsdb_column *column; | |
143 | ||
144 | if (node->name[0] == '_') { | |
145 | error = ovsdb_syntax_error(json, NULL, "names beginning with " | |
146 | "\"_\" are reserved"); | |
b966380b BP |
147 | } else if (!ovsdb_parser_is_id(node->name)) { |
148 | error = ovsdb_syntax_error(json, NULL, "name must be a valid id"); | |
f85f8ebb BP |
149 | } else { |
150 | error = ovsdb_column_from_json(node->data, node->name, &column); | |
151 | } | |
152 | if (error) { | |
153 | ovsdb_table_schema_destroy(ts); | |
154 | return error; | |
155 | } | |
156 | ||
157 | add_column(ts, column); | |
158 | } | |
159 | *tsp = ts; | |
e3c17733 | 160 | return NULL; |
f85f8ebb BP |
161 | } |
162 | ||
c5f341ab BP |
163 | /* Returns table schema 'ts' serialized into JSON. |
164 | * | |
165 | * The "isRoot" member is included in the JSON only if its value would differ | |
166 | * from 'default_is_root'. Ordinarily 'default_is_root' should be false, | |
167 | * because ordinarily a table would be not be part of the root set if its | |
168 | * "isRoot" member is omitted. However, garbage collection was not orginally | |
169 | * included in OVSDB, so in older schemas that do not include any "isRoot" | |
170 | * members, every table is implicitly part of the root set. To serialize such | |
171 | * a schema in a way that can be read by older OVSDB tools, specify | |
172 | * 'default_is_root' as true. */ | |
f85f8ebb | 173 | struct json * |
c5f341ab BP |
174 | ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts, |
175 | bool default_is_root) | |
f85f8ebb BP |
176 | { |
177 | struct json *json, *columns; | |
178 | struct shash_node *node; | |
179 | ||
180 | json = json_object_create(); | |
f85f8ebb BP |
181 | if (!ts->mutable) { |
182 | json_object_put(json, "mutable", json_boolean_create(false)); | |
183 | } | |
c5f341ab BP |
184 | if (default_is_root != ts->is_root) { |
185 | json_object_put(json, "isRoot", json_boolean_create(ts->is_root)); | |
186 | } | |
f85f8ebb BP |
187 | |
188 | columns = json_object_create(); | |
189 | ||
190 | SHASH_FOR_EACH (node, &ts->columns) { | |
bd76d25d | 191 | const struct ovsdb_column *column = node->data; |
f85f8ebb BP |
192 | if (node->name[0] != '_') { |
193 | json_object_put(columns, column->name, | |
194 | ovsdb_column_to_json(column)); | |
195 | } | |
196 | } | |
197 | json_object_put(json, "columns", columns); | |
87ab878c BP |
198 | if (ts->max_rows != UINT_MAX) { |
199 | json_object_put(json, "maxRows", json_integer_create(ts->max_rows)); | |
200 | } | |
f85f8ebb BP |
201 | |
202 | return json; | |
203 | } | |
204 | ||
205 | const struct ovsdb_column * | |
206 | ovsdb_table_schema_get_column(const struct ovsdb_table_schema *ts, | |
207 | const char *name) | |
208 | { | |
209 | return shash_find_data(&ts->columns, name); | |
210 | } | |
211 | \f | |
212 | struct ovsdb_table * | |
213 | ovsdb_table_create(struct ovsdb_table_schema *ts) | |
214 | { | |
215 | struct ovsdb_table *table; | |
216 | ||
217 | table = xmalloc(sizeof *table); | |
218 | table->schema = ts; | |
71c93bd4 | 219 | table->txn_table = NULL; |
f85f8ebb BP |
220 | hmap_init(&table->rows); |
221 | ||
222 | return table; | |
223 | } | |
224 | ||
225 | void | |
226 | ovsdb_table_destroy(struct ovsdb_table *table) | |
227 | { | |
228 | if (table) { | |
229 | struct ovsdb_row *row, *next; | |
230 | ||
4e8e4213 | 231 | HMAP_FOR_EACH_SAFE (row, next, hmap_node, &table->rows) { |
f85f8ebb BP |
232 | ovsdb_row_destroy(row); |
233 | } | |
234 | hmap_destroy(&table->rows); | |
235 | ||
236 | ovsdb_table_schema_destroy(table->schema); | |
237 | free(table); | |
238 | } | |
239 | } | |
240 | ||
629cd2f1 BP |
241 | const struct ovsdb_row * |
242 | ovsdb_table_get_row(const struct ovsdb_table *table, const struct uuid *uuid) | |
f85f8ebb BP |
243 | { |
244 | struct ovsdb_row *row; | |
245 | ||
4e8e4213 | 246 | HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), &table->rows) { |
f85f8ebb BP |
247 | if (uuid_equals(ovsdb_row_get_uuid(row), uuid)) { |
248 | return row; | |
249 | } | |
250 | } | |
251 | ||
252 | return NULL; | |
253 | } | |
254 | ||
f85f8ebb BP |
255 | /* This is probably not the function you want. Use ovsdb_txn_row_modify() |
256 | * instead. */ | |
257 | bool | |
258 | ovsdb_table_put_row(struct ovsdb_table *table, struct ovsdb_row *row) | |
259 | { | |
260 | const struct uuid *uuid = ovsdb_row_get_uuid(row); | |
629cd2f1 BP |
261 | if (!ovsdb_table_get_row(table, uuid)) { |
262 | hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid)); | |
f85f8ebb BP |
263 | return true; |
264 | } else { | |
265 | return false; | |
266 | } | |
267 | } |