2007-04-05 13:18:31 +10:00
/*
simple ctdb benchmark
Copyright ( C ) Andrew Tridgell 2006
2007-05-31 13:50:53 +10:00
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
2007-07-10 15:29:31 +10:00
the Free Software Foundation ; either version 3 of the License , or
2007-05-31 13:50:53 +10:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
2007-04-05 13:18:31 +10:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2007-05-31 13:50:53 +10:00
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
2007-07-10 15:29:31 +10:00
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2007-04-05 13:18:31 +10:00
*/
# include "includes.h"
# include "lib/events/events.h"
# include "system/filesys.h"
# include "popt.h"
2007-04-17 22:16:50 +10:00
# include "cmdline.h"
2007-04-05 13:18:31 +10:00
# include <sys/time.h>
# include <time.h>
static struct timeval tp1 , tp2 ;
static void start_timer ( void )
{
gettimeofday ( & tp1 , NULL ) ;
}
static double end_timer ( void )
{
gettimeofday ( & tp2 , NULL ) ;
return ( tp2 . tv_sec + ( tp2 . tv_usec * 1.0e-6 ) ) -
( tp1 . tv_sec + ( tp1 . tv_usec * 1.0e-6 ) ) ;
}
static int timelimit = 10 ;
static int num_records = 10 ;
2007-06-02 13:31:36 +10:00
static int num_nodes ;
2007-04-05 13:18:31 +10:00
static int msg_count ;
# define TESTKEY "testkey"
/*
fetch a record
store a expanded record
send a message to next node to tell it to do the same
*/
static void bench_fetch_1node ( struct ctdb_context * ctdb )
{
TDB_DATA key , data , nulldata ;
struct ctdb_db_context * ctdb_db ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
int dest , ret ;
2007-04-17 14:52:51 +10:00
struct ctdb_record_handle * h ;
2007-04-05 13:18:31 +10:00
2007-04-17 15:01:42 +10:00
key . dptr = discard_const ( TESTKEY ) ;
key . dsize = strlen ( TESTKEY ) ;
2007-04-05 13:18:31 +10:00
ctdb_db = ctdb_db_handle ( ctdb , " test.tdb " ) ;
2007-04-17 14:52:51 +10:00
h = ctdb_fetch_lock ( ctdb_db , tmp_ctx , key , & data ) ;
if ( h = = NULL ) {
2007-04-05 13:18:31 +10:00
printf ( " Failed to fetch record '%s' on node %d \n " ,
2007-09-04 10:18:44 +10:00
( const char * ) key . dptr , ctdb_get_pnn ( ctdb ) ) ;
2007-04-05 13:18:31 +10:00
talloc_free ( tmp_ctx ) ;
return ;
}
if ( data . dsize > 1000 ) {
data . dsize = 0 ;
}
if ( data . dsize = = 0 ) {
data . dptr = ( uint8_t * ) talloc_asprintf ( tmp_ctx , " Test data \n " ) ;
}
data . dptr = ( uint8_t * ) talloc_asprintf_append ( ( char * ) data . dptr ,
" msg_count=%d on node %d \n " ,
2007-09-04 10:18:44 +10:00
msg_count , ctdb_get_pnn ( ctdb ) ) ;
2007-04-05 13:18:31 +10:00
data . dsize = strlen ( ( const char * ) data . dptr ) + 1 ;
2007-04-17 14:52:51 +10:00
ret = ctdb_record_store ( h , data ) ;
2007-04-17 15:33:58 +10:00
talloc_free ( h ) ;
2007-04-05 13:18:31 +10:00
if ( ret ! = 0 ) {
printf ( " Failed to store record \n " ) ;
}
talloc_free ( tmp_ctx ) ;
/* tell the next node to do the same */
nulldata . dptr = NULL ;
nulldata . dsize = 0 ;
2007-09-04 10:18:44 +10:00
dest = ( ctdb_get_pnn ( ctdb ) + 1 ) % num_nodes ;
2007-04-05 13:18:31 +10:00
ctdb_send_message ( ctdb , dest , 0 , nulldata ) ;
}
/*
handler for messages in bench_ring ( )
*/
2007-04-28 00:31:45 +10:00
static void message_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
2007-04-13 20:38:24 +10:00
TDB_DATA data , void * private_data )
2007-04-05 13:18:31 +10:00
{
msg_count + + ;
bench_fetch_1node ( ctdb ) ;
}
/*
benchmark the following :
fetch a record
store a expanded record
send a message to next node to tell it to do the same
*/
static void bench_fetch ( struct ctdb_context * ctdb , struct event_context * ev )
{
2007-09-04 10:18:44 +10:00
int pnn = ctdb_get_pnn ( ctdb ) ;
2007-04-05 13:18:31 +10:00
2007-09-04 10:18:44 +10:00
if ( pnn = = num_nodes - 1 ) {
2007-04-05 13:18:31 +10:00
bench_fetch_1node ( ctdb ) ;
}
start_timer ( ) ;
while ( end_timer ( ) < timelimit ) {
2007-09-04 10:18:44 +10:00
if ( pnn = = 0 & & msg_count % 100 = = 0 ) {
2007-04-05 13:18:31 +10:00
printf ( " Fetch: %.2f msgs/sec \r " , msg_count / end_timer ( ) ) ;
fflush ( stdout ) ;
}
if ( event_loop_once ( ev ) ! = 0 ) {
printf ( " Event loop failed! \n " ) ;
break ;
}
}
printf ( " Fetch: %.2f msgs/sec \n " , msg_count / end_timer ( ) ) ;
}
enum my_functions { FUNC_FETCH = 1 } ;
/*
ctdb call function to fetch a record
*/
static int fetch_func ( struct ctdb_call_info * call )
{
call - > reply_data = & call - > record_data ;
return 0 ;
}
2007-06-02 13:16:11 +10:00
/*
handler for reconfigure message
*/
static void reconfigure_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
TDB_DATA data , void * private_data )
{
int * ready = ( int * ) private_data ;
* ready = 1 ;
}
2007-04-05 13:18:31 +10:00
/*
main program
*/
int main ( int argc , const char * argv [ ] )
{
struct ctdb_context * ctdb ;
struct ctdb_db_context * ctdb_db ;
struct poptOption popt_options [ ] = {
POPT_AUTOHELP
2007-04-16 14:12:50 +10:00
POPT_CTDB_CMDLINE
2007-04-05 13:18:31 +10:00
{ " timelimit " , ' t ' , POPT_ARG_INT , & timelimit , 0 , " timelimit " , " integer " } ,
{ " num-records " , ' r ' , POPT_ARG_INT , & num_records , 0 , " num_records " , " integer " } ,
2007-06-02 13:31:36 +10:00
{ NULL , ' n ' , POPT_ARG_INT , & num_nodes , 0 , " num_nodes " , " integer " } ,
2007-04-05 13:18:31 +10:00
POPT_TABLEEND
} ;
int opt ;
const char * * extra_argv ;
int extra_argc = 0 ;
int ret ;
poptContext pc ;
struct event_context * ev ;
struct ctdb_call call ;
2007-06-02 13:16:11 +10:00
int cluster_ready = 0 ;
2007-04-05 13:18:31 +10:00
pc = poptGetContext ( argv [ 0 ] , argc , argv , popt_options , POPT_CONTEXT_KEEP_FIRST ) ;
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
switch ( opt ) {
default :
fprintf ( stderr , " Invalid option %s: %s \n " ,
poptBadOption ( pc , 0 ) , poptStrerror ( opt ) ) ;
exit ( 1 ) ;
}
}
2007-04-18 11:20:24 +10:00
/* talloc_enable_leak_report_full(); */
2007-04-17 23:03:30 +02:00
2007-04-05 13:18:31 +10:00
/* setup the remaining options for the main program to use */
extra_argv = poptGetArgs ( pc ) ;
if ( extra_argv ) {
extra_argv + + ;
while ( extra_argv [ extra_argc ] ) extra_argc + + ;
}
ev = event_context_init ( NULL ) ;
2007-06-02 13:16:11 +10:00
ctdb = ctdb_cmdline_client ( ev ) ;
2007-04-05 13:18:31 +10:00
2007-06-02 13:16:11 +10:00
ctdb_set_message_handler ( ctdb , CTDB_SRVID_RECONFIGURE , reconfigure_handler ,
& cluster_ready ) ;
2007-04-30 15:31:40 +02:00
2007-04-05 13:18:31 +10:00
/* attach to a specific database */
2008-06-04 10:46:20 +10:00
ctdb_db = ctdb_attach ( ctdb , " test.tdb " , false , 0 ) ;
2007-04-05 13:18:31 +10:00
if ( ! ctdb_db ) {
printf ( " ctdb_attach failed - %s \n " , ctdb_errstr ( ctdb ) ) ;
exit ( 1 ) ;
}
ret = ctdb_set_call ( ctdb_db , fetch_func , FUNC_FETCH ) ;
2007-04-11 14:05:01 +10:00
ctdb_set_message_handler ( ctdb , 0 , message_handler , & msg_count ) ;
2007-04-11 11:01:42 +10:00
2007-06-02 13:16:11 +10:00
printf ( " Waiting for cluster \n " ) ;
2007-06-02 13:31:36 +10:00
while ( 1 ) {
uint32_t recmode = 1 ;
2007-08-23 13:00:10 +10:00
ctdb_ctrl_getrecmode ( ctdb , ctdb , timeval_zero ( ) , CTDB_CURRENT_NODE , & recmode ) ;
2007-06-02 13:31:36 +10:00
if ( recmode = = 0 ) break ;
2007-06-02 13:16:11 +10:00
event_loop_once ( ev ) ;
}
2007-04-05 13:18:31 +10:00
bench_fetch ( ctdb , ev ) ;
ZERO_STRUCT ( call ) ;
call . key . dptr = discard_const ( TESTKEY ) ;
call . key . dsize = strlen ( TESTKEY ) ;
2007-06-02 13:16:11 +10:00
printf ( " Fetching final record \n " ) ;
2007-04-05 13:18:31 +10:00
/* fetch the record */
call . call_id = FUNC_FETCH ;
call . call_data . dptr = NULL ;
call . call_data . dsize = 0 ;
ret = ctdb_call ( ctdb_db , & call ) ;
if ( ret = = - 1 ) {
printf ( " ctdb_call FUNC_FETCH failed - %s \n " , ctdb_errstr ( ctdb ) ) ;
exit ( 1 ) ;
}
printf ( " DATA: \n %s \n " , ( char * ) call . reply_data . dptr ) ;
return 0 ;
}