2010-05-26 13:55:19 +10:00
/*
* Example program to demonstrate the libctdb api
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
2010-06-02 09:24:17 +10:00
/*
* This program needs to be linked with libtdb and libctdb
* ( You need these packages installed : libtdb libtdb - devel
* ctdb and ctdb - devel )
*
* This program can then be compiled using
* gcc - o tst tst . c - ltdb - lctdb
*
*
*/
2010-05-20 16:01:28 +09:30
# include <stdio.h>
# include <stdint.h>
# include <poll.h>
# include <fcntl.h>
2010-05-20 16:16:04 +09:30
# include <string.h>
2010-05-20 16:07:30 +09:30
# include <stdlib.h>
# include <err.h>
2010-05-21 12:07:41 +09:30
# include <stdbool.h>
2010-06-04 20:27:06 +09:30
# include <syslog.h>
2010-06-02 09:24:17 +10:00
# include <tdb.h>
# include <ctdb.h>
2010-09-13 14:28:11 +10:00
# include <ctdb_protocol.h>
2010-05-20 16:01:28 +09:30
2010-05-20 16:16:04 +09:30
TDB_DATA key ;
2010-09-13 14:28:11 +10:00
2010-09-15 14:56:57 +10:00
char * ctdb_addr_to_str ( ctdb_sock_addr * addr )
{
static char cip [ 128 ] = " " ;
switch ( addr - > sa . sa_family ) {
case AF_INET :
inet_ntop ( addr - > ip . sin_family , & addr - > ip . sin_addr , cip , sizeof ( cip ) ) ;
break ;
case AF_INET6 :
inet_ntop ( addr - > ip6 . sin6_family , & addr - > ip6 . sin6_addr , cip , sizeof ( cip ) ) ;
break ;
default :
printf ( " ERROR, unknown family %u \n " , addr - > sa . sa_family ) ;
}
return cip ;
}
2010-09-13 14:28:11 +10:00
void print_nodemap ( struct ctdb_node_map * nodemap )
{
int i ;
printf ( " number of nodes:%d \n " , nodemap - > num ) ;
for ( i = 0 ; i < nodemap - > num ; i + + ) {
printf ( " Node:%d Address:%s Flags:%s%s%s%s%s%s \n " ,
nodemap - > nodes [ i ] . pnn ,
2010-09-15 14:56:57 +10:00
ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ,
2010-09-13 14:28:11 +10:00
nodemap - > nodes [ i ] . flags & NODE_FLAGS_DISCONNECTED ? " DISCONNECTED " : " " ,
nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ? " UNHEALTHY " : " " ,
nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ? " ADMIN DISABLED " : " " ,
nodemap - > nodes [ i ] . flags & NODE_FLAGS_BANNED ? " BANNED " : " " ,
nodemap - > nodes [ i ] . flags & NODE_FLAGS_DELETED ? " DELETED " : " " ,
nodemap - > nodes [ i ] . flags & NODE_FLAGS_STOPPED ? " STOPPED " : " " ) ;
}
}
2010-05-20 16:07:30 +09:30
void msg_h ( struct ctdb_connection * ctdb , uint64_t srvid , TDB_DATA data , void * private_data )
2010-05-20 16:01:28 +09:30
{
2010-09-15 14:56:57 +10:00
printf ( " Message received on port %llx : %s \n " , srvid , data . dptr ) ;
}
void rip_h ( struct ctdb_connection * ctdb , uint64_t srvid , TDB_DATA data , void * private_data )
{
printf ( " RELEASE IP message for %s \n " , data . dptr ) ;
}
void tip_h ( struct ctdb_connection * ctdb , uint64_t srvid , TDB_DATA data , void * private_data )
{
printf ( " TAKE IP message for %s \n " , data . dptr ) ;
2010-05-20 16:01:28 +09:30
}
2010-09-13 14:28:11 +10:00
static void gnm_cb ( struct ctdb_connection * ctdb ,
struct ctdb_request * req , void * private )
{
bool status ;
struct ctdb_node_map * nodemap ;
status = ctdb_getnodemap_recv ( ctdb , req , & nodemap ) ;
2011-08-19 17:05:36 +02:00
ctdb_request_free ( req ) ;
2010-09-13 14:28:11 +10:00
if ( ! status ) {
printf ( " Error reading NODEMAP \n " ) ;
return ;
}
printf ( " ASYNC response to getnodemap: \n " ) ;
print_nodemap ( nodemap ) ;
ctdb_free_nodemap ( nodemap ) ;
}
2010-09-15 14:56:57 +10:00
void print_ips ( struct ctdb_all_public_ips * ips )
{
int i ;
printf ( " Num public ips:%d \n " , ips - > num ) ;
for ( i = 0 ; i < ips - > num ; i + + ) {
printf ( " %s hosted on node %d \n " ,
ctdb_addr_to_str ( & ips - > ips [ i ] . addr ) ,
ips - > ips [ i ] . pnn ) ;
}
}
static void ips_cb ( struct ctdb_connection * ctdb ,
struct ctdb_request * req , void * private )
{
bool status ;
struct ctdb_all_public_ips * ips ;
status = ctdb_getpublicips_recv ( ctdb , req , & ips ) ;
2011-08-19 17:05:36 +02:00
ctdb_request_free ( req ) ;
2010-09-15 14:56:57 +10:00
if ( ! status ) {
printf ( " Error reading PUBLIC IPS \n " ) ;
return ;
}
printf ( " ASYNC response to getpublicips: \n " ) ;
print_ips ( ips ) ;
ctdb_free_publicips ( ips ) ;
}
2010-05-24 13:17:36 +09:30
static void pnn_cb ( struct ctdb_connection * ctdb ,
struct ctdb_request * req , void * private )
2010-05-20 16:16:04 +09:30
{
2010-06-04 20:19:25 +09:30
bool status ;
2010-05-24 13:17:36 +09:30
uint32_t pnn ;
2010-06-04 16:54:08 +09:30
status = ctdb_getpnn_recv ( ctdb , req , & pnn ) ;
2011-08-19 17:05:36 +02:00
ctdb_request_free ( req ) ;
2010-06-04 20:19:25 +09:30
if ( ! status ) {
2010-05-20 16:16:04 +09:30
printf ( " Error reading PNN \n " ) ;
return ;
}
2010-09-13 14:28:11 +10:00
printf ( " ASYNC RESPONSE TO GETPNN: pnn:%d \n " , pnn ) ;
2010-05-20 16:16:04 +09:30
}
2010-05-24 13:17:36 +09:30
static void rm_cb ( struct ctdb_connection * ctdb ,
struct ctdb_request * req , void * private )
2010-05-20 16:16:04 +09:30
{
2010-06-04 20:19:25 +09:30
bool status ;
2010-05-24 13:17:36 +09:30
uint32_t rm ;
2010-06-04 16:54:08 +09:30
status = ctdb_getrecmaster_recv ( ctdb , req , & rm ) ;
2011-08-19 17:05:36 +02:00
ctdb_request_free ( req ) ;
2010-06-04 20:19:25 +09:30
if ( ! status ) {
2010-05-20 16:16:04 +09:30
printf ( " Error reading RECMASTER \n " ) ;
return ;
}
2010-06-04 20:19:25 +09:30
printf ( " GETRECMASTER ASYNC: recmaster:%d \n " , rm ) ;
2010-05-20 16:16:04 +09:30
}
/*
* example on how to first read ( non - existing recortds are implicitely created
* on demand ) a record and change it in the callback .
* This forms the atom for the read - modify - write cycle .
*
* Pure read , or pure write are just special cases of this cycle .
*/
2010-06-04 13:33:08 +09:30
static void rrl_cb ( struct ctdb_db * ctdb_db ,
struct ctdb_lock * lock , TDB_DATA outdata , void * private )
2010-05-20 16:16:04 +09:30
{
TDB_DATA data ;
char tmp [ 256 ] ;
2010-06-04 14:20:17 +10:00
bool * rrl_cb_called = private ;
* rrl_cb_called = true ;
2010-05-20 16:16:04 +09:30
2010-05-24 13:17:36 +09:30
if ( ! lock ) {
printf ( " rrl_cb returned error \n " ) ;
2010-05-20 16:16:04 +09:30
return ;
}
printf ( " rrl size:%d data:%.*s \n " , outdata . dsize ,
outdata . dsize , outdata . dptr ) ;
if ( outdata . dsize = = 0 ) {
tmp [ 0 ] = 0 ;
} else {
strcpy ( tmp , outdata . dptr ) ;
}
strcat ( tmp , " * " ) ;
data . dptr = tmp ;
data . dsize = strlen ( tmp ) + 1 ;
2010-06-08 17:11:40 +09:30
if ( ! ctdb_writerecord ( ctdb_db , lock , data ) )
printf ( " Error writing data! \n " ) ;
2010-05-20 16:16:04 +09:30
2010-06-05 15:38:11 +10:00
/* Release the lock as quickly as possible */
2010-06-08 17:11:40 +09:30
ctdb_release_lock ( ctdb_db , lock ) ;
2010-06-05 15:38:11 +10:00
2010-05-20 16:16:04 +09:30
printf ( " Wrote new record : %s \n " , tmp ) ;
}
2010-05-21 12:07:41 +09:30
static bool registered = false ;
2010-05-24 13:17:36 +09:30
void message_handler_cb ( struct ctdb_connection * ctdb ,
struct ctdb_request * req , void * private )
2010-05-20 16:07:30 +09:30
{
2010-06-04 20:19:25 +09:30
if ( ! ctdb_set_message_handler_recv ( ctdb , req ) ) {
2010-05-24 13:17:36 +09:30
err ( 1 , " registering message " ) ;
}
2011-08-19 17:05:36 +02:00
ctdb_request_free ( req ) ;
2010-05-24 13:17:36 +09:30
printf ( " Message handler registered \n " ) ;
2010-05-21 12:07:41 +09:30
registered = true ;
2010-05-20 16:07:30 +09:30
}
2010-05-20 16:01:28 +09:30
2011-01-14 17:35:31 +11:00
static int traverse_callback ( struct ctdb_connection * ctdb_connection , struct ctdb_db * ctdb_db , int status , TDB_DATA key , TDB_DATA data , void * private_data )
{
if ( status = = TRAVERSE_STATUS_FINISHED ) {
printf ( " Traverse finished \n " ) ;
return 0 ;
}
if ( status = = TRAVERSE_STATUS_ERROR ) {
printf ( " Traverse failed \n " ) ;
return 1 ;
}
printf ( " traverse callback status:%d \n " , status ) ;
printf ( " key: %d [%s] \n " , key . dsize , key . dptr ) ;
printf ( " data:%d [%s] \n " , data . dsize , data . dptr ) ;
return 0 ;
}
2010-05-20 16:01:28 +09:30
int main ( int argc , char * argv [ ] )
{
2010-05-20 16:07:30 +09:30
struct ctdb_connection * ctdb_connection ;
struct ctdb_request * handle ;
2010-05-20 16:16:04 +09:30
struct ctdb_db * ctdb_db_context ;
2010-09-13 14:28:11 +10:00
struct ctdb_node_map * nodemap ;
2010-05-20 16:01:28 +09:30
struct pollfd pfd ;
2010-05-20 16:16:04 +09:30
uint32_t recmaster ;
2010-05-20 16:01:28 +09:30
TDB_DATA msg ;
2010-06-04 14:20:17 +10:00
bool rrl_cb_called = false ;
2010-09-15 14:56:57 +10:00
uint64_t srvid ;
2010-06-04 14:20:17 +10:00
2010-06-04 20:27:06 +09:30
ctdb_log_level = LOG_DEBUG ;
2010-06-04 20:27:03 +09:30
ctdb_connection = ctdb_connect ( " /tmp/ctdb.socket " ,
ctdb_log_file , stderr ) ;
2010-05-20 16:07:30 +09:30
if ( ! ctdb_connection )
err ( 1 , " Connecting to /tmp/ctdb.socket " ) ;
2010-05-20 16:01:28 +09:30
2010-05-20 16:07:30 +09:30
pfd . fd = ctdb_get_fd ( ctdb_connection ) ;
2010-05-20 16:01:28 +09:30
2010-09-15 14:56:57 +10:00
srvid = CTDB_SRVID_TEST_RANGE | 55 ;
handle = ctdb_set_message_handler_send ( ctdb_connection , srvid ,
2010-08-18 10:18:35 +10:00
msg_h , NULL ,
2010-09-15 14:56:57 +10:00
message_handler_cb , & srvid ) ;
2010-05-20 16:01:28 +09:30
if ( handle = = NULL ) {
printf ( " Failed to register message port \n " ) ;
exit ( 10 ) ;
}
2010-09-15 14:56:57 +10:00
/* Hack for testing: this makes sure registrations went out. */
2010-05-21 12:07:41 +09:30
while ( ! registered ) {
ctdb_service ( ctdb_connection , POLLIN | POLLOUT ) ;
}
2010-09-15 14:56:57 +10:00
handle = ctdb_set_message_handler_send ( ctdb_connection ,
CTDB_SRVID_RELEASE_IP ,
rip_h , NULL ,
message_handler_cb , NULL ) ;
if ( handle = = NULL ) {
printf ( " Failed to register message port for RELEASE IP \n " ) ;
exit ( 10 ) ;
}
handle = ctdb_set_message_handler_send ( ctdb_connection ,
CTDB_SRVID_TAKE_IP ,
tip_h , NULL ,
message_handler_cb , NULL ) ;
if ( handle = = NULL ) {
printf ( " Failed to register message port for TAKE IP \n " ) ;
exit ( 10 ) ;
}
2010-05-20 16:01:28 +09:30
msg . dptr = " HelloWorld " ;
msg . dsize = strlen ( msg . dptr ) ;
2010-09-15 14:56:57 +10:00
srvid = CTDB_SRVID_TEST_RANGE | 55 ;
if ( ! ctdb_send_message ( ctdb_connection , 0 , srvid , msg ) ) {
2010-05-20 16:01:28 +09:30
printf ( " Failed to send message. Aborting \n " ) ;
exit ( 10 ) ;
}
2010-05-20 16:07:30 +09:30
handle = ctdb_getrecmaster_send ( ctdb_connection , 0 , rm_cb , NULL ) ;
2010-05-20 16:01:28 +09:30
if ( handle = = NULL ) {
printf ( " Failed to send get_recmaster control \n " ) ;
exit ( 10 ) ;
}
2010-06-08 17:11:40 +09:30
ctdb_db_context = ctdb_attachdb ( ctdb_connection , " test_test.tdb " ,
false , 0 ) ;
2010-05-20 16:16:04 +09:30
if ( ! ctdb_db_context ) {
printf ( " Failed to attach to database \n " ) ;
exit ( 10 ) ;
}
/*
* SYNC call with callback to read the recmaster
* calls the blocking sync function .
* Avoid this mode for performance critical tasks
*/
2010-06-04 20:19:25 +09:30
if ( ! ctdb_getrecmaster ( ctdb_connection , CTDB_CURRENT_NODE , & recmaster ) ) {
2010-05-20 16:16:04 +09:30
printf ( " Failed to receive response to getrecmaster \n " ) ;
exit ( 10 ) ;
}
2010-06-04 20:19:25 +09:30
printf ( " GETRECMASTER SYNC: recmaster:%d \n " , recmaster ) ;
2010-05-20 16:16:04 +09:30
handle = ctdb_getpnn_send ( ctdb_connection , CTDB_CURRENT_NODE ,
pnn_cb , NULL ) ;
if ( handle = = NULL ) {
printf ( " Failed to send get_pnn control \n " ) ;
exit ( 10 ) ;
}
2010-06-04 14:20:17 +10:00
/* In the non-contended case the callback might be invoked
* immediately , before ctdb_readrecordlock_async ( ) returns .
* In the contended case the callback will be invoked later .
*
* Normally an application would not care whether the callback
* has already been invoked here or not , but if the application
* needs to know , it can use the * private_data pointer
* to pass data through to the callback and back .
*/
2010-06-04 13:33:08 +09:30
if ( ! ctdb_readrecordlock_async ( ctdb_db_context , key ,
2010-06-04 14:20:17 +10:00
rrl_cb , & rrl_cb_called ) ) {
2010-05-20 16:16:04 +09:30
printf ( " Failed to send READRECORDLOCK \n " ) ;
exit ( 10 ) ;
}
2010-06-04 13:33:08 +09:30
if ( ! rrl_cb_called ) {
2010-05-24 13:52:17 +09:30
printf ( " READRECORDLOCK is async \n " ) ;
}
2010-09-13 14:28:11 +10:00
/*
* Read the nodemap from a node ( async )
*/
handle = ctdb_getnodemap_send ( ctdb_connection , CTDB_CURRENT_NODE ,
gnm_cb , NULL ) ;
if ( handle = = NULL ) {
printf ( " Failed to send get_nodemap control \n " ) ;
exit ( 10 ) ;
}
2010-09-15 14:56:57 +10:00
/*
* Read the list of public ips from a node ( async )
*/
handle = ctdb_getpublicips_send ( ctdb_connection , CTDB_CURRENT_NODE ,
ips_cb , NULL ) ;
if ( handle = = NULL ) {
printf ( " Failed to send getpublicips control \n " ) ;
exit ( 10 ) ;
}
2010-09-13 14:28:11 +10:00
/*
* Read the nodemap from a node ( sync )
*/
if ( ! ctdb_getnodemap ( ctdb_connection , CTDB_CURRENT_NODE ,
& nodemap ) ) {
printf ( " Failed to receive response to getrecmaster \n " ) ;
exit ( 10 ) ;
}
printf ( " SYNC response to getnodemap: \n " ) ;
print_nodemap ( nodemap ) ;
ctdb_free_nodemap ( nodemap ) ;
2011-01-14 17:35:31 +11:00
printf ( " Traverse the test_test.tdb database \n " ) ;
ctdb_traverse_async ( ctdb_db_context , traverse_callback , NULL ) ;
2010-05-20 16:01:28 +09:30
for ( ; ; ) {
2010-05-20 16:07:30 +09:30
pfd . events = ctdb_which_events ( ctdb_connection ) ;
2010-05-20 16:01:28 +09:30
if ( poll ( & pfd , 1 , - 1 ) < 0 ) {
printf ( " Poll failed " ) ;
exit ( 10 ) ;
}
2010-05-20 16:07:30 +09:30
if ( ctdb_service ( ctdb_connection , pfd . revents ) < 0 ) {
err ( 1 , " Failed to service " ) ;
}
2010-05-20 16:01:28 +09:30
}
return 0 ;
}