Test suite: Tweak NFS tickle test.
[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         if (!ctdb_writerecord(ctdb_db, lock, data))
111                 printf("Error writing data!\n");
112
113         /* Release the lock as quickly as possible */
114         ctdb_release_lock(ctdb_db, lock);
115
116         printf("Wrote new record : %s\n", tmp);
117
118 }
119
120 static bool registered = false;
121 void message_handler_cb(struct ctdb_connection *ctdb,
122                         struct ctdb_request *req, void *private)
123 {
124         if (!ctdb_set_message_handler_recv(ctdb, req)) {
125                 err(1, "registering message");
126         }
127         ctdb_request_free(ctdb, req);
128         printf("Message handler registered\n");
129         registered = true;
130 }
131
132 int main(int argc, char *argv[])
133 {
134         struct ctdb_connection *ctdb_connection;
135         struct ctdb_request *handle;
136         struct ctdb_db *ctdb_db_context;
137         struct pollfd pfd;
138         uint32_t recmaster;
139         TDB_DATA msg;
140         bool rrl_cb_called = false;
141
142         ctdb_log_level = LOG_DEBUG;
143         ctdb_connection = ctdb_connect("/tmp/ctdb.socket",
144                                        ctdb_log_file, stderr);
145         if (!ctdb_connection)
146                 err(1, "Connecting to /tmp/ctdb.socket");
147
148         pfd.fd = ctdb_get_fd(ctdb_connection);
149
150         handle = ctdb_set_message_handler_send(ctdb_connection, 55,
151                                                msg_h, NULL,
152                                                message_handler_cb, NULL);
153         if (handle == NULL) {
154                 printf("Failed to register message port\n");
155                 exit(10);
156         }
157
158         /* Hack for testing: this makes sure registration goes out. */
159         while (!registered) {
160                 ctdb_service(ctdb_connection, POLLIN|POLLOUT);
161         }
162
163         msg.dptr="HelloWorld";
164         msg.dsize = strlen(msg.dptr);
165
166         if (!ctdb_send_message(ctdb_connection, 0, 55, msg)) {
167                 printf("Failed to send message. Aborting\n");
168                 exit(10);
169         }
170
171         handle = ctdb_getrecmaster_send(ctdb_connection, 0, rm_cb, NULL);
172         if (handle == NULL) {
173                 printf("Failed to send get_recmaster control\n");
174                 exit(10);
175         }
176
177         ctdb_db_context = ctdb_attachdb(ctdb_connection, "test_test.tdb",
178                                         false, 0);
179         if (!ctdb_db_context) {
180                 printf("Failed to attach to database\n");
181                 exit(10);
182         }
183
184         /*
185          * SYNC call with callback to read the recmaster
186          * calls the blocking sync function.
187          * Avoid this mode for performance critical tasks
188          */
189         if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
190                 printf("Failed to receive response to getrecmaster\n");
191                 exit(10);
192         }
193         printf("GETRECMASTER SYNC: recmaster:%d\n", recmaster);
194
195
196         handle = ctdb_getpnn_send(ctdb_connection, CTDB_CURRENT_NODE,
197                                   pnn_cb, NULL);
198         if (handle == NULL) {
199                 printf("Failed to send get_pnn control\n");
200                 exit(10);
201         }
202
203         /* In the non-contended case the callback might be invoked
204          * immediately, before ctdb_readrecordlock_async() returns.
205          * In the contended case the callback will be invoked later.
206          *
207          * Normally an application would not care whether the callback
208          * has already been invoked here or not, but if the application
209          * needs to know, it can use the *private_data pointer
210          * to pass data through to the callback and back.
211          */
212         if (!ctdb_readrecordlock_async(ctdb_db_context, key,
213                                        rrl_cb, &rrl_cb_called)) {
214                 printf("Failed to send READRECORDLOCK\n");
215                 exit(10);
216         }
217         if (!rrl_cb_called) {
218                 printf("READRECORDLOCK is async\n");
219         }
220         for (;;) {
221
222           pfd.events = ctdb_which_events(ctdb_connection);
223           if (poll(&pfd, 1, -1) < 0) {
224             printf("Poll failed");
225             exit(10);
226           }
227           if (ctdb_service(ctdb_connection, pfd.revents) < 0) {
228                   err(1, "Failed to service");
229           }
230         }
231
232         return 0;
233 }