2007-04-26 16:27:49 +04:00
/*
ctdb control tool
Copyright ( C ) Andrew Tridgell 2007
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
This library 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "includes.h"
# include "lib/events/events.h"
# include "system/filesys.h"
# include "popt.h"
# include "cmdline.h"
2007-05-02 06:43:35 +04:00
# include "../include/ctdb.h"
2007-04-26 16:27:49 +04:00
# include "../include/ctdb_private.h"
/*
show usage message
*/
static void usage ( void )
{
2007-05-02 07:29:03 +04:00
printf (
" Usage: ctdb_control [options] <control> \n "
" \n Controls: \n "
" ping \n "
" process-exists <vnn:pid> see if a process exists \n "
" status <vnn|all> show ctdb status on a node \n "
" statusreset <vnn|all> reset status on a node \n "
" debug <vnn|all> <level> set ctdb debug level on a node \n "
" debuglevel display ctdb debug levels \n "
" getvnnmap <vnn> display ctdb vnnmap \n "
" setvnnmap <vnn> <generation> <numslots> <lmaster>* \n "
" getdbmap <vnn> lists databases on a node \n "
" getnodemap <vnn> lists nodes known to a ctdb daemon \n "
2007-05-02 16:00:48 +04:00
" createdb <vnn> <dbname> create a database \n "
2007-05-05 23:53:15 +04:00
" catdb <dbname> [vnn] lists all keys/data in a db \n "
2007-05-02 07:29:03 +04:00
" cpdb <fromvnn> <tovnn> <dbid> lists all keys in a remote tdb \n "
" setdmaster <vnn> <dbid> <dmaster> sets new dmaster for all records in the database \n "
" cleardb <vnn> <dbid> deletes all records in a db \n "
" getrecmode <vnn> get recovery mode \n "
" setrecmode <vnn> <mode> set recovery mode \n "
2007-05-07 00:51:58 +04:00
" getrecmaster <vnn> get recovery master \n "
" setrecmaster <vnn> <master_vnn> set recovery master \n "
2007-05-05 22:31:22 +04:00
" attach <dbname> attach a database \n "
" getpid <vnn> get the pid of a ctdb daemon \n "
2007-05-12 09:15:27 +04:00
" freeze <vnn|all> freeze a node \n "
" thaw <vnn|all> thaw a node \n "
2007-05-05 22:31:22 +04:00
) ;
2007-04-26 16:27:49 +04:00
exit ( 1 ) ;
}
2007-04-27 17:14:36 +04:00
/*
see if a process exists
*/
2007-04-26 16:27:49 +04:00
static int control_process_exists ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-04-26 16:51:41 +04:00
uint32_t vnn , pid ;
2007-04-26 16:27:49 +04:00
int ret ;
2007-04-26 16:51:41 +04:00
if ( argc < 1 ) {
2007-04-26 16:27:49 +04:00
usage ( ) ;
}
2007-04-26 16:51:41 +04:00
if ( sscanf ( argv [ 0 ] , " %u:%u " , & vnn , & pid ) ! = 2 ) {
printf ( " Badly formed vnn:pid \n " ) ;
return - 1 ;
}
2007-04-26 16:27:49 +04:00
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_process_exists ( ctdb , vnn , pid ) ;
2007-04-26 16:27:49 +04:00
if ( ret = = 0 ) {
2007-04-26 16:51:41 +04:00
printf ( " %u:%u exists \n " , vnn , pid ) ;
2007-04-26 16:27:49 +04:00
} else {
2007-04-26 16:51:41 +04:00
printf ( " %u:%u does not exist \n " , vnn , pid ) ;
2007-04-26 16:27:49 +04:00
}
return ret ;
}
2007-04-26 16:51:41 +04:00
/*
display status structure
*/
static void show_status ( struct ctdb_status * s )
{
2007-05-05 02:11:54 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
int i ;
const char * prefix = NULL ;
size_t preflen = 0 ;
const struct {
const char * name ;
uint32_t offset ;
} fields [ ] = {
# define STATUS_FIELD(n) { #n, offsetof(struct ctdb_status, n) }
2007-05-05 08:09:46 +04:00
STATUS_FIELD ( num_clients ) ,
2007-05-12 09:51:08 +04:00
STATUS_FIELD ( frozen ) ,
STATUS_FIELD ( recovering ) ,
2007-05-05 02:11:54 +04:00
STATUS_FIELD ( client_packets_sent ) ,
STATUS_FIELD ( client_packets_recv ) ,
STATUS_FIELD ( node_packets_sent ) ,
STATUS_FIELD ( node_packets_recv ) ,
STATUS_FIELD ( node . req_call ) ,
STATUS_FIELD ( node . reply_call ) ,
STATUS_FIELD ( node . req_dmaster ) ,
STATUS_FIELD ( node . reply_dmaster ) ,
STATUS_FIELD ( node . reply_error ) ,
STATUS_FIELD ( node . req_message ) ,
STATUS_FIELD ( node . req_finished ) ,
STATUS_FIELD ( node . req_control ) ,
STATUS_FIELD ( node . reply_control ) ,
STATUS_FIELD ( client . req_call ) ,
STATUS_FIELD ( client . req_message ) ,
STATUS_FIELD ( client . req_finished ) ,
STATUS_FIELD ( client . req_connect_wait ) ,
STATUS_FIELD ( client . req_shutdown ) ,
STATUS_FIELD ( client . req_control ) ,
STATUS_FIELD ( controls . status ) ,
STATUS_FIELD ( controls . get_config ) ,
STATUS_FIELD ( controls . ping ) ,
STATUS_FIELD ( controls . attach ) ,
STATUS_FIELD ( controls . set_call ) ,
STATUS_FIELD ( controls . process_exists ) ,
STATUS_FIELD ( controls . traverse_start ) ,
STATUS_FIELD ( controls . traverse_all ) ,
STATUS_FIELD ( controls . traverse_data ) ,
STATUS_FIELD ( controls . update_seqnum ) ,
STATUS_FIELD ( controls . enable_seqnum ) ,
STATUS_FIELD ( controls . set_seqnum_frequency ) ,
STATUS_FIELD ( controls . register_srvid ) ,
STATUS_FIELD ( controls . deregister_srvid ) ,
2007-05-10 08:06:48 +04:00
STATUS_FIELD ( timeouts . call ) ,
STATUS_FIELD ( timeouts . control ) ,
STATUS_FIELD ( timeouts . traverse ) ,
2007-05-05 02:11:54 +04:00
STATUS_FIELD ( total_calls ) ,
STATUS_FIELD ( pending_calls ) ,
STATUS_FIELD ( lockwait_calls ) ,
STATUS_FIELD ( pending_lockwait_calls ) ,
2007-05-05 02:33:35 +04:00
STATUS_FIELD ( memory_used ) ,
2007-05-05 02:11:54 +04:00
STATUS_FIELD ( max_hop_count ) ,
} ;
2007-04-26 16:51:41 +04:00
printf ( " CTDB version %u \n " , CTDB_VERSION ) ;
2007-05-05 02:11:54 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( fields ) ; i + + ) {
if ( strchr ( fields [ i ] . name , ' . ' ) ) {
preflen = strcspn ( fields [ i ] . name , " . " ) + 1 ;
if ( ! prefix | | strncmp ( prefix , fields [ i ] . name , preflen ) ! = 0 ) {
prefix = fields [ i ] . name ;
printf ( " %*.*s \n " , preflen - 1 , preflen - 1 , fields [ i ] . name ) ;
}
} else {
preflen = 0 ;
}
printf ( " %*s%-22s%*s%10u \n " ,
preflen ? 4 : 0 , " " ,
fields [ i ] . name + preflen ,
preflen ? 0 : 4 , " " ,
* ( uint32_t * ) ( fields [ i ] . offset + ( uint8_t * ) s ) ) ;
}
printf ( " %-30s %.6f sec \n " , " max_call_latency " , s - > max_call_latency ) ;
printf ( " %-30s %.6f sec \n " , " max_lockwait_latency " , s - > max_lockwait_latency ) ;
talloc_free ( tmp_ctx ) ;
2007-04-26 16:51:41 +04:00
}
2007-04-28 19:13:30 +04:00
/*
display remote ctdb status combined from all nodes
*/
static int control_status_all ( struct ctdb_context * ctdb )
{
int ret , i ;
struct ctdb_status status ;
2007-04-28 19:42:40 +04:00
uint32_t * nodes ;
uint32_t num_nodes ;
2007-05-04 03:01:01 +04:00
nodes = ctdb_get_connected_nodes ( ctdb , timeval_current_ofs ( 1 , 0 ) , ctdb , & num_nodes ) ;
2007-04-28 19:42:40 +04:00
CTDB_NO_MEMORY ( ctdb , nodes ) ;
2007-04-28 19:13:30 +04:00
ZERO_STRUCT ( status ) ;
2007-04-28 19:42:40 +04:00
for ( i = 0 ; i < num_nodes ; i + + ) {
2007-04-28 19:13:30 +04:00
struct ctdb_status s1 ;
int j ;
uint32_t * v1 = ( uint32_t * ) & s1 ;
uint32_t * v2 = ( uint32_t * ) & status ;
uint32_t num_ints =
2007-04-28 19:46:37 +04:00
offsetof ( struct ctdb_status , __last_counter ) / sizeof ( uint32_t ) ;
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_status ( ctdb , nodes [ i ] , & s1 ) ;
2007-04-28 19:13:30 +04:00
if ( ret ! = 0 ) {
2007-04-28 19:42:40 +04:00
printf ( " Unable to get status from node %u \n " , nodes [ i ] ) ;
2007-04-28 19:13:30 +04:00
return ret ;
}
for ( j = 0 ; j < num_ints ; j + + ) {
v2 [ j ] + = v1 [ j ] ;
}
2007-05-01 07:25:02 +04:00
status . max_hop_count =
MAX ( status . max_hop_count , s1 . max_hop_count ) ;
2007-04-28 19:13:30 +04:00
status . max_call_latency =
MAX ( status . max_call_latency , s1 . max_call_latency ) ;
status . max_lockwait_latency =
MAX ( status . max_lockwait_latency , s1 . max_lockwait_latency ) ;
}
2007-04-28 19:42:40 +04:00
talloc_free ( nodes ) ;
printf ( " Gathered status for %u nodes \n " , num_nodes ) ;
2007-04-28 19:13:30 +04:00
show_status ( & status ) ;
return 0 ;
}
2007-04-27 17:14:36 +04:00
/*
display remote ctdb status
*/
2007-04-26 16:51:41 +04:00
static int control_status ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn ;
int ret ;
struct ctdb_status status ;
if ( argc < 1 ) {
usage ( ) ;
}
2007-04-28 19:13:30 +04:00
if ( strcmp ( argv [ 0 ] , " all " ) = = 0 ) {
return control_status_all ( ctdb ) ;
}
2007-04-26 16:51:41 +04:00
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_status ( ctdb , vnn , & status ) ;
2007-04-26 16:51:41 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to get status from node %u \n " , vnn ) ;
return ret ;
}
show_status ( & status ) ;
return 0 ;
}
2007-04-28 21:13:36 +04:00
/*
reset status on all nodes
*/
static int control_status_reset_all ( struct ctdb_context * ctdb )
{
int ret , i ;
uint32_t * nodes ;
uint32_t num_nodes ;
2007-05-04 03:01:01 +04:00
nodes = ctdb_get_connected_nodes ( ctdb , timeval_current_ofs ( 1 , 0 ) , ctdb , & num_nodes ) ;
2007-04-28 21:13:36 +04:00
CTDB_NO_MEMORY ( ctdb , nodes ) ;
for ( i = 0 ; i < num_nodes ; i + + ) {
ret = ctdb_status_reset ( ctdb , nodes [ i ] ) ;
if ( ret ! = 0 ) {
printf ( " Unable to reset status on node %u \n " , nodes [ i ] ) ;
return ret ;
}
}
talloc_free ( nodes ) ;
return 0 ;
}
/*
reset remote ctdb status
*/
static int control_status_reset ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn ;
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
if ( strcmp ( argv [ 0 ] , " all " ) = = 0 ) {
return control_status_reset_all ( ctdb ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
ret = ctdb_status_reset ( ctdb , vnn ) ;
if ( ret ! = 0 ) {
printf ( " Unable to reset status on node %u \n " , vnn ) ;
return ret ;
}
return 0 ;
}
2007-05-02 04:20:34 +04:00
2007-04-27 17:14:36 +04:00
/*
display remote ctdb vnn map
*/
2007-04-27 14:56:10 +04:00
static int control_getvnnmap ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn ;
int i , ret ;
2007-05-03 05:06:24 +04:00
struct ctdb_vnn_map * vnnmap = NULL ;
2007-04-27 14:56:10 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-05-04 03:45:53 +04:00
ret = ctdb_ctrl_getvnnmap ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , ctdb , & vnnmap ) ;
2007-04-27 14:56:10 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to get vnnmap from node %u \n " , vnn ) ;
return ret ;
}
printf ( " Generation:%d \n " , vnnmap - > generation ) ;
printf ( " Size:%d \n " , vnnmap - > size ) ;
for ( i = 0 ; i < vnnmap - > size ; i + + ) {
printf ( " hash:%d lmaster:%d \n " , i , vnnmap - > map [ i ] ) ;
}
return 0 ;
}
2007-04-26 21:27:07 +04:00
2007-05-05 22:31:22 +04:00
/*
display pid of a ctdb daemon
*/
static int control_getpid ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn , pid ;
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
ret = ctdb_ctrl_getpid ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , & pid ) ;
if ( ret ! = 0 ) {
printf ( " Unable to get daemon pid from node %u \n " , vnn ) ;
return ret ;
}
printf ( " Pid:%d \n " , pid ) ;
return 0 ;
}
2007-04-29 16:51:56 +04:00
/*
display recovery mode of a remote node
*/
static int control_getrecmode ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn , recmode ;
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-05-04 09:21:40 +04:00
ret = ctdb_ctrl_getrecmode ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , & recmode ) ;
2007-04-29 16:51:56 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to get recmode from node %u \n " , vnn ) ;
return ret ;
}
printf ( " Recovery mode:%s (%d) \n " , recmode = = CTDB_RECOVERY_NORMAL ? " NORMAL " : " RECOVERY " , recmode ) ;
return 0 ;
}
/*
set recovery mode of a remote node
*/
static int control_setrecmode ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn , recmode ;
int ret ;
if ( argc < 2 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-05-07 00:51:58 +04:00
recmode = strtoul ( argv [ 1 ] , NULL , 0 ) ;
2007-04-29 16:51:56 +04:00
2007-05-04 09:21:40 +04:00
ret = ctdb_ctrl_setrecmode ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , recmode ) ;
2007-04-29 16:51:56 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to set recmode on node %u \n " , vnn ) ;
return ret ;
}
return 0 ;
}
2007-05-07 00:51:58 +04:00
/*
display recovery master of a remote node
*/
static int control_getrecmaster ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn , recmaster ;
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
ret = ctdb_ctrl_getrecmaster ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , & recmaster ) ;
if ( ret ! = 0 ) {
printf ( " Unable to get recmaster from node %u \n " , vnn ) ;
return ret ;
}
printf ( " Recovery master:%d \n " , recmaster ) ;
return 0 ;
}
/*
set recovery master of a remote node
*/
static int control_setrecmaster ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn , recmaster ;
int ret ;
if ( argc < 2 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
recmaster = strtoul ( argv [ 1 ] , NULL , 0 ) ;
ret = ctdb_ctrl_setrecmaster ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , recmaster ) ;
if ( ret ! = 0 ) {
printf ( " Unable to set recmaster on node %u \n " , vnn ) ;
return ret ;
}
return 0 ;
}
2007-04-28 23:47:13 +04:00
/*
2007-05-04 06:18:39 +04:00
display remote list of keys / data for a db
2007-04-28 23:47:13 +04:00
*/
2007-04-29 18:58:27 +04:00
static int control_catdb ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-04-28 23:47:13 +04:00
{
2007-05-04 07:25:30 +04:00
const char * db_name ;
2007-05-04 06:18:39 +04:00
struct ctdb_db_context * ctdb_db ;
2007-05-05 23:53:15 +04:00
uint32_t vnn ;
2007-05-04 06:18:39 +04:00
int ret ;
2007-04-28 23:47:13 +04:00
2007-05-04 06:18:39 +04:00
if ( argc < 1 ) {
2007-04-28 23:47:13 +04:00
usage ( ) ;
}
2007-05-04 07:25:30 +04:00
db_name = argv [ 0 ] ;
ctdb_db = ctdb_attach ( ctdb , db_name ) ;
2007-05-04 06:18:39 +04:00
if ( ctdb_db = = NULL ) {
2007-05-04 07:25:30 +04:00
DEBUG ( 0 , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
2007-05-04 06:18:39 +04:00
return - 1 ;
2007-04-28 23:47:13 +04:00
}
2007-05-04 06:18:39 +04:00
2007-05-05 23:53:15 +04:00
if ( argc = = 1 ) {
/* traverse and dump the cluster tdb */
ret = ctdb_dump_db ( ctdb_db , stdout ) ;
if ( ret = = - 1 ) {
printf ( " Unable to dump database \n " ) ;
return - 1 ;
}
} else {
struct ctdb_key_list keys ;
int i ;
/* dump only the local tdb of a specific node */
vnn = strtoul ( argv [ 1 ] , NULL , 0 ) ;
ret = ctdb_ctrl_pulldb ( ctdb , vnn , ctdb_db - > db_id , CTDB_LMASTER_ANY , ctdb , & keys ) ;
if ( ret = = - 1 ) {
printf ( " Unable to pull remote database \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < keys . num ; i + + ) {
char * keystr , * datastr ;
keystr = hex_encode ( ctdb , keys . keys [ i ] . dptr , keys . keys [ i ] . dsize ) ;
datastr = hex_encode ( ctdb , keys . data [ i ] . dptr , keys . data [ i ] . dsize ) ;
2007-04-28 23:47:13 +04:00
2007-05-05 23:53:15 +04:00
printf ( " rsn:%llu lmaster:%d dmaster:%d key:%s data:%s \n " , keys . headers [ i ] . rsn , keys . lmasters [ i ] , keys . headers [ i ] . dmaster , keystr , datastr ) ;
ret + + ;
}
}
2007-05-04 07:25:30 +04:00
talloc_free ( ctdb_db ) ;
2007-05-04 06:18:39 +04:00
printf ( " Dumped %d records \n " , ret ) ;
2007-04-28 23:47:13 +04:00
return 0 ;
}
2007-04-29 18:58:27 +04:00
/*
copy a db from one node to another
*/
static int control_cpdb ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t fromvnn , tovnn , dbid ;
int ret ;
TALLOC_CTX * mem_ctx ;
if ( argc < 3 ) {
usage ( ) ;
}
fromvnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
tovnn = strtoul ( argv [ 1 ] , NULL , 0 ) ;
dbid = strtoul ( argv [ 2 ] , NULL , 0 ) ;
mem_ctx = talloc_new ( ctdb ) ;
2007-05-04 09:21:40 +04:00
ret = ctdb_ctrl_copydb ( ctdb , timeval_current_ofs ( 1 , 0 ) , fromvnn , tovnn , dbid , CTDB_LMASTER_ANY , mem_ctx ) ;
2007-04-29 18:58:27 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to copy db from node %u to node %u \n " , fromvnn , tovnn ) ;
return ret ;
}
talloc_free ( mem_ctx ) ;
return 0 ;
}
2007-04-28 14:00:50 +04:00
/*
display a list of the databases on a remote ctdb
*/
static int control_getdbmap ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn ;
int i , ret ;
2007-05-03 07:07:34 +04:00
struct ctdb_dbid_map * dbmap = NULL ;
2007-04-28 14:00:50 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-05-04 09:21:40 +04:00
ret = ctdb_ctrl_getdbmap ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , ctdb , & dbmap ) ;
2007-04-28 14:00:50 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to get dbids from node %u \n " , vnn ) ;
return ret ;
}
2007-05-03 07:07:34 +04:00
printf ( " Number of databases:%d \n " , dbmap - > num ) ;
for ( i = 0 ; i < dbmap - > num ; i + + ) {
2007-04-28 14:00:50 +04:00
const char * path ;
2007-05-05 23:53:15 +04:00
const char * name ;
2007-04-28 14:00:50 +04:00
2007-05-04 09:21:40 +04:00
ctdb_ctrl_getdbpath ( ctdb , timeval_current_ofs ( 1 , 0 ) , CTDB_CURRENT_NODE , dbmap - > dbids [ i ] , ctdb , & path ) ;
2007-05-05 23:53:15 +04:00
ctdb_ctrl_getdbname ( ctdb , timeval_current_ofs ( 1 , 0 ) , CTDB_CURRENT_NODE , dbmap - > dbids [ i ] , ctdb , & name ) ;
printf ( " dbid:0x%08x name:%s path:%s \n " , dbmap - > dbids [ i ] , name , path ) ;
2007-04-28 14:00:50 +04:00
}
2007-05-02 04:20:34 +04:00
2007-04-28 14:00:50 +04:00
return 0 ;
}
2007-04-28 14:40:26 +04:00
/*
display a list nodes known to a remote ctdb
*/
static int control_getnodemap ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn ;
int i , ret ;
2007-05-03 07:30:38 +04:00
struct ctdb_node_map * nodemap = NULL ;
2007-04-28 14:40:26 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-05-04 03:01:01 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , ctdb , & nodemap ) ;
2007-04-28 14:40:26 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to get nodemap from node %u \n " , vnn ) ;
return ret ;
}
printf ( " Number of nodes:%d \n " , nodemap - > num ) ;
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2007-05-02 05:06:58 +04:00
printf ( " vnn:%d %s%s \n " , nodemap - > nodes [ i ] . vnn ,
2007-04-28 17:11:23 +04:00
nodemap - > nodes [ i ] . flags & NODE_FLAGS_CONNECTED ?
2007-05-02 05:06:58 +04:00
" CONNECTED " : " UNAVAILABLE " ,
nodemap - > nodes [ i ] . vnn = = vnn ? " (THIS NODE) " : " " ) ;
2007-04-28 14:40:26 +04:00
}
2007-05-03 07:30:38 +04:00
2007-04-28 14:40:26 +04:00
return 0 ;
}
2007-04-27 17:14:36 +04:00
/*
set remote ctdb vnn map
*/
2007-04-27 16:08:12 +04:00
static int control_setvnnmap ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-05-03 05:06:24 +04:00
uint32_t vnn , num_nodes , generation ;
2007-04-27 16:08:12 +04:00
struct ctdb_vnn_map * vnnmap ;
int i , ret ;
if ( argc < 3 ) {
usage ( ) ;
}
2007-05-03 05:06:24 +04:00
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
generation = strtoul ( argv [ 1 ] , NULL , 0 ) ;
num_nodes = strtoul ( argv [ 2 ] , NULL , 0 ) ;
2007-04-27 16:08:12 +04:00
2007-05-10 04:03:21 +04:00
vnnmap = talloc ( ctdb , struct ctdb_vnn_map ) ;
2007-05-10 07:15:58 +04:00
CTDB_NO_MEMORY ( ctdb , vnnmap ) ;
2007-05-03 05:06:24 +04:00
vnnmap - > generation = generation ;
vnnmap - > size = num_nodes ;
2007-05-10 04:03:21 +04:00
vnnmap - > map = talloc_array ( vnnmap , uint32_t , vnnmap - > size ) ;
2007-05-10 07:15:58 +04:00
CTDB_NO_MEMORY ( ctdb , vnnmap - > map ) ;
2007-05-10 04:03:21 +04:00
2007-04-27 16:08:12 +04:00
for ( i = 0 ; i < vnnmap - > size ; i + + ) {
vnnmap - > map [ i ] = strtoul ( argv [ 3 + i ] , NULL , 0 ) ;
}
2007-05-04 09:21:40 +04:00
ret = ctdb_ctrl_setvnnmap ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , ctdb , vnnmap ) ;
2007-04-27 16:08:12 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to set vnnmap for node %u \n " , vnn ) ;
return ret ;
}
return 0 ;
}
2007-05-02 15:00:02 +04:00
2007-04-29 12:34:11 +04:00
/*
set the dmaster for all records in a database
*/
static int control_setdmaster ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn , dbid , dmaster ;
int ret ;
2007-04-29 12:48:46 +04:00
if ( argc < 3 ) {
2007-04-29 12:34:11 +04:00
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
dbid = strtoul ( argv [ 1 ] , NULL , 0 ) ;
dmaster = strtoul ( argv [ 2 ] , NULL , 0 ) ;
2007-05-04 09:21:40 +04:00
ret = ctdb_ctrl_setdmaster ( ctdb , timeval_current_ofs ( 1 , 0 ) , vnn , ctdb , dbid , dmaster ) ;
2007-04-29 12:34:11 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to set dmaster for node %u db:0x%08x \n " , vnn , dbid ) ;
return ret ;
}
return 0 ;
}
2007-04-29 12:48:46 +04:00
/*
clears a database
*/
static int control_cleardb ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn , dbid ;
int ret ;
if ( argc < 2 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
dbid = strtoul ( argv [ 1 ] , NULL , 0 ) ;
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_cleardb ( ctdb , vnn , ctdb , dbid ) ;
2007-04-29 12:48:46 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to clear db for node %u db:0x%08x \n " , vnn , dbid ) ;
return ret ;
}
return 0 ;
}
2007-05-02 06:43:35 +04:00
/*
create a database
*/
static int control_createdb ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn ;
const char * dbname ;
int ret ;
int32_t res ;
TDB_DATA data ;
2007-05-04 02:30:18 +04:00
struct timeval timeout ;
2007-05-02 06:43:35 +04:00
if ( argc < 2 ) {
usage ( ) ;
}
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
dbname = argv [ 1 ] ;
/* tell ctdb daemon to attach */
data . dptr = discard_const ( dbname ) ;
data . dsize = strlen ( dbname ) + 1 ;
2007-05-04 02:30:18 +04:00
timeout = timeval_current_ofs ( 1 , 0 ) ;
2007-05-02 06:43:35 +04:00
ret = ctdb_control ( ctdb , vnn , 0 , CTDB_CONTROL_DB_ATTACH ,
2007-05-04 02:30:18 +04:00
0 , data , ctdb , & data , & res ,
& timeout ) ;
2007-05-02 06:43:35 +04:00
if ( ret ! = 0 | | res ! = 0 | | data . dsize ! = sizeof ( uint32_t ) ) {
DEBUG ( 0 , ( " Failed to attach to database '%s' \n " , dbname ) ) ;
return - 1 ;
}
return 0 ;
}
2007-04-27 17:14:36 +04:00
/*
ping all node
*/
2007-04-26 21:27:07 +04:00
static int control_ping ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret , i ;
2007-04-28 19:42:40 +04:00
uint32_t * nodes ;
uint32_t num_nodes ;
2007-04-26 21:27:07 +04:00
2007-05-04 03:01:01 +04:00
nodes = ctdb_get_connected_nodes ( ctdb , timeval_current_ofs ( 1 , 0 ) , ctdb , & num_nodes ) ;
2007-04-28 19:42:40 +04:00
CTDB_NO_MEMORY ( ctdb , nodes ) ;
2007-04-26 21:27:07 +04:00
2007-04-28 19:42:40 +04:00
for ( i = 0 ; i < num_nodes ; i + + ) {
2007-04-26 21:27:07 +04:00
struct timeval tv = timeval_current ( ) ;
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_ping ( ctdb , nodes [ i ] ) ;
2007-04-28 17:15:21 +04:00
if ( ret = = - 1 ) {
2007-04-28 19:42:40 +04:00
printf ( " Unable to get ping response from node %u \n " , nodes [ i ] ) ;
2007-04-26 21:27:07 +04:00
} else {
2007-04-28 17:15:21 +04:00
printf ( " response from %u time=%.6f sec (%d clients) \n " ,
2007-04-28 19:42:40 +04:00
nodes [ i ] , timeval_elapsed ( & tv ) , ret ) ;
2007-04-26 21:27:07 +04:00
}
}
2007-04-28 19:42:40 +04:00
talloc_free ( nodes ) ;
2007-04-26 21:27:07 +04:00
return 0 ;
}
2007-04-27 17:14:36 +04:00
/*
display debug level on all node
*/
static int control_debuglevel ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret , i ;
2007-04-28 19:42:40 +04:00
uint32_t * nodes ;
uint32_t num_nodes ;
2007-05-04 03:01:01 +04:00
nodes = ctdb_get_connected_nodes ( ctdb , timeval_current_ofs ( 1 , 0 ) , ctdb , & num_nodes ) ;
2007-04-28 19:42:40 +04:00
CTDB_NO_MEMORY ( ctdb , nodes ) ;
2007-04-27 17:14:36 +04:00
2007-04-28 19:42:40 +04:00
for ( i = 0 ; i < num_nodes ; i + + ) {
2007-04-27 17:14:36 +04:00
uint32_t level ;
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_get_debuglevel ( ctdb , nodes [ i ] , & level ) ;
2007-04-27 17:14:36 +04:00
if ( ret ! = 0 ) {
2007-04-28 19:42:40 +04:00
printf ( " Unable to get debuglevel response from node %u \n " ,
nodes [ i ] ) ;
2007-04-27 17:14:36 +04:00
} else {
2007-04-28 19:42:40 +04:00
printf ( " Node %u is at debug level %u \n " , nodes [ i ] , level ) ;
2007-04-27 17:14:36 +04:00
}
}
2007-04-28 19:42:40 +04:00
talloc_free ( nodes ) ;
2007-04-27 17:14:36 +04:00
return 0 ;
}
/*
set debug level on a node
*/
static int control_debug ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2007-04-28 19:13:30 +04:00
uint32_t vnn , level , i ;
2007-04-28 19:42:40 +04:00
uint32_t * nodes ;
uint32_t num_nodes ;
2007-04-27 17:14:36 +04:00
if ( argc < 2 ) {
usage ( ) ;
}
level = strtoul ( argv [ 1 ] , NULL , 0 ) ;
2007-04-28 19:42:40 +04:00
if ( strcmp ( argv [ 0 ] , " all " ) ! = 0 ) {
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_set_debuglevel ( ctdb , vnn , level ) ;
2007-04-28 19:42:40 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to set debug level on node %u \n " , vnn ) ;
2007-04-28 19:13:30 +04:00
}
2007-04-28 19:42:40 +04:00
2007-04-28 19:13:30 +04:00
return 0 ;
}
2007-05-04 03:01:01 +04:00
nodes = ctdb_get_connected_nodes ( ctdb , timeval_current_ofs ( 1 , 0 ) , ctdb , & num_nodes ) ;
2007-04-28 19:42:40 +04:00
CTDB_NO_MEMORY ( ctdb , nodes ) ;
for ( i = 0 ; i < num_nodes ; i + + ) {
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_set_debuglevel ( ctdb , nodes [ i ] , level ) ;
2007-04-28 19:42:40 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to set debug level on node %u \n " , nodes [ i ] ) ;
break ;
}
2007-04-27 17:14:36 +04:00
}
2007-04-28 19:42:40 +04:00
talloc_free ( nodes ) ;
2007-04-27 17:14:36 +04:00
return 0 ;
}
2007-04-30 17:54:06 +04:00
2007-05-12 09:15:27 +04:00
/*
freeze a node
*/
static int control_freeze ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-05-12 09:44:56 +04:00
int ret = 0 , count = 0 ;
2007-05-12 09:15:27 +04:00
uint32_t vnn , i ;
uint32_t * nodes ;
uint32_t num_nodes ;
if ( argc < 1 ) {
usage ( ) ;
}
if ( strcmp ( argv [ 0 ] , " all " ) ! = 0 ) {
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
ret = ctdb_ctrl_freeze ( ctdb , timeval_current_ofs ( 5 , 0 ) , vnn ) ;
if ( ret ! = 0 ) {
printf ( " Unable to freeze node %u \n " , vnn ) ;
}
return 0 ;
}
nodes = ctdb_get_connected_nodes ( ctdb , timeval_current_ofs ( 1 , 0 ) , ctdb , & num_nodes ) ;
CTDB_NO_MEMORY ( ctdb , nodes ) ;
for ( i = 0 ; i < num_nodes ; i + + ) {
int res = ctdb_ctrl_freeze ( ctdb , timeval_current_ofs ( 5 , 0 ) , nodes [ i ] ) ;
if ( res ! = 0 ) {
printf ( " Warning: Unable to freeze node %u \n " , nodes [ i ] ) ;
2007-05-12 09:44:56 +04:00
} else {
count + + ;
2007-05-12 09:15:27 +04:00
}
ret | = res ;
}
2007-05-12 09:44:56 +04:00
printf ( " Froze %u nodes \n " , count ) ;
2007-05-12 09:15:27 +04:00
talloc_free ( nodes ) ;
return 0 ;
}
/*
thaw a node
*/
static int control_thaw ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-05-12 09:44:56 +04:00
int ret = 0 , count = 0 ;
2007-05-12 09:15:27 +04:00
uint32_t vnn , i ;
uint32_t * nodes ;
uint32_t num_nodes ;
if ( argc < 1 ) {
usage ( ) ;
}
if ( strcmp ( argv [ 0 ] , " all " ) ! = 0 ) {
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
ret = ctdb_ctrl_thaw ( ctdb , timeval_current_ofs ( 5 , 0 ) , vnn ) ;
if ( ret ! = 0 ) {
printf ( " Unable to thaw node %u \n " , vnn ) ;
}
return 0 ;
}
nodes = ctdb_get_connected_nodes ( ctdb , timeval_current_ofs ( 1 , 0 ) , ctdb , & num_nodes ) ;
CTDB_NO_MEMORY ( ctdb , nodes ) ;
for ( i = 0 ; i < num_nodes ; i + + ) {
int res = ctdb_ctrl_thaw ( ctdb , timeval_current_ofs ( 5 , 0 ) , nodes [ i ] ) ;
if ( res ! = 0 ) {
printf ( " Warning: Unable to thaw node %u \n " , nodes [ i ] ) ;
2007-05-12 09:44:56 +04:00
} else {
count + + ;
2007-05-12 09:15:27 +04:00
}
ret | = res ;
}
2007-05-12 09:44:56 +04:00
printf ( " Thawed %u nodes \n " , count ) ;
2007-05-12 09:15:27 +04:00
talloc_free ( nodes ) ;
return 0 ;
}
2007-04-30 17:54:06 +04:00
/*
attach to a database
*/
static int control_attach ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
if ( argc < 1 ) {
usage ( ) ;
}
db_name = argv [ 0 ] ;
ctdb_db = ctdb_attach ( ctdb , db_name ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( 0 , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
return - 1 ;
}
return 0 ;
}
2007-05-05 05:03:10 +04:00
/*
dump memory usage
*/
static int control_dumpmemory ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t vnn ;
if ( argc < 1 ) {
usage ( ) ;
}
if ( strcmp ( argv [ 0 ] , " all " ) = = 0 ) {
2007-05-05 07:17:26 +04:00
vnn = CTDB_BROADCAST_ALL ;
2007-05-05 05:03:10 +04:00
} else {
vnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
}
ctdb_control ( ctdb , vnn , 0 , CTDB_CONTROL_DUMP_MEMORY ,
CTDB_CTRL_FLAG_NOREPLY , tdb_null , NULL , NULL , NULL , NULL ) ;
return 0 ;
}
2007-04-26 16:27:49 +04:00
/*
main program
*/
int main ( int argc , const char * argv [ ] )
{
struct ctdb_context * ctdb ;
struct poptOption popt_options [ ] = {
POPT_AUTOHELP
POPT_CTDB_CMDLINE
POPT_TABLEEND
} ;
int opt ;
const char * * extra_argv ;
int extra_argc = 0 ;
2007-05-02 07:34:55 +04:00
int ret , i ;
2007-04-26 16:27:49 +04:00
poptContext pc ;
struct event_context * ev ;
const char * control ;
2007-05-02 07:34:55 +04:00
static struct {
const char * name ;
int ( * fn ) ( struct ctdb_context * , int , const char * * ) ;
} commands [ ] = {
{ " process-exists " , control_process_exists } ,
{ " status " , control_status } ,
{ " statusreset " , control_status_reset } ,
{ " getvnnmap " , control_getvnnmap } ,
{ " getdbmap " , control_getdbmap } ,
{ " getnodemap " , control_getnodemap } ,
{ " catdb " , control_catdb } ,
{ " cpdb " , control_cpdb } ,
{ " setvnnmap " , control_setvnnmap } ,
{ " setdmaster " , control_setdmaster } ,
2007-05-02 16:00:48 +04:00
{ " createdb " , control_createdb } ,
2007-05-02 07:34:55 +04:00
{ " cleardb " , control_cleardb } ,
{ " getrecmode " , control_getrecmode } ,
{ " setrecmode " , control_setrecmode } ,
2007-05-07 00:51:58 +04:00
{ " getrecmaster " , control_getrecmaster } ,
{ " setrecmaster " , control_setrecmaster } ,
2007-05-02 07:34:55 +04:00
{ " ping " , control_ping } ,
{ " debug " , control_debug } ,
{ " debuglevel " , control_debuglevel } ,
{ " attach " , control_attach } ,
2007-05-05 05:03:10 +04:00
{ " dumpmemory " , control_dumpmemory } ,
2007-05-05 22:31:22 +04:00
{ " getpid " , control_getpid } ,
2007-05-12 09:15:27 +04:00
{ " freeze " , control_freeze } ,
{ " thaw " , control_thaw } ,
2007-05-02 07:34:55 +04:00
} ;
2007-04-26 16:27:49 +04: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 ) ;
}
}
/* 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 + + ;
}
if ( extra_argc < 1 ) {
usage ( ) ;
}
control = extra_argv [ 0 ] ;
ev = event_context_init ( NULL ) ;
/* initialise ctdb */
ctdb = ctdb_cmdline_client ( ev ) ;
if ( ctdb = = NULL ) {
printf ( " Failed to init ctdb \n " ) ;
exit ( 1 ) ;
}
2007-05-02 07:34:55 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( commands ) ; i + + ) {
if ( strcmp ( control , commands [ i ] . name ) = = 0 ) {
ret = commands [ i ] . fn ( ctdb , extra_argc - 1 , extra_argv + 1 ) ;
break ;
}
}
if ( i = = ARRAY_SIZE ( commands ) ) {
2007-04-26 16:27:49 +04:00
printf ( " Unknown control '%s' \n " , control ) ;
exit ( 1 ) ;
}
return ret ;
}