2 wait for a tdb chain lock
4 Copyright (C) Andrew Tridgell 2006
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 3 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "lib/events/events.h"
22 #include "system/filesys.h"
23 #include "system/wait.h"
25 #include "lib/tdb/include/tdb.h"
26 #include "../include/ctdb_private.h"
29 struct lockwait_handle {
30 struct ctdb_context *ctdb;
35 void (*callback)(void *);
36 struct timeval start_time;
39 static void lockwait_handler(struct event_context *ev, struct fd_event *fde,
40 uint16_t flags, void *private_data)
42 struct lockwait_handle *h = talloc_get_type(private_data,
43 struct lockwait_handle);
44 void (*callback)(void *) = h->callback;
45 void *p = h->private_data;
46 pid_t child = h->child;
47 talloc_set_destructor(h, NULL);
49 ctdb_latency(&h->ctdb->status.max_lockwait_latency, h->start_time);
50 h->ctdb->status.pending_lockwait_calls--;
53 waitpid(child, NULL, 0);
56 static int lockwait_destructor(struct lockwait_handle *h)
58 h->ctdb->status.pending_lockwait_calls--;
60 kill(h->child, SIGKILL);
61 waitpid(h->child, NULL, 0);
66 setup a non-blocking chainlock on a tdb record. If this function
67 returns NULL then it could not get the chainlock. Otherwise it
68 returns a opaque handle, and will call callback() once it has
69 managed to get the chainlock. You can cancel it by using talloc_free
70 on the returned handle.
72 It is the callers responsibility to unlock the chainlock once
75 struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db,
77 void (*callback)(void *private_data),
80 struct lockwait_handle *result;
83 ctdb_db->ctdb->status.lockwait_calls++;
84 ctdb_db->ctdb->status.pending_lockwait_calls++;
86 if (!(result = talloc_zero(ctdb_db, struct lockwait_handle))) {
87 ctdb_db->ctdb->status.pending_lockwait_calls--;
91 ret = pipe(result->fd);
95 ctdb_db->ctdb->status.pending_lockwait_calls--;
99 result->child = fork();
101 if (result->child == (pid_t)-1) {
102 close(result->fd[0]);
103 close(result->fd[1]);
105 ctdb_db->ctdb->status.pending_lockwait_calls--;
109 result->callback = callback;
110 result->private_data = private_data;
111 result->ctdb = ctdb_db->ctdb;
113 if (result->child == 0) {
114 close(result->fd[0]);
116 * Do we need a tdb_reopen here?
118 tdb_chainlock(ctdb_db->ltdb->tdb, key);
122 close(result->fd[1]);
123 talloc_set_destructor(result, lockwait_destructor);
125 result->fde = event_add_fd(ctdb_db->ctdb->ev, result, result->fd[0],
126 EVENT_FD_READ, lockwait_handler,
128 if (result->fde == NULL) {
130 ctdb_db->ctdb->status.pending_lockwait_calls--;
134 result->start_time = timeval_current();