ac2aa29dfb78f85e9b4fe7028039e2f0da3fcee1
[sliver-openvswitch.git] / ovsdb / server.c
1 /* Copyright (c) 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 "server.h"
19
20 #include <assert.h>
21
22 #include "hash.h"
23 #include "ovsdb.h"
24
25 /* Initializes 'session' as a session within 'server'. */
26 void
27 ovsdb_session_init(struct ovsdb_session *session, struct ovsdb_server *server)
28 {
29     session->server = server;
30     list_init(&session->completions);
31     hmap_init(&session->waiters);
32 }
33
34 /* Destroys 'session'. */
35 void
36 ovsdb_session_destroy(struct ovsdb_session *session)
37 {
38     assert(hmap_is_empty(&session->waiters));
39     hmap_destroy(&session->waiters);
40 }
41
42 /* Searches 'session' for an ovsdb_lock_waiter named 'lock_name' and returns
43  * it if it finds one, otherwise NULL. */
44 struct ovsdb_lock_waiter *
45 ovsdb_session_get_lock_waiter(const struct ovsdb_session *session,
46                               const char *lock_name)
47 {
48     struct ovsdb_lock_waiter *waiter;
49
50     HMAP_FOR_EACH_WITH_HASH (waiter, session_node, hash_string(lock_name, 0),
51                              &session->waiters) {
52         if (!strcmp(lock_name, waiter->lock_name)) {
53             return waiter;
54         }
55     }
56     return NULL;
57 }
58
59 /* Returns the waiter that owns 'lock'.
60  *
61  * A lock always has an owner, so this function will never return NULL. */
62 struct ovsdb_lock_waiter *
63 ovsdb_lock_get_owner(const struct ovsdb_lock *lock)
64 {
65     return CONTAINER_OF(list_front(&lock->waiters),
66                         struct ovsdb_lock_waiter, lock_node);
67 }
68
69 /* Removes 'waiter' from its lock's list.  This means that, if 'waiter' was
70  * formerly the owner of its lock, then it no longer owns it.
71  *
72  * Returns the session that now owns 'waiter'.  This is NULL if 'waiter' was
73  * the lock's owner and no other sessions were waiting for the lock.  In this
74  * case, the lock has been destroyed, so the caller must be sure not to refer
75  * to it again.  A nonnull return value reflects a change in the lock's
76  * ownership if and only if 'waiter' formerly owned the lock. */
77 struct ovsdb_session *
78 ovsdb_lock_waiter_remove(struct ovsdb_lock_waiter *waiter)
79 {
80     struct ovsdb_lock *lock = waiter->lock;
81
82     list_remove(&waiter->lock_node);
83     waiter->lock = NULL;
84
85     if (list_is_empty(&lock->waiters)) {
86         hmap_remove(&lock->server->locks, &lock->hmap_node);
87         free(lock->name);
88         free(lock);
89         return NULL;
90     }
91
92     return ovsdb_lock_get_owner(lock)->session;
93 }
94
95 /* Destroys 'waiter', which must have already been removed from its lock's
96  * waiting list with ovsdb_lock_waiter_remove().
97  *
98  * Removing and destroying locks are decoupled because a lock initially created
99  * by the "steal" request, that is later stolen by another client, remains in
100  * the database session until the database client sends an "unlock" request. */
101 void
102 ovsdb_lock_waiter_destroy(struct ovsdb_lock_waiter *waiter)
103 {
104     assert(!waiter->lock);
105     hmap_remove(&waiter->session->waiters, &waiter->session_node);
106     free(waiter->lock_name);
107     free(waiter);
108 }
109
110 /* Returns true if 'waiter' owns its associated lock. */
111 bool
112 ovsdb_lock_waiter_is_owner(const struct ovsdb_lock_waiter *waiter)
113 {
114     return waiter->lock && waiter == ovsdb_lock_get_owner(waiter->lock);
115 }
116
117 /* Initializes 'server'.
118  *
119  * The caller must call ovsdb_server_add_db() for each database to which
120  * 'server' should provide access. */
121 void
122 ovsdb_server_init(struct ovsdb_server *server)
123 {
124     shash_init(&server->dbs);
125     hmap_init(&server->locks);
126 }
127
128 /* Adds 'db' to the set of databases served out by 'server'.  Returns true if
129  * successful, false if 'db''s name is the same as some database already in
130  * 'server'. */
131 bool
132 ovsdb_server_add_db(struct ovsdb_server *server, struct ovsdb *db)
133 {
134     return shash_add_once(&server->dbs, db->schema->name, db);
135 }
136
137 /* Destroys 'server'. */
138 void
139 ovsdb_server_destroy(struct ovsdb_server *server)
140 {
141     shash_destroy(&server->dbs);
142     hmap_destroy(&server->locks);
143 }
144
145 static struct ovsdb_lock *
146 ovsdb_server_create_lock__(struct ovsdb_server *server, const char *lock_name,
147                            uint32_t hash)
148 {
149     struct ovsdb_lock *lock;
150
151     HMAP_FOR_EACH_WITH_HASH (lock, hmap_node, hash, &server->locks) {
152         if (!strcmp(lock->name, lock_name)) {
153             return lock;
154         }
155     }
156
157     lock = xzalloc(sizeof *lock);
158     lock->server = server;
159     lock->name = xstrdup(lock_name);
160     hmap_insert(&server->locks, &lock->hmap_node, hash);
161     list_init(&lock->waiters);
162
163     return lock;
164 }
165
166 /* Attempts to acquire the lock named 'lock_name' for 'session' within
167  * 'server'.  Returns the new lock waiter.
168  *
169  * If 'mode' is OVSDB_LOCK_STEAL, then the new lock waiter is always the owner
170  * of the lock.  '*victimp' receives the session of the previous owner or NULL
171  * if the lock was previously unowned.  (If the victim itself originally
172  * obtained the lock through a "steal" operation, then this function also
173  * removes the victim from the lock's waiting list.)
174  *
175  * If 'mode' is OVSDB_LOCK_WAIT, then the new lock waiter is the owner of the
176  * lock only if this lock had no existing owner.  '*victimp' is set to NULL. */
177 struct ovsdb_lock_waiter *
178 ovsdb_server_lock(struct ovsdb_server *server,
179                   struct ovsdb_session *session,
180                   const char *lock_name,
181                   enum ovsdb_lock_mode mode,
182                   struct ovsdb_session **victimp)
183 {
184     uint32_t hash = hash_string(lock_name, 0);
185     struct ovsdb_lock_waiter *waiter, *victim;
186     struct ovsdb_lock *lock;
187
188     lock = ovsdb_server_create_lock__(server, lock_name, hash);
189     victim = (mode == OVSDB_LOCK_STEAL && !list_is_empty(&lock->waiters)
190               ? ovsdb_lock_get_owner(lock)
191               : NULL);
192
193     waiter = xmalloc(sizeof *waiter);
194     waiter->mode = mode;
195     waiter->lock_name = xstrdup(lock_name);
196     waiter->lock = lock;
197     if (mode == OVSDB_LOCK_STEAL) {
198         list_push_front(&lock->waiters, &waiter->lock_node);
199     } else {
200         list_push_back(&lock->waiters, &waiter->lock_node);
201     }
202     waiter->session = session;
203     hmap_insert(&waiter->session->waiters, &waiter->session_node, hash);
204
205     if (victim && victim->mode == OVSDB_LOCK_STEAL) {
206         ovsdb_lock_waiter_remove(victim);
207     }
208     *victimp = victim ? victim->session : NULL;
209
210     return waiter;
211 }