]>
git.proxmox.com Git - mirror_ovs.git/blob - ovsdb/server.c
1 /* Copyright (c) 2011, 2012 Nicira, Inc.
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 /* Initializes 'session' as a session within 'server'. */
26 ovsdb_session_init(struct ovsdb_session
*session
, struct ovsdb_server
*server
)
28 session
->server
= server
;
29 ovs_list_init(&session
->completions
);
30 hmap_init(&session
->waiters
);
33 /* Destroys 'session'. */
35 ovsdb_session_destroy(struct ovsdb_session
*session
)
37 ovs_assert(hmap_is_empty(&session
->waiters
));
38 hmap_destroy(&session
->waiters
);
41 /* Searches 'session' for an ovsdb_lock_waiter named 'lock_name' and returns
42 * it if it finds one, otherwise NULL. */
43 struct ovsdb_lock_waiter
*
44 ovsdb_session_get_lock_waiter(const struct ovsdb_session
*session
,
45 const char *lock_name
)
47 struct ovsdb_lock_waiter
*waiter
;
49 HMAP_FOR_EACH_WITH_HASH (waiter
, session_node
, hash_string(lock_name
, 0),
51 if (!strcmp(lock_name
, waiter
->lock_name
)) {
58 /* Returns the waiter that owns 'lock'.
60 * A lock always has an owner, so this function will never return NULL. */
61 struct ovsdb_lock_waiter
*
62 ovsdb_lock_get_owner(const struct ovsdb_lock
*lock
)
64 return CONTAINER_OF(ovs_list_front(&lock
->waiters
),
65 struct ovsdb_lock_waiter
, lock_node
);
68 /* Removes 'waiter' from its lock's list. This means that, if 'waiter' was
69 * formerly the owner of its lock, then it no longer owns it.
71 * Returns the session that now owns 'waiter'. This is NULL if 'waiter' was
72 * the lock's owner and no other sessions were waiting for the lock. In this
73 * case, the lock has been destroyed, so the caller must be sure not to refer
74 * to it again. A nonnull return value reflects a change in the lock's
75 * ownership if and only if 'waiter' formerly owned the lock. */
76 struct ovsdb_session
*
77 ovsdb_lock_waiter_remove(struct ovsdb_lock_waiter
*waiter
)
79 struct ovsdb_lock
*lock
= waiter
->lock
;
81 ovs_list_remove(&waiter
->lock_node
);
84 if (ovs_list_is_empty(&lock
->waiters
)) {
85 hmap_remove(&lock
->server
->locks
, &lock
->hmap_node
);
91 return ovsdb_lock_get_owner(lock
)->session
;
94 /* Destroys 'waiter', which must have already been removed from its lock's
95 * waiting list with ovsdb_lock_waiter_remove().
97 * Removing and destroying locks are decoupled because a lock initially created
98 * by the "steal" request, that is later stolen by another client, remains in
99 * the database session until the database client sends an "unlock" request. */
101 ovsdb_lock_waiter_destroy(struct ovsdb_lock_waiter
*waiter
)
103 ovs_assert(!waiter
->lock
);
104 hmap_remove(&waiter
->session
->waiters
, &waiter
->session_node
);
105 free(waiter
->lock_name
);
109 /* Returns true if 'waiter' owns its associated lock. */
111 ovsdb_lock_waiter_is_owner(const struct ovsdb_lock_waiter
*waiter
)
113 return waiter
->lock
&& waiter
== ovsdb_lock_get_owner(waiter
->lock
);
116 /* Initializes 'server'.
118 * The caller must call ovsdb_server_add_db() for each database to which
119 * 'server' should provide access. */
121 ovsdb_server_init(struct ovsdb_server
*server
)
123 shash_init(&server
->dbs
);
124 hmap_init(&server
->locks
);
125 uuid_generate(&server
->uuid
);
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
132 ovsdb_server_add_db(struct ovsdb_server
*server
, struct ovsdb
*db
)
134 return shash_add_once(&server
->dbs
, db
->name
, db
);
137 /* Removes 'db' from the set of databases served out by 'server'. */
139 ovsdb_server_remove_db(struct ovsdb_server
*server
, struct ovsdb
*db
)
141 shash_find_and_delete_assert(&server
->dbs
, db
->name
);
144 /* Destroys 'server'. */
146 ovsdb_server_destroy(struct ovsdb_server
*server
)
148 shash_destroy(&server
->dbs
);
149 hmap_destroy(&server
->locks
);
152 static struct ovsdb_lock
*
153 ovsdb_server_create_lock__(struct ovsdb_server
*server
, const char *lock_name
,
156 struct ovsdb_lock
*lock
;
158 HMAP_FOR_EACH_WITH_HASH (lock
, hmap_node
, hash
, &server
->locks
) {
159 if (!strcmp(lock
->name
, lock_name
)) {
164 lock
= xzalloc(sizeof *lock
);
165 lock
->server
= server
;
166 lock
->name
= xstrdup(lock_name
);
167 hmap_insert(&server
->locks
, &lock
->hmap_node
, hash
);
168 ovs_list_init(&lock
->waiters
);
173 /* Attempts to acquire the lock named 'lock_name' for 'session' within
174 * 'server'. Returns the new lock waiter.
176 * If 'mode' is OVSDB_LOCK_STEAL, then the new lock waiter is always the owner
177 * of the lock. '*victimp' receives the session of the previous owner or NULL
178 * if the lock was previously unowned. (If the victim itself originally
179 * obtained the lock through a "steal" operation, then this function also
180 * removes the victim from the lock's waiting list.)
182 * If 'mode' is OVSDB_LOCK_WAIT, then the new lock waiter is the owner of the
183 * lock only if this lock had no existing owner. '*victimp' is set to NULL. */
184 struct ovsdb_lock_waiter
*
185 ovsdb_server_lock(struct ovsdb_server
*server
,
186 struct ovsdb_session
*session
,
187 const char *lock_name
,
188 enum ovsdb_lock_mode mode
,
189 struct ovsdb_session
**victimp
)
191 uint32_t hash
= hash_string(lock_name
, 0);
192 struct ovsdb_lock_waiter
*waiter
, *victim
;
193 struct ovsdb_lock
*lock
;
195 lock
= ovsdb_server_create_lock__(server
, lock_name
, hash
);
196 victim
= (mode
== OVSDB_LOCK_STEAL
&& !ovs_list_is_empty(&lock
->waiters
)
197 ? ovsdb_lock_get_owner(lock
)
200 waiter
= xmalloc(sizeof *waiter
);
202 waiter
->lock_name
= xstrdup(lock_name
);
204 if (mode
== OVSDB_LOCK_STEAL
) {
205 ovs_list_push_front(&lock
->waiters
, &waiter
->lock_node
);
207 ovs_list_push_back(&lock
->waiters
, &waiter
->lock_node
);
209 waiter
->session
= session
;
210 hmap_insert(&waiter
->session
->waiters
, &waiter
->session_node
, hash
);
212 if (victim
&& victim
->mode
== OVSDB_LOCK_STEAL
) {
213 ovsdb_lock_waiter_remove(victim
);
215 *victimp
= victim
? victim
->session
: NULL
;