6fd376a7f86a2b8ac8024434fbfcf6ef35585a4b
[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 <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(req, &pnn);
53         ctdb_request_free(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(req, &rm);
68         ctdb_request_free(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_connection *ctdb,
85                   struct ctdb_request *req, void *private)
86 {
87         struct ctdb_lock *lock;
88         TDB_DATA outdata;
89         TDB_DATA data;
90         char tmp[256];
91
92         lock = ctdb_readrecordlock_recv(private, req, &outdata);
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(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
138         ctdb_connection = ctdb_connect("/tmp/ctdb.socket");
139         if (!ctdb_connection)
140                 err(1, "Connecting to /tmp/ctdb.socket");
141
142         pfd.fd = ctdb_get_fd(ctdb_connection);
143
144         handle = ctdb_set_message_handler_send(ctdb_connection, 55, msg_h,
145                                                message_handler_cb, NULL);
146         if (handle == NULL) {
147                 printf("Failed to register message port\n");
148                 exit(10);
149         }
150
151         /* Hack for testing: this makes sure registration goes out. */
152         while (!registered) {
153                 ctdb_service(ctdb_connection, POLLIN|POLLOUT);
154         }
155
156         msg.dptr="HelloWorld";
157         msg.dsize = strlen(msg.dptr);
158
159         ret = ctdb_send_message(ctdb_connection, 0, 55, msg);
160         if (ret != 0) {
161                 printf("Failed to send message. Aborting\n");
162                 exit(10);
163         }
164
165         handle = ctdb_getrecmaster_send(ctdb_connection, 0, rm_cb, NULL);
166         if (handle == NULL) {
167                 printf("Failed to send get_recmaster control\n");
168                 exit(10);
169         }
170
171         ctdb_db_context = ctdb_attachdb(ctdb_connection, "test_test.tdb", 0, 0);
172         if (!ctdb_db_context) {
173                 printf("Failed to attach to database\n");
174                 exit(10);
175         }
176
177         /*
178          * SYNC call with callback to read the recmaster
179          * calls the blocking sync function.
180          * Avoid this mode for performance critical tasks
181          */
182         ret = ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster);
183         if (ret != 0) {
184                 printf("Failed to receive response to getrecmaster\n");
185                 exit(10);
186         }
187         printf("GETRECMASTER SYNC: status:%d recmaster:%d\n", ret, recmaster);
188
189
190         handle = ctdb_getpnn_send(ctdb_connection, CTDB_CURRENT_NODE,
191                                   pnn_cb, NULL);
192         if (handle == NULL) {
193                 printf("Failed to send get_pnn control\n");
194                 exit(10);
195         }
196
197         if (!ctdb_readrecordlock_send(ctdb_db_context, key, &handle,
198                                       rrl_cb, ctdb_db_context)) {
199                 printf("Failed to send READRECORDLOCK\n");
200                 exit(10);
201         }
202         if (handle) {
203                 printf("READRECORDLOCK is async\n");
204         }
205         for (;;) {
206
207           pfd.events = ctdb_which_events(ctdb_connection);
208           if (poll(&pfd, 1, -1) < 0) {
209             printf("Poll failed");
210             exit(10);
211           }
212           if (ctdb_service(ctdb_connection, pfd.revents) < 0) {
213                   err(1, "Failed to service");
214           }
215         }
216
217         return 0;
218 }