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");