2 * Example program to demonstrate the libctdb api
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 * This program needs to be linked with libtdb and libctdb
20 * (You need these packages installed: libtdb libtdb-devel
21 * ctdb and ctdb-devel)
23 * This program can then be compiled using
24 * gcc -o tst tst.c -ltdb -lctdb
39 #include <ctdb_protocol.h>
44 char *ctdb_addr_to_str(ctdb_sock_addr
*addr
)
46 static char cip
[128] = "";
48 switch (addr
->sa
.sa_family
) {
50 inet_ntop(addr
->ip
.sin_family
, &addr
->ip
.sin_addr
, cip
, sizeof(cip
));
53 inet_ntop(addr
->ip6
.sin6_family
, &addr
->ip6
.sin6_addr
, cip
, sizeof(cip
));
56 printf("ERROR, unknown family %u\n", addr
->sa
.sa_family
);
62 void print_nodemap(struct ctdb_node_map
*nodemap
)
66 printf("number of nodes:%d\n", nodemap
->num
);
67 for (i
=0;i
<nodemap
->num
;i
++) {
68 printf("Node:%d Address:%s Flags:%s%s%s%s%s%s\n",
69 nodemap
->nodes
[i
].pnn
,
70 ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
),
71 nodemap
->nodes
[i
].flags
&NODE_FLAGS_DISCONNECTED
?"DISCONNECTED ":"",
72 nodemap
->nodes
[i
].flags
&NODE_FLAGS_UNHEALTHY
?"UNHEALTHY ":"",
73 nodemap
->nodes
[i
].flags
&NODE_FLAGS_PERMANENTLY_DISABLED
?"ADMIN DISABLED ":"",
74 nodemap
->nodes
[i
].flags
&NODE_FLAGS_BANNED
?"BANNED ":"",
75 nodemap
->nodes
[i
].flags
&NODE_FLAGS_DELETED
?"DELETED ":"",
76 nodemap
->nodes
[i
].flags
&NODE_FLAGS_STOPPED
?"STOPPED ":"");
80 void msg_h(struct ctdb_connection
*ctdb
, uint64_t srvid
, TDB_DATA data
, void *private_data
)
82 printf("Message received on port %llx : %s\n", srvid
, data
.dptr
);
85 void rip_h(struct ctdb_connection
*ctdb
, uint64_t srvid
, TDB_DATA data
, void *private_data
)
87 printf("RELEASE IP message for %s\n", data
.dptr
);
90 void tip_h(struct ctdb_connection
*ctdb
, uint64_t srvid
, TDB_DATA data
, void *private_data
)
92 printf("TAKE IP message for %s\n", data
.dptr
);
95 static void gnm_cb(struct ctdb_connection
*ctdb
,
96 struct ctdb_request
*req
, void *private)
99 struct ctdb_node_map
*nodemap
;
101 status
= ctdb_getnodemap_recv(ctdb
, req
, &nodemap
);
102 ctdb_request_free(req
);
104 printf("Error reading NODEMAP\n");
107 printf("ASYNC response to getnodemap:\n");
108 print_nodemap(nodemap
);
109 ctdb_free_nodemap(nodemap
);
112 void print_ips(struct ctdb_all_public_ips
*ips
)
116 printf("Num public ips:%d\n", ips
->num
);
117 for (i
=0; i
<ips
->num
;i
++) {
118 printf("%s hosted on node %d\n",
119 ctdb_addr_to_str(&ips
->ips
[i
].addr
),
124 static void ips_cb(struct ctdb_connection
*ctdb
,
125 struct ctdb_request
*req
, void *private)
128 struct ctdb_all_public_ips
*ips
;
130 status
= ctdb_getpublicips_recv(ctdb
, req
, &ips
);
131 ctdb_request_free(req
);
133 printf("Error reading PUBLIC IPS\n");
136 printf("ASYNC response to getpublicips:\n");
138 ctdb_free_publicips(ips
);
141 static void pnn_cb(struct ctdb_connection
*ctdb
,
142 struct ctdb_request
*req
, void *private)
147 status
= ctdb_getpnn_recv(ctdb
, req
, &pnn
);
148 ctdb_request_free(req
);
150 printf("Error reading PNN\n");
153 printf("ASYNC RESPONSE TO GETPNN: pnn:%d\n", pnn
);
156 static void rm_cb(struct ctdb_connection
*ctdb
,
157 struct ctdb_request
*req
, void *private)
162 status
= ctdb_getrecmaster_recv(ctdb
, req
, &rm
);
163 ctdb_request_free(req
);
165 printf("Error reading RECMASTER\n");
169 printf("GETRECMASTER ASYNC: recmaster:%d\n", rm
);
173 * example on how to first read(non-existing recortds are implicitely created
174 * on demand) a record and change it in the callback.
175 * This forms the atom for the read-modify-write cycle.
177 * Pure read, or pure write are just special cases of this cycle.
179 static void rrl_cb(struct ctdb_db
*ctdb_db
,
180 struct ctdb_lock
*lock
, TDB_DATA outdata
, void *private)
184 bool *rrl_cb_called
= private;
186 *rrl_cb_called
= true;
189 printf("rrl_cb returned error\n");
193 printf("rrl size:%d data:%.*s\n", outdata
.dsize
,
194 outdata
.dsize
, outdata
.dptr
);
195 if (outdata
.dsize
== 0) {
198 strcpy(tmp
, outdata
.dptr
);
203 data
.dsize
= strlen(tmp
) + 1;
204 if (!ctdb_writerecord(ctdb_db
, lock
, data
))
205 printf("Error writing data!\n");
207 /* Release the lock as quickly as possible */
208 ctdb_release_lock(ctdb_db
, lock
);
210 printf("Wrote new record : %s\n", tmp
);
214 static bool registered
= false;
215 void message_handler_cb(struct ctdb_connection
*ctdb
,
216 struct ctdb_request
*req
, void *private)
218 if (!ctdb_set_message_handler_recv(ctdb
, req
)) {
219 err(1, "registering message");
221 ctdb_request_free(req
);
222 printf("Message handler registered\n");
226 static int traverse_callback(struct ctdb_connection
*ctdb_connection
, struct ctdb_db
*ctdb_db
, int status
, TDB_DATA key
, TDB_DATA data
, void *private_data
)
228 if (status
== TRAVERSE_STATUS_FINISHED
) {
229 printf("Traverse finished\n");
232 if (status
== TRAVERSE_STATUS_ERROR
) {
233 printf("Traverse failed\n");
237 printf("traverse callback status:%d\n", status
);
238 printf("key: %d [%s]\n", key
.dsize
, key
.dptr
);
239 printf("data:%d [%s]\n", data
.dsize
, data
.dptr
);
245 int main(int argc
, char *argv
[])
247 struct ctdb_connection
*ctdb_connection
;
248 struct ctdb_request
*handle
;
249 struct ctdb_db
*ctdb_db_context
;
250 struct ctdb_node_map
*nodemap
;
254 bool rrl_cb_called
= false;
257 ctdb_log_level
= LOG_DEBUG
;
258 ctdb_connection
= ctdb_connect("/tmp/ctdb.socket",
259 ctdb_log_file
, stderr
);
260 if (!ctdb_connection
)
261 err(1, "Connecting to /tmp/ctdb.socket");
263 pfd
.fd
= ctdb_get_fd(ctdb_connection
);
265 srvid
= CTDB_SRVID_TEST_RANGE
|55;
266 handle
= ctdb_set_message_handler_send(ctdb_connection
, srvid
,
268 message_handler_cb
, &srvid
);
269 if (handle
== NULL
) {
270 printf("Failed to register message port\n");
274 /* Hack for testing: this makes sure registrations went out. */
275 while (!registered
) {
276 ctdb_service(ctdb_connection
, POLLIN
|POLLOUT
);
279 handle
= ctdb_set_message_handler_send(ctdb_connection
,
280 CTDB_SRVID_RELEASE_IP
,
282 message_handler_cb
, NULL
);
283 if (handle
== NULL
) {
284 printf("Failed to register message port for RELEASE IP\n");
288 handle
= ctdb_set_message_handler_send(ctdb_connection
,
291 message_handler_cb
, NULL
);
292 if (handle
== NULL
) {
293 printf("Failed to register message port for TAKE IP\n");
297 msg
.dptr
="HelloWorld";
298 msg
.dsize
= strlen(msg
.dptr
);
300 srvid
= CTDB_SRVID_TEST_RANGE
|55;
301 if (!ctdb_send_message(ctdb_connection
, 0, srvid
, msg
)) {
302 printf("Failed to send message. Aborting\n");
306 handle
= ctdb_getrecmaster_send(ctdb_connection
, 0, rm_cb
, NULL
);
307 if (handle
== NULL
) {
308 printf("Failed to send get_recmaster control\n");
312 ctdb_db_context
= ctdb_attachdb(ctdb_connection
, "test_test.tdb",
314 if (!ctdb_db_context
) {
315 printf("Failed to attach to database\n");
320 * SYNC call with callback to read the recmaster
321 * calls the blocking sync function.
322 * Avoid this mode for performance critical tasks
324 if (!ctdb_getrecmaster(ctdb_connection
, CTDB_CURRENT_NODE
, &recmaster
)) {
325 printf("Failed to receive response to getrecmaster\n");
328 printf("GETRECMASTER SYNC: recmaster:%d\n", recmaster
);
331 handle
= ctdb_getpnn_send(ctdb_connection
, CTDB_CURRENT_NODE
,
333 if (handle
== NULL
) {
334 printf("Failed to send get_pnn control\n");
338 /* In the non-contended case the callback might be invoked
339 * immediately, before ctdb_readrecordlock_async() returns.
340 * In the contended case the callback will be invoked later.
342 * Normally an application would not care whether the callback
343 * has already been invoked here or not, but if the application
344 * needs to know, it can use the *private_data pointer
345 * to pass data through to the callback and back.
347 if (!ctdb_readrecordlock_async(ctdb_db_context
, key
,
348 rrl_cb
, &rrl_cb_called
)) {
349 printf("Failed to send READRECORDLOCK\n");
352 if (!rrl_cb_called
) {
353 printf("READRECORDLOCK is async\n");
357 * Read the nodemap from a node (async)
359 handle
= ctdb_getnodemap_send(ctdb_connection
, CTDB_CURRENT_NODE
,
361 if (handle
== NULL
) {
362 printf("Failed to send get_nodemap control\n");
367 * Read the list of public ips from a node (async)
369 handle
= ctdb_getpublicips_send(ctdb_connection
, CTDB_CURRENT_NODE
,
371 if (handle
== NULL
) {
372 printf("Failed to send getpublicips control\n");
377 * Read the nodemap from a node (sync)
379 if (!ctdb_getnodemap(ctdb_connection
, CTDB_CURRENT_NODE
,
381 printf("Failed to receive response to getrecmaster\n");
384 printf("SYNC response to getnodemap:\n");
385 print_nodemap(nodemap
);
386 ctdb_free_nodemap(nodemap
);
388 printf("Traverse the test_test.tdb database\n");
389 ctdb_traverse_async(ctdb_db_context
, traverse_callback
, NULL
);
393 pfd
.events
= ctdb_which_events(ctdb_connection
);
394 if (poll(&pfd
, 1, -1) < 0) {
395 printf("Poll failed");
398 if (ctdb_service(ctdb_connection
, pfd
.revents
) < 0) {
399 err(1, "Failed to service");