d3afe8d8d173ec73efe33cbe1ac67af6c1339587
[rusty/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 <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         int status;
51         uint32_t pnn;
52
53         status = ctdb_getpnn_recv(ctdb, req, &pnn);
54         ctdb_request_free(ctdb, req);
55         if (status != 0) {
56                 printf("Error reading PNN\n");
57                 return;
58         }
59         printf("status:%d pnn:%d\n", status, pnn);
60 }
61
62 static void rm_cb(struct ctdb_connection *ctdb,
63                   struct ctdb_request *req, void *private)
64 {
65         int status;
66         uint32_t rm;
67
68         status = ctdb_getrecmaster_recv(ctdb, req, &rm);
69         ctdb_request_free(ctdb, req);
70         if (status != 0) {
71                 printf("Error reading RECMASTER\n");
72                 return;
73         }
74
75         printf("GETRECMASTER ASYNC: status:%d recmaster:%d\n", status, 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) != 0) {
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         int ret;
137         TDB_DATA msg;
138         bool rrl_cb_called = false;
139
140         ctdb_log_level = LOG_DEBUG;
141         ctdb_connection = ctdb_connect("/tmp/ctdb.socket",
142                                        ctdb_log_file, stderr);
143         if (!ctdb_connection)
144                 err(1, "Connecting to /tmp/ctdb.socket");
145
146         pfd.fd = ctdb_get_fd(ctdb_connection);
147
148         handle = ctdb_set_message_handler_send(ctdb_connection, 55, msg_h,
149                                                message_handler_cb, NULL);
150         if (handle == NULL) {
151                 printf("Failed to register message port\n");
152                 exit(10);
153         }
154
155         /* Hack for testing: this makes sure registration goes out. */
156         while (!registered) {
157                 ctdb_service(ctdb_connection, POLLIN|POLLOUT);
158         }
159
160         msg.dptr="HelloWorld";
161         msg.dsize = strlen(msg.dptr);
162
163         ret = ctdb_send_message(ctdb_connection, 0, 55, msg);
164         if (ret != 0) {
165                 printf("Failed to send message. Aborting\n");
166                 exit(10);
167         }
168
169         handle = ctdb_getrecmaster_send(ctdb_connection, 0, rm_cb, NULL);
170         if (handle == NULL) {
171                 printf("Failed to send get_recmaster control\n");
172                 exit(10);
173         }
174
175         ctdb_db_context = ctdb_attachdb(ctdb_connection, "test_test.tdb", 0, 0);
176         if (!ctdb_db_context) {
177                 printf("Failed to attach to database\n");
178                 exit(10);
179         }
180
181         /*
182          * SYNC call with callback to read the recmaster
183          * calls the blocking sync function.
184          * Avoid this mode for performance critical tasks
185          */
186         ret = ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster);
187         if (ret != 0) {
188                 printf("Failed to receive response to getrecmaster\n");
189                 exit(10);
190         }
191         printf("GETRECMASTER SYNC: status:%d recmaster:%d\n", ret, recmaster);
192
193
194         handle = ctdb_getpnn_send(ctdb_connection, CTDB_CURRENT_NODE,
195                                   pnn_cb, NULL);
196         if (handle == NULL) {
197                 printf("Failed to send get_pnn control\n");
198                 exit(10);
199         }
200
201         /* In the non-contended case the callback might be invoked
202          * immediately, before ctdb_readrecordlock_async() returns.
203          * In the contended case the callback will be invoked later.
204          *
205          * Normally an application would not care whether the callback
206          * has already been invoked here or not, but if the application
207          * needs to know, it can use the *private_data pointer
208          * to pass data through to the callback and back.
209          */
210         if (!ctdb_readrecordlock_async(ctdb_db_context, key,
211                                        rrl_cb, &rrl_cb_called)) {
212                 printf("Failed to send READRECORDLOCK\n");
213                 exit(10);
214         }
215         if (!rrl_cb_called) {
216                 printf("READRECORDLOCK is async\n");
217         }
218         for (;;) {
219
220           pfd.events = ctdb_which_events(ctdb_connection);
221           if (poll(&pfd, 1, -1) < 0) {
222             printf("Poll failed");
223             exit(10);
224           }
225           if (ctdb_service(ctdb_connection, pfd.revents) < 0) {
226                   err(1, "Failed to service");
227           }
228         }
229
230         return 0;
231 }