693de9fef38fb76f0325f90a6393060b28e3a381
[bbaumbach/samba-autobuild/.git] / source4 / cluster / ctdb / ctdb_cluster.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    ctdb clustering hooks
5
6    Copyright (C) Andrew Tridgell 2006
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "lib/events/events.h"
24 #include "cluster/cluster.h"
25 #include "system/filesys.h"
26 #include "cluster/cluster_private.h"
27 #include "lib/tdb/include/tdb.h"
28 #include "include/ctdb.h"
29 #include "db_wrap.h"
30 #include "lib/util/dlinklist.h"
31 #include "param/param.h"
32
33 /* a linked list of messaging handlers, allowing incoming messages
34    to be directed to the right messaging context */
35 struct cluster_messaging_list {
36         struct cluster_messaging_list *next, *prev;
37         struct cluster_state *state;
38         struct messaging_context *msg;
39         struct server_id server;
40         cluster_message_fn_t handler;
41 };
42
43 struct cluster_state {
44         struct ctdb_context *ctdb;
45         struct cluster_messaging_list *list;
46         uint32_t vnn;
47 };
48
49
50
51 /*
52   return a server_id for a ctdb node
53 */
54 static struct server_id ctdb_id(struct cluster_ops *ops, uint32_t id)
55 {
56         struct cluster_state *state = (struct cluster_state *)ops->private;
57         struct ctdb_context *ctdb = state->ctdb;
58         struct server_id server_id;
59         server_id.node = ctdb_get_vnn(ctdb);
60         server_id.id = id;
61         return server_id;
62 }
63
64
65 /*
66   return a server_id as a string
67 */
68 static const char *ctdb_id_string(struct cluster_ops *ops, 
69                                   TALLOC_CTX *mem_ctx, struct server_id id)
70 {
71         return talloc_asprintf(mem_ctx, "%u.%u", id.node, id.id);
72 }
73
74 /*
75   this is an interim method for subsystems that have not yet been
76   converted to use the ctdb api. It opens a shared database in the
77   cluster temporary area, using TDB_CLEAR_IF_FIRST which relies on
78   correct operation of fcntl locks on the shared fileystem.
79 */
80 static struct tdb_wrap *ctdb_tdb_tmp_open(struct cluster_ops *ops,
81                                           TALLOC_CTX *mem_ctx, const char *dbname, 
82                                           int flags)
83 {
84         const char *dir = lp_parm_string(-1, "ctdb", "shared data");
85         char *path;
86         struct tdb_wrap *w;
87         if (dir == NULL) {
88                 DEBUG(0,("ERROR: You must set 'ctdb:shared data' to a cluster shared path\n"));
89                 return NULL;
90         }
91         path = talloc_asprintf(mem_ctx, "%s/%s", dir, dbname);
92         w = tdb_wrap_open(mem_ctx, path, 0,  
93                           flags | TDB_CLEAR_IF_FIRST,
94                           O_RDWR|O_CREAT, 0600);
95         talloc_free(path);
96         return w;
97 }
98
99 /*
100   get at the ctdb handle
101 */
102 static void *ctdb_backend_handle(struct cluster_ops *ops)
103 {
104         struct cluster_state *state = (struct cluster_state *)ops->private;
105         return (void *)state->ctdb;
106 }
107
108 struct ctdb_handler_state {
109         struct cluster_state *state;
110         cluster_message_fn_t handler;
111         struct messaging_context *msg;
112 };
113
114 /*
115   dispatch incoming ctdb messages
116 */
117 static void ctdb_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
118                                  TDB_DATA data, void *private)
119 {
120         struct ctdb_handler_state *s = talloc_get_type(private, 
121                                                        struct ctdb_handler_state);
122         DATA_BLOB blob;
123         blob.data = data.dptr;
124         blob.length = data.dsize;
125         s->handler(s->msg, blob);
126 }
127
128 static int ctdb_handler_destructor(struct ctdb_handler_state *s)
129 {
130         /* XXX - tell ctdb to de-register the message handler */
131         return 0;
132 }
133
134 /*
135   setup a handler for ctdb messages
136 */
137 static NTSTATUS ctdb_message_init(struct cluster_ops *ops,
138                                   struct messaging_context *msg, 
139                                   struct server_id server,
140                                   cluster_message_fn_t handler)
141 {
142         struct cluster_state *state = (struct cluster_state *)ops->private;
143         struct ctdb_handler_state *h;
144         int ret;
145
146         h = talloc(msg, struct ctdb_handler_state);
147         NT_STATUS_HAVE_NO_MEMORY(h);
148
149         h->state = state;
150         h->handler = handler;
151         h->msg = msg;
152
153         talloc_set_destructor(h, ctdb_handler_destructor);
154
155         /* setup a message handler */
156         ret = ctdb_set_message_handler(state->ctdb, server.id, 
157                                        ctdb_message_handler, h);
158         if (ret == -1) {
159                 DEBUG(0,("ctdb_set_message_handler failed - %s\n", 
160                          ctdb_errstr(state->ctdb)));
161                 exit(1);
162         }
163
164         return NT_STATUS_OK;
165 }
166
167 /*
168   send a ctdb message to another node
169 */
170 static NTSTATUS ctdb_message_send(struct cluster_ops *ops,
171                                   struct server_id server, DATA_BLOB *data)
172 {
173         struct cluster_state *state = (struct cluster_state *)ops->private;
174         struct ctdb_context *ctdb = state->ctdb;
175         TDB_DATA tdata;
176         int ret;
177
178         tdata.dptr = data->data;
179         tdata.dsize = data->length;
180
181         ret = ctdb_send_message(ctdb, server.node, server.id, tdata);
182         if (ret != 0) {
183                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
184         }
185         return NT_STATUS_OK;
186 }
187
188 static struct cluster_ops cluster_ctdb_ops = {
189         .cluster_id           = ctdb_id,
190         .cluster_id_string    = ctdb_id_string,
191         .cluster_tdb_tmp_open = ctdb_tdb_tmp_open,
192         .backend_handle       = ctdb_backend_handle,
193         .message_init         = ctdb_message_init,
194         .message_send         = ctdb_message_send,
195         .private           = NULL
196 };
197
198 /* initialise ctdb */
199 void cluster_ctdb_init(struct event_context *ev, const char *model)
200 {
201         struct cluster_state *state;
202         int ret;
203
204         if (!lp_parm_bool(-1, "ctdb", "enable", False)) {
205                 return;
206         }
207
208         state = talloc(ev, struct cluster_state);
209         if (state == NULL) goto failed;
210
211         state->ctdb = ctdb_init(ev);
212         if (state->ctdb == NULL) goto failed;
213
214         ret = ctdb_socket_connect(state->ctdb);
215         if (ret == -1) {
216                 DEBUG(0,(__location__ " Failed to connect to ctdb socket\n"));
217                 goto failed;
218         }
219
220         /* get our vnn */
221         state->vnn = ctdb_ctrl_getvnn(state->ctdb, timeval_zero(), CTDB_CURRENT_NODE);
222         if (state->vnn == (uint32_t)-1) {
223                 DEBUG(0,(__location__ " Failed to get ctdb vnn\n"));
224                 goto failed;
225         }
226
227         state->list = NULL;
228
229         cluster_ctdb_ops.private = state;
230
231         cluster_set_ops(&cluster_ctdb_ops);
232
233 #if 0
234         /* nasty hack for now ... */
235         {
236                 void brl_ctdb_init_ops(void);
237                 brl_ctdb_init_ops();
238         }
239 #endif
240
241         return;
242         
243 failed:
244         DEBUG(0,("cluster_ctdb_init failed\n"));
245         talloc_free(state);
246 }