4 Copyright (C) Andrew Tridgell 2006
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "lib/events/events.h"
23 #include "system/filesys.h"
26 #include "ctdb_private.h"
30 #define PARENT_SRVID 0
31 #define CHILD1_SRVID 1
32 #define CHILD2_SRVID 2
36 static struct timeval tp1,tp2;
38 static void start_timer(void)
40 gettimeofday(&tp1,NULL);
43 static double end_timer(void)
45 gettimeofday(&tp2,NULL);
46 return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
47 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
50 static void message_handler(struct ctdb_context *ctdb, uint32_t srvid,
51 TDB_DATA data, void *private_data)
55 static void child_handler(struct ctdb_context *ctdb, uint32_t srvid,
56 TDB_DATA data, void *private_data)
61 void test1(struct ctdb_db_context *ctdb_db)
63 TDB_DATA key, data, data2, store_data;
65 struct ctdb_record_handle *h;
68 test 1 : write data and read it back. should all be the same
70 printf("Test1: write and verify we can read it back: ");
71 key.dptr = discard_const("Record");
72 key.dsize = strlen((const char *)key.dptr)+1;
73 h = ctdb_fetch_lock(ctdb_db, ctdb_db, key, &data);
75 printf("test1: ctdb_fetch_lock() failed\n");
79 store_data.dptr = discard_const("data to store");
80 store_data.dsize = strlen((const char *)store_data.dptr)+1;
81 ret = ctdb_record_store(h, store_data);
84 printf("test1: ctdb_record_store() failed\n");
88 h = ctdb_fetch_lock(ctdb_db, ctdb_db, key, &data2);
90 printf("test1: ctdb_fetch_lock() failed\n");
94 /* hopefully data2 will now contain the record written above */
95 if (!strcmp("data to store", (const char *)data2.dptr)) {
102 /* just write it back to unlock it */
103 ret = ctdb_record_store(h, store_data);
106 printf("test1: ctdb_record_store() failed\n");
111 void child(int srvid, struct event_context *ev, struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db)
115 struct ctdb_record_handle *h;
117 data.dptr=discard_const("dummy message");
118 data.dsize=strlen((const char *)data.dptr)+1;
120 ctdb_set_message_handler(ctdb, srvid, child_handler, NULL);
122 ctdb_send_message(ctdb, ctdb_get_vnn(ctdb), PARENT_SRVID, data);
128 /* fetch and lock the record */
129 key.dptr = discard_const("Record");
130 key.dsize = strlen((const char *)key.dptr)+1;
131 printf("client:%d fetching the record\n",srvid);
132 h = ctdb_fetch_lock(ctdb_db, ctdb_db, key, &data2);
133 printf("client:%d the record is fetched and locked\n",srvid);
135 printf("client: ctdb_fetch_lock() failed\n");
138 ctdb_send_message(ctdb, ctdb_get_vnn(ctdb), PARENT_SRVID, data);
140 /* wait until parent tells us to release the lock */
145 printf("child %d terminating\n",srvid);
153 int main(int argc, const char *argv[])
155 struct ctdb_context *ctdb;
156 struct ctdb_db_context *ctdb_db;
159 struct poptOption popt_options[] = {
165 const char **extra_argv;
169 struct event_context *ev;
171 pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
173 while ((opt = poptGetNextOpt(pc)) != -1) {
176 fprintf(stderr, "Invalid option %s: %s\n",
177 poptBadOption(pc, 0), poptStrerror(opt));
182 /* setup the remaining options for the main program to use */
183 extra_argv = poptGetArgs(pc);
186 while (extra_argv[extra_argc]) extra_argc++;
189 ev = event_context_init(NULL);
191 /* initialise ctdb */
192 ctdb = ctdb_cmdline_init(ev);
194 printf("Failed to init ctdb\n");
198 /* attach to a specific database */
199 ctdb_db = ctdb_attach(ctdb, "test.tdb", TDB_DEFAULT, O_RDWR|O_CREAT|O_TRUNC, 0666);
201 printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb));
205 /* start the protocol running */
206 ret = ctdb_start(ctdb);
209 /* wait until all nodes are connected (should not be needed
210 outside of test code) */
211 ctdb_connect_wait(ctdb);
215 start two child processes
219 set up a message handler so our child processes can talk to us
221 ctdb_set_message_handler(ctdb, PARENT_SRVID, message_handler, NULL);
225 child(CHILD1_SRVID, ev, ctdb, ctdb_db);
227 child(CHILD2_SRVID, ev, ctdb, ctdb_db);
232 test 1 : write data and read it back.
237 wait until both children have sent us a message they have started
239 printf("Wait for both child processes to start: ");
247 send message to child 1 to make it to fetch and lock the record
249 data.dptr=discard_const("dummy message");
250 data.dsize=strlen((const char *)data.dptr)+1;
251 ctdb_send_message(ctdb, ctdb_get_vnn(ctdb), CHILD1_SRVID, data);
253 /* wait for child 1 to complete fetching and locking the record */
258 /* now tell child 2 to fetch and lock the same record */
259 ctdb_send_message(ctdb, ctdb_get_vnn(ctdb), CHILD2_SRVID, data);
261 /* wait a while for child 2 to complete fetching and locking the
262 record, this should fail since the record is already locked
263 by the first child */
265 while ( (end_timer() < 1.0) && (num_msg!=4) ) {
269 printf("Child 2 did not get the lock since it is held by client 1:SUCCESS\n");
271 printf("Child 2 did get the lock:FAILURE\n");
275 /* send message to child 1 to terminate, which should let child 2
278 ctdb_send_message(ctdb, ctdb_get_vnn(ctdb), CHILD1_SRVID, data);
281 /* wait for a final message from child 2 it has received the lock
282 which indicates success */
286 printf("child 2 aquired the lock after child 1 terminated:SUCCESS\n");
288 /* send a message to child 2 to tell it to terminate too */
289 ctdb_send_message(ctdb, ctdb_get_vnn(ctdb), CHILD2_SRVID, data);
292 printf("Test was SUCCESSFUL\n");