Merge "next" branch into "master".
[cascardo/ovs.git] / ovsdb / ovsdb.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 "ovsdb.h"
19
20 #include "column.h"
21 #include "json.h"
22 #include "ovsdb-error.h"
23 #include "ovsdb-parser.h"
24 #include "ovsdb-types.h"
25 #include "table.h"
26 #include "transaction.h"
27
28 struct ovsdb_schema *
29 ovsdb_schema_create(const char *name)
30 {
31     struct ovsdb_schema *schema;
32
33     schema = xzalloc(sizeof *schema);
34     schema->name = xstrdup(name);
35     shash_init(&schema->tables);
36
37     return schema;
38 }
39
40 struct ovsdb_schema *
41 ovsdb_schema_clone(const struct ovsdb_schema *old)
42 {
43     struct ovsdb_schema *new;
44     struct shash_node *node;
45
46     new = ovsdb_schema_create(old->name);
47     SHASH_FOR_EACH (node, &old->tables) {
48         const struct ovsdb_table_schema *ts = node->data;
49
50         shash_add(&new->tables, node->name, ovsdb_table_schema_clone(ts));
51     }
52     return new;
53 }
54
55
56 void
57 ovsdb_schema_destroy(struct ovsdb_schema *schema)
58 {
59     struct shash_node *node;
60
61     SHASH_FOR_EACH (node, &schema->tables) {
62         ovsdb_table_schema_destroy(node->data);
63     }
64     shash_destroy(&schema->tables);
65     free(schema->name);
66     free(schema);
67 }
68
69 struct ovsdb_error *
70 ovsdb_schema_from_file(const char *file_name, struct ovsdb_schema **schemap)
71 {
72     struct ovsdb_schema *schema;
73     struct ovsdb_error *error;
74     struct json *json;
75
76     *schemap = NULL;
77     json = json_from_file(file_name);
78     if (json->type == JSON_STRING) {
79         error = ovsdb_error("failed to read schema",
80                            "\"%s\" could not be read as JSON (%s)",
81                            file_name, json_string(json));
82         json_destroy(json);
83         return error;
84     }
85
86     error = ovsdb_schema_from_json(json, &schema);
87     json_destroy(json);
88     if (error) {
89         return ovsdb_wrap_error(error,
90                                 "failed to parse \"%s\" as ovsdb schema",
91                                 file_name);
92     }
93
94     *schemap = schema;
95     return NULL;
96 }
97
98 static struct ovsdb_error * WARN_UNUSED_RESULT
99 ovsdb_schema_check_ref_table(const struct ovsdb_column *column,
100                              const struct shash *tables,
101                              const struct ovsdb_base_type *base,
102                              const char *base_name)
103 {
104     if (base->type == OVSDB_TYPE_UUID && base->u.uuid.refTableName
105         && !shash_find(tables, base->u.uuid.refTableName)) {
106         return ovsdb_syntax_error(NULL, NULL,
107                                   "column %s %s refers to undefined table %s",
108                                   column->name, base_name,
109                                   base->u.uuid.refTableName);
110     } else {
111         return NULL;
112     }
113 }
114
115 struct ovsdb_error *
116 ovsdb_schema_from_json(struct json *json, struct ovsdb_schema **schemap)
117 {
118     struct ovsdb_schema *schema;
119     const struct json *name, *tables;
120     struct ovsdb_error *error;
121     struct shash_node *node;
122     struct ovsdb_parser parser;
123
124     *schemap = NULL;
125
126     ovsdb_parser_init(&parser, json, "database schema");
127     name = ovsdb_parser_member(&parser, "name", OP_ID);
128     tables = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
129     error = ovsdb_parser_finish(&parser);
130     if (error) {
131         return error;
132     }
133
134     schema = ovsdb_schema_create(json_string(name));
135     SHASH_FOR_EACH (node, json_object(tables)) {
136         struct ovsdb_table_schema *table;
137
138         if (node->name[0] == '_') {
139             error = ovsdb_syntax_error(json, NULL, "names beginning with "
140                                        "\"_\" are reserved");
141         } else if (!ovsdb_parser_is_id(node->name)) {
142             error = ovsdb_syntax_error(json, NULL, "name must be a valid id");
143         } else {
144             error = ovsdb_table_schema_from_json(node->data, node->name,
145                                                  &table);
146         }
147         if (error) {
148             ovsdb_schema_destroy(schema);
149             return error;
150         }
151
152         shash_add(&schema->tables, table->name, table);
153     }
154
155     /* Validate that all refTables refer to the names of tables that exist. */
156     SHASH_FOR_EACH (node, &schema->tables) {
157         struct ovsdb_table_schema *table = node->data;
158         struct shash_node *node2;
159
160         SHASH_FOR_EACH (node2, &table->columns) {
161             struct ovsdb_column *column = node2->data;
162
163             error = ovsdb_schema_check_ref_table(column, &schema->tables,
164                                                  &column->type.key, "key");
165             if (!error) {
166                 error = ovsdb_schema_check_ref_table(column, &schema->tables,
167                                                      &column->type.value,
168                                                      "value");
169             }
170             if (error) {
171                 ovsdb_schema_destroy(schema);
172                 return error;
173             }
174         }
175     }
176
177     *schemap = schema;
178     return 0;
179 }
180
181 struct json *
182 ovsdb_schema_to_json(const struct ovsdb_schema *schema)
183 {
184     struct json *json, *tables;
185     struct shash_node *node;
186
187     json = json_object_create();
188     json_object_put_string(json, "name", schema->name);
189
190     tables = json_object_create();
191
192     SHASH_FOR_EACH (node, &schema->tables) {
193         struct ovsdb_table_schema *table = node->data;
194         json_object_put(tables, table->name,
195                         ovsdb_table_schema_to_json(table));
196     }
197     json_object_put(json, "tables", tables);
198
199     return json;
200 }
201 \f
202 static void
203 ovsdb_set_ref_table(const struct shash *tables,
204                     struct ovsdb_base_type *base)
205 {
206     if (base->type == OVSDB_TYPE_UUID && base->u.uuid.refTableName) {
207         struct ovsdb_table *table;
208
209         table = shash_find_data(tables, base->u.uuid.refTableName);
210         base->u.uuid.refTable = table;
211     }
212 }
213
214 struct ovsdb *
215 ovsdb_create(struct ovsdb_schema *schema)
216 {
217     struct shash_node *node;
218     struct ovsdb *db;
219
220     db = xmalloc(sizeof *db);
221     db->schema = schema;
222     list_init(&db->replicas);
223     list_init(&db->triggers);
224     db->run_triggers = false;
225
226     shash_init(&db->tables);
227     SHASH_FOR_EACH (node, &schema->tables) {
228         struct ovsdb_table_schema *ts = node->data;
229         shash_add(&db->tables, node->name, ovsdb_table_create(ts));
230     }
231
232     /* Set all the refTables. */
233     SHASH_FOR_EACH (node, &schema->tables) {
234         struct ovsdb_table_schema *table = node->data;
235         struct shash_node *node2;
236
237         SHASH_FOR_EACH (node2, &table->columns) {
238             struct ovsdb_column *column = node2->data;
239
240             ovsdb_set_ref_table(&db->tables, &column->type.key);
241             ovsdb_set_ref_table(&db->tables, &column->type.value);
242         }
243     }
244
245     return db;
246 }
247
248 void
249 ovsdb_destroy(struct ovsdb *db)
250 {
251     if (db) {
252         struct shash_node *node;
253
254         /* Remove all the replicas. */
255         while (!list_is_empty(&db->replicas)) {
256             struct ovsdb_replica *r
257                 = CONTAINER_OF(list_pop_back(&db->replicas),
258                                struct ovsdb_replica, node);
259             ovsdb_remove_replica(db, r);
260         }
261
262         /* Delete all the tables.  This also deletes their schemas. */
263         SHASH_FOR_EACH (node, &db->tables) {
264             struct ovsdb_table *table = node->data;
265             ovsdb_table_destroy(table);
266         }
267         shash_destroy(&db->tables);
268
269         /* The schemas, but not the table that points to them, were deleted in
270          * the previous step, so we need to clear out the table.  We can't
271          * destroy the table, because ovsdb_schema_destroy() will do that. */
272         shash_clear(&db->schema->tables);
273
274         ovsdb_schema_destroy(db->schema);
275         free(db);
276     }
277 }
278
279 struct ovsdb_table *
280 ovsdb_get_table(const struct ovsdb *db, const char *name)
281 {
282     return shash_find_data(&db->tables, name);
283 }
284 \f
285 void
286 ovsdb_replica_init(struct ovsdb_replica *r,
287                    const struct ovsdb_replica_class *class)
288 {
289     r->class = class;
290 }
291
292 void
293 ovsdb_add_replica(struct ovsdb *db, struct ovsdb_replica *r)
294 {
295     list_push_back(&db->replicas, &r->node);
296 }
297
298 void
299 ovsdb_remove_replica(struct ovsdb *db OVS_UNUSED, struct ovsdb_replica *r)
300 {
301     list_remove(&r->node);
302     (r->class->destroy)(r);
303 }