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