libctdb: add ctdb arg to more functions.
[sahlberg/ctdb.git] / libctdb / tst.c
1 /*
2  * Example program to demonstrate the libctdb api
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 /*
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)
22  *
23  * This program can then be compiled using
24  *    gcc -o tst tst.c -ltdb -lctdb
25  *
26  *
27  */
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <poll.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <err.h>
35 #include <stdbool.h>
36 #include <tdb.h>
37 #include <ctdb.h>
38
39 TDB_DATA key;
40
41 void msg_h(struct ctdb_connection *ctdb, uint64_t srvid, TDB_DATA data, void *private_data)
42 {
43         printf("Message received on port %d : %s\n", (int)srvid, data.dptr);
44 }
45
46 static void pnn_cb(struct ctdb_connection *ctdb,
47                    struct ctdb_request *req, void *private)
48 {
49         int status;
50         uint32_t pnn;
51
52         status = ctdb_getpnn_recv(ctdb, req, &pnn);
53         ctdb_request_free(ctdb, req);
54         if (status != 0) {
55                 printf("Error reading PNN\n");
56                 return;
57         }
58         printf("status:%d pnn:%d\n", status, pnn);
59 }
60
61 static void rm_cb(struct ctdb_connection *ctdb,
62                   struct ctdb_request *req, void *private)
63 {
64         int status;
65         uint32_t rm;
66
67         status = ctdb_getrecmaster_recv(ctdb, req, &rm);
68         ctdb_request_free(ctdb, req);
69         if (status != 0) {
70                 printf("Error reading RECMASTER\n");
71                 return;
72         }
73
74         printf("GETRECMASTER ASYNC: status:%d recmaster:%d\n", status, rm);
75 }
76
77 /*
78  * example on how to first read(non-existing recortds are implicitely created
79  * on demand) a record and change it in the callback.
80  * This forms the atom for the read-modify-write cycle.
81  *
82  * Pure read, or pure write are just special cases of this cycle.
83  */
84 static void rrl_cb(struct ctdb_db *ctdb_db,
85                    struct ctdb_lock *lock, TDB_DATA outdata, void *private)
86 {
87         TDB_DATA data;
88         char tmp[256];
89         bool *rrl_cb_called = private;
90
91         *rrl_cb_called = true;
92
93         if (!lock) {
94                 printf("rrl_cb returned error\n");
95                 return;
96         }
97
98         printf("rrl size:%d data:%.*s\n", outdata.dsize,
99                outdata.dsize, outdata.dptr);
100         if (outdata.dsize == 0) {
101                 tmp[0] = 0;
102         } else {
103                 strcpy(tmp, outdata.dptr);
104         }
105         strcat(tmp, "*");
106
107         data.dptr  = tmp;
108         data.dsize = strlen(tmp) + 1;
109         ctdb_writerecord(lock, data);
110
111         printf("Wrote new record : %s\n", tmp);
112
113         ctdb_release_lock(lock);
114 }
115
116 static bool registered = false;
117 void message_handler_cb(struct ctdb_connection *ctdb,
118                         struct ctdb_request *req, void *private)
119 {
120         if (ctdb_set_message_handler_recv(ctdb, req) != 0) {
121                 err(1, "registering message");
122         }
123         ctdb_request_free(ctdb, req);
124         printf("Message handler registered\n");
125         registered = true;
126 }
127
128 int main(int argc, char *argv[])
129 {
130         struct ctdb_connection *ctdb_connection;
131         struct ctdb_request *handle;
132         struct ctdb_db *ctdb_db_context;
133         struct pollfd pfd;
134         uint32_t recmaster;
135         int ret;
136         TDB_DATA msg;
137         bool rrl_cb_called = false;
138
139
140         ctdb_connection = ctdb_connect("/tmp/ctdb.socket");
141         if (!ctdb_connection)
142                 err(1, "Connecting to /tmp/ctdb.socket");
143
144         pfd.fd = ctdb_get_fd(ctdb_connection);
145
146         handle = ctdb_set_message_handler_send(ctdb_connection, 55, msg_h,
147                                                message_handler_cb, NULL);
148         if (handle == NULL) {
149                 printf("Failed to register message port\n");
150                 exit(10);
151         }
152
153         /* Hack for testing: this makes sure registration goes out. */
154         while (!registered) {
155                 ctdb_service(ctdb_connection, POLLIN|POLLOUT);
156         }
157
158         msg.dptr="HelloWorld";
159         msg.dsize = strlen(msg.dptr);
160
161         ret = ctdb_send_message(ctdb_connection, 0, 55, msg);
162         if (ret != 0) {
163                 printf("Failed to send message. Aborting\n");
164                 exit(10);
165         }
166
167         handle = ctdb_getrecmaster_send(ctdb_connection, 0, rm_cb, NULL);
168         if (handle == NULL) {
169                 printf("Failed to send get_recmaster control\n");
170                 exit(10);
171         }
172
173         ctdb_db_context = ctdb_attachdb(ctdb_connection, "test_test.tdb", 0, 0);
174         if (!ctdb_db_context) {
175                 printf("Failed to attach to database\n");
176                 exit(10);
177         }
178
179         /*
180          * SYNC call with callback to read the recmaster
181          * calls the blocking sync function.
182          * Avoid this mode for performance critical tasks
183          */
184         ret = ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster);
185         if (ret != 0) {
186                 printf("Failed to receive response to getrecmaster\n");
187                 exit(10);
188         }
189         printf("GETRECMASTER SYNC: status:%d recmaster:%d\n", ret, recmaster);
190
191
192         handle = ctdb_getpnn_send(ctdb_connection, CTDB_CURRENT_NODE,
193                                   pnn_cb, NULL);
194         if (handle == NULL) {
195                 printf("Failed to send get_pnn control\n");
196                 exit(10);
197         }
198
199         /* In the non-contended case the callback might be invoked
200          * immediately, before ctdb_readrecordlock_async() returns.
201          * In the contended case the callback will be invoked later.
202          *
203          * Normally an application would not care whether the callback
204          * has already been invoked here or not, but if the application
205          * needs to know, it can use the *private_data pointer
206          * to pass data through to the callback and back.
207          */
208         if (!ctdb_readrecordlock_async(ctdb_db_context, key,
209                                        rrl_cb, &rrl_cb_called)) {
210                 printf("Failed to send READRECORDLOCK\n");
211                 exit(10);
212         }
213         if (!rrl_cb_called) {
214                 printf("READRECORDLOCK is async\n");
215         }
216         for (;;) {
217
218           pfd.events = ctdb_which_events(ctdb_connection);
219           if (poll(&pfd, 1, -1) < 0) {
220             printf("Poll failed");
221             exit(10);
222           }
223           if (ctdb_service(ctdb_connection, pfd.revents) < 0) {
224                   err(1, "Failed to service");
225           }
226         }
227
228         return 0;
229 }