2007-05-03 11:06:24 +10:00
/*
2007-05-12 15:15:27 +10:00
ctdb recovery code
2007-05-03 11:06:24 +10:00
Copyright ( C ) Andrew Tridgell 2007
Copyright ( C ) Ronnie Sahlberg 2007
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-05-03 11:06:24 +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-05-03 11:06:24 +10:00
*/
2015-10-26 16:50:46 +11:00
# include "replace.h"
2008-01-17 11:33:23 +11:00
# include "system/time.h"
2007-05-03 11:06:24 +10:00
# include "system/network.h"
# include "system/filesys.h"
# include "system/wait.h"
2015-10-26 16:50:46 +11:00
# include <talloc.h>
# include <tevent.h>
# include <tdb.h>
2014-08-15 15:46:33 +10:00
# include "lib/tdb_wrap/tdb_wrap.h"
2015-10-26 16:50:46 +11:00
# include "lib/util/dlinklist.h"
# include "lib/util/debug.h"
2016-02-16 13:41:21 +11:00
# include "lib/util/time.h"
2015-09-23 16:10:59 -07:00
# include "lib/util/util_process.h"
2015-10-26 16:50:46 +11:00
# include "ctdb_private.h"
# include "ctdb_client.h"
2015-10-23 14:11:53 +11:00
# include "common/system.h"
2015-10-23 14:17:34 +11:00
# include "common/common.h"
2015-11-11 15:41:10 +11:00
# include "common/logging.h"
2007-05-12 15:29:06 +10:00
2007-05-03 11:06:24 +10:00
int
ctdb_control_getvnnmap ( struct ctdb_context * ctdb , uint32_t opcode , TDB_DATA indata , TDB_DATA * outdata )
{
2007-05-10 08:13:19 +10:00
struct ctdb_vnn_map_wire * map ;
size_t len ;
2007-05-03 11:06:24 +10:00
2014-09-04 11:21:24 +10:00
CHECK_CONTROL_DATA_SIZE ( 0 ) ;
2007-05-10 08:13:19 +10:00
len = offsetof ( struct ctdb_vnn_map_wire , map ) + sizeof ( uint32_t ) * ctdb - > vnn_map - > size ;
map = talloc_size ( outdata , len ) ;
2008-07-04 17:04:26 +10:00
CTDB_NO_MEMORY ( ctdb , map ) ;
2007-05-10 08:13:19 +10:00
map - > generation = ctdb - > vnn_map - > generation ;
map - > size = ctdb - > vnn_map - > size ;
memcpy ( map - > map , ctdb - > vnn_map - > map , sizeof ( uint32_t ) * map - > size ) ;
outdata - > dsize = len ;
outdata - > dptr = ( uint8_t * ) map ;
2007-05-03 11:06:24 +10:00
return 0 ;
}
2015-09-14 13:49:05 +10:00
int
2007-05-03 11:06:24 +10:00
ctdb_control_setvnnmap ( struct ctdb_context * ctdb , uint32_t opcode , TDB_DATA indata , TDB_DATA * outdata )
{
2007-05-10 08:22:26 +10:00
struct ctdb_vnn_map_wire * map = ( struct ctdb_vnn_map_wire * ) indata . dptr ;
2015-09-14 13:49:05 +10:00
if ( ctdb - > recovery_mode ! = CTDB_RECOVERY_ACTIVE ) {
DEBUG ( DEBUG_ERR , ( " Attempt to set vnnmap when not in recovery \n " ) ) ;
2014-08-21 12:32:02 +10:00
return - 1 ;
2007-05-14 13:48:40 +10:00
}
2007-05-10 08:22:26 +10:00
talloc_free ( ctdb - > vnn_map ) ;
ctdb - > vnn_map = talloc ( ctdb , struct ctdb_vnn_map ) ;
CTDB_NO_MEMORY ( ctdb , ctdb - > vnn_map ) ;
ctdb - > vnn_map - > generation = map - > generation ;
ctdb - > vnn_map - > size = map - > size ;
ctdb - > vnn_map - > map = talloc_array ( ctdb - > vnn_map , uint32_t , map - > size ) ;
CTDB_NO_MEMORY ( ctdb , ctdb - > vnn_map - > map ) ;
2007-05-03 11:06:24 +10:00
2007-05-10 08:22:26 +10:00
memcpy ( ctdb - > vnn_map - > map , map - > map , sizeof ( uint32_t ) * map - > size ) ;
2007-05-03 11:06:24 +10:00
return 0 ;
}
2007-05-03 13:07:34 +10:00
int
ctdb_control_getdbmap ( struct ctdb_context * ctdb , uint32_t opcode , TDB_DATA indata , TDB_DATA * outdata )
{
uint32_t i , len ;
struct ctdb_db_context * ctdb_db ;
2015-10-29 17:46:05 +11:00
struct ctdb_dbid_map_old * dbid_map ;
2007-05-03 13:07:34 +10:00
CHECK_CONTROL_DATA_SIZE ( 0 ) ;
len = 0 ;
for ( ctdb_db = ctdb - > db_list ; ctdb_db ; ctdb_db = ctdb_db - > next ) {
len + + ;
}
2015-10-29 17:46:05 +11:00
outdata - > dsize = offsetof ( struct ctdb_dbid_map_old , dbs ) + sizeof ( dbid_map - > dbs [ 0 ] ) * len ;
2007-05-03 13:07:34 +10:00
outdata - > dptr = ( unsigned char * ) talloc_zero_size ( outdata , outdata - > dsize ) ;
if ( ! outdata - > dptr ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ALERT , ( __location__ " Failed to allocate dbmap array \n " ) ) ;
2007-05-03 13:07:34 +10:00
exit ( 1 ) ;
}
2015-10-29 17:46:05 +11:00
dbid_map = ( struct ctdb_dbid_map_old * ) outdata - > dptr ;
2007-05-03 13:07:34 +10:00
dbid_map - > num = len ;
2007-09-21 12:24:02 +10:00
for ( i = 0 , ctdb_db = ctdb - > db_list ; ctdb_db ; i + + , ctdb_db = ctdb_db - > next ) {
2015-10-29 17:46:05 +11:00
dbid_map - > dbs [ i ] . db_id = ctdb_db - > db_id ;
2011-09-01 10:21:55 +10:00
if ( ctdb_db - > persistent ! = 0 ) {
dbid_map - > dbs [ i ] . flags | = CTDB_DB_FLAGS_PERSISTENT ;
}
2011-09-01 10:28:15 +10:00
if ( ctdb_db - > readonly ! = 0 ) {
dbid_map - > dbs [ i ] . flags | = CTDB_DB_FLAGS_READONLY ;
}
2012-03-20 16:58:35 +11:00
if ( ctdb_db - > sticky ! = 0 ) {
dbid_map - > dbs [ i ] . flags | = CTDB_DB_FLAGS_STICKY ;
}
2007-05-03 13:07:34 +10:00
}
return 0 ;
}
2007-05-03 13:30:38 +10:00
2015-02-20 12:31:37 +11:00
int
ctdb_control_getnodemap ( struct ctdb_context * ctdb , uint32_t opcode , TDB_DATA indata , TDB_DATA * outdata )
{
CHECK_CONTROL_DATA_SIZE ( 0 ) ;
outdata - > dptr = ( unsigned char * ) ctdb_node_list_to_map ( ctdb - > nodes ,
ctdb - > num_nodes ,
outdata ) ;
if ( outdata - > dptr = = NULL ) {
return - 1 ;
}
outdata - > dsize = talloc_get_size ( outdata - > dptr ) ;
2008-10-14 10:40:29 +11:00
return 0 ;
}
2015-02-10 15:43:03 +11:00
/*
reload the nodes file
*/
int
ctdb_control_reload_nodes_file ( struct ctdb_context * ctdb , uint32_t opcode )
2008-02-19 14:44:48 +11:00
{
2008-12-02 13:26:30 +11:00
int i , num_nodes ;
TALLOC_CTX * tmp_ctx ;
2015-02-10 15:43:03 +11:00
struct ctdb_node * * nodes ;
2008-12-02 13:26:30 +11:00
tmp_ctx = talloc_new ( ctdb ) ;
/* steal the old nodes file for a while */
talloc_steal ( tmp_ctx , ctdb - > nodes ) ;
nodes = ctdb - > nodes ;
ctdb - > nodes = NULL ;
num_nodes = ctdb - > num_nodes ;
ctdb - > num_nodes = 0 ;
2008-02-19 14:44:48 +11:00
2008-12-02 13:26:30 +11:00
/* load the new nodes file */
2008-02-19 14:44:48 +11:00
ctdb_load_nodes_file ( ctdb ) ;
2008-05-11 14:28:33 +10:00
2008-10-07 18:12:54 +11:00
for ( i = 0 ; i < ctdb - > num_nodes ; i + + ) {
2008-12-02 13:26:30 +11:00
/* keep any identical pre-existing nodes and connections */
if ( ( i < num_nodes ) & & ctdb_same_address ( & ctdb - > nodes [ i ] - > address , & nodes [ i ] - > address ) ) {
talloc_free ( ctdb - > nodes [ i ] ) ;
ctdb - > nodes [ i ] = talloc_steal ( ctdb - > nodes , nodes [ i ] ) ;
continue ;
}
2009-06-01 14:18:34 +10:00
if ( ctdb - > nodes [ i ] - > flags & NODE_FLAGS_DELETED ) {
continue ;
}
2008-12-02 13:26:30 +11:00
/* any new or different nodes must be added */
2008-10-07 18:12:54 +11:00
if ( ctdb - > methods - > add_node ( ctdb - > nodes [ i ] ) ! = 0 ) {
DEBUG ( DEBUG_CRIT , ( __location__ " methods->add_node failed at %d \n " , i ) ) ;
ctdb_fatal ( ctdb , " failed to add node. shutting down \n " ) ;
}
2008-12-02 13:26:30 +11:00
if ( ctdb - > methods - > connect_node ( ctdb - > nodes [ i ] ) ! = 0 ) {
DEBUG ( DEBUG_CRIT , ( __location__ " methods->add_connect failed at %d \n " , i ) ) ;
ctdb_fatal ( ctdb , " failed to connect to node. shutting down \n " ) ;
}
2008-05-11 14:28:33 +10:00
}
2008-02-19 14:44:48 +11:00
2009-06-01 14:18:34 +10:00
/* tell the recovery daemon to reaload the nodes file too */
ctdb_daemon_send_message ( ctdb , ctdb - > pnn , CTDB_SRVID_RELOAD_NODES , tdb_null ) ;
2008-12-02 13:26:30 +11:00
talloc_free ( tmp_ctx ) ;
2008-02-19 14:44:48 +11:00
2007-05-03 13:30:38 +10:00
return 0 ;
}
2007-05-03 16:18:03 +10:00
2008-01-07 14:07:01 +11:00
/*
a traverse function for pulling all relevent records from pulldb
*/
struct pulldb_data {
2007-05-10 17:43:45 +10:00
struct ctdb_context * ctdb ;
2012-05-21 13:11:38 +10:00
struct ctdb_db_context * ctdb_db ;
2008-07-30 19:59:18 +10:00
struct ctdb_marshall_buffer * pulldata ;
2008-01-07 14:07:01 +11:00
uint32_t len ;
2012-05-25 12:27:59 +10:00
uint32_t allocated_len ;
2008-01-07 14:07:01 +11:00
bool failed ;
2007-05-10 17:43:45 +10:00
} ;
2008-01-07 14:07:01 +11:00
static int traverse_pulldb ( struct tdb_context * tdb , TDB_DATA key , TDB_DATA data , void * p )
2007-05-10 17:43:45 +10:00
{
2008-01-07 14:07:01 +11:00
struct pulldb_data * params = ( struct pulldb_data * ) p ;
2015-10-29 17:30:30 +11:00
struct ctdb_rec_data_old * rec ;
2012-05-21 13:11:38 +10:00
struct ctdb_context * ctdb = params - > ctdb ;
struct ctdb_db_context * ctdb_db = params - > ctdb_db ;
2007-05-10 17:43:45 +10:00
2008-01-07 14:07:01 +11:00
/* add the record to the blob */
rec = ctdb_marshall_record ( params - > pulldata , 0 , key , NULL , data ) ;
if ( rec = = NULL ) {
params - > failed = true ;
return - 1 ;
2007-05-10 17:43:45 +10:00
}
2012-05-25 12:27:59 +10:00
if ( params - > len + rec - > length > = params - > allocated_len ) {
params - > allocated_len = rec - > length + params - > len + ctdb - > tunable . pulldb_preallocation_size ;
params - > pulldata = talloc_realloc_size ( NULL , params - > pulldata , params - > allocated_len ) ;
}
2008-01-07 14:07:01 +11:00
if ( params - > pulldata = = NULL ) {
2010-09-03 11:58:27 +10:00
DEBUG ( DEBUG_CRIT , ( __location__ " Failed to expand pulldb_data to %u \n " , rec - > length + params - > len ) ) ;
ctdb_fatal ( params - > ctdb , " failed to allocate memory for recovery. shutting down \n " ) ;
2008-01-07 14:07:01 +11:00
}
params - > pulldata - > count + + ;
memcpy ( params - > len + ( uint8_t * ) params - > pulldata , rec , rec - > length ) ;
params - > len + = rec - > length ;
2012-05-21 13:11:38 +10:00
if ( ctdb - > tunable . db_record_size_warn ! = 0 & & rec - > length > ctdb - > tunable . db_record_size_warn ) {
DEBUG ( DEBUG_ERR , ( " Data record in %s is big. Record size is %d bytes \n " , ctdb_db - > db_name , ( int ) rec - > length ) ) ;
}
2008-01-07 14:07:01 +11:00
talloc_free ( rec ) ;
2007-05-10 17:43:45 +10:00
return 0 ;
}
/*
2012-11-20 11:20:34 +01:00
pull a bunch of records from a ltdb , filtering by lmaster
2007-05-10 17:43:45 +10:00
*/
int32_t ctdb_control_pull_db ( struct ctdb_context * ctdb , TDB_DATA indata , TDB_DATA * outdata )
2007-05-03 16:18:03 +10:00
{
2015-10-28 19:10:53 +11:00
struct ctdb_pulldb * pull ;
2007-05-03 16:18:03 +10:00
struct ctdb_db_context * ctdb_db ;
2008-01-07 14:07:01 +11:00
struct pulldb_data params ;
2008-07-30 14:24:56 +10:00
struct ctdb_marshall_buffer * reply ;
2007-05-10 17:43:45 +10:00
2015-10-28 19:10:53 +11:00
pull = ( struct ctdb_pulldb * ) indata . dptr ;
2015-09-14 14:53:45 +10:00
2007-05-10 17:43:45 +10:00
ctdb_db = find_ctdb_db ( ctdb , pull - > db_id ) ;
if ( ! ctdb_db ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " Unknown db 0x%08x \n " , pull - > db_id ) ) ;
2007-05-10 17:43:45 +10:00
return - 1 ;
}
2015-09-15 14:01:49 +10:00
if ( ! ctdb_db_frozen ( ctdb_db ) ) {
2015-09-14 14:53:45 +10:00
DEBUG ( DEBUG_ERR ,
( " rejecting ctdb_control_pull_db when not frozen \n " ) ) ;
2009-10-12 12:08:39 +11:00
return - 1 ;
}
2008-07-30 14:24:56 +10:00
reply = talloc_zero ( outdata , struct ctdb_marshall_buffer ) ;
2008-01-07 14:07:01 +11:00
CTDB_NO_MEMORY ( ctdb , reply ) ;
reply - > db_id = pull - > db_id ;
2007-05-12 19:57:12 +10:00
2008-01-07 14:07:01 +11:00
params . ctdb = ctdb ;
2012-05-21 13:11:38 +10:00
params . ctdb_db = ctdb_db ;
2008-01-07 14:07:01 +11:00
params . pulldata = reply ;
2008-07-30 14:24:56 +10:00
params . len = offsetof ( struct ctdb_marshall_buffer , data ) ;
2012-05-25 12:27:59 +10:00
params . allocated_len = params . len ;
2008-01-07 14:07:01 +11:00
params . failed = false ;
2007-05-10 17:43:45 +10:00
2009-12-07 13:28:11 +01:00
if ( ctdb_db - > unhealthy_reason ) {
/* this is just a warning, as the tdb should be empty anyway */
DEBUG ( DEBUG_WARNING , ( " db(%s) unhealty in ctdb_control_pull_db: %s \n " ,
ctdb_db - > db_name , ctdb_db - > unhealthy_reason ) ) ;
}
2015-09-14 14:53:45 +10:00
if ( ctdb_lockdb_mark ( ctdb_db ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to get lock on entire db - failing \n " ) ) ;
2007-05-10 17:43:45 +10:00
return - 1 ;
}
2008-01-07 14:07:01 +11:00
if ( tdb_traverse_read ( ctdb_db - > ltdb - > tdb , traverse_pulldb , & params ) = = - 1 ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to get traverse db '%s' \n " , ctdb_db - > db_name ) ) ;
2015-09-14 14:53:45 +10:00
ctdb_lockdb_unmark ( ctdb_db ) ;
2008-01-07 14:07:01 +11:00
talloc_free ( params . pulldata ) ;
return - 1 ;
2007-05-10 17:43:45 +10:00
}
2015-09-14 14:53:45 +10:00
ctdb_lockdb_unmark ( ctdb_db ) ;
2007-05-10 17:43:45 +10:00
2008-01-07 14:07:01 +11:00
outdata - > dptr = ( uint8_t * ) params . pulldata ;
outdata - > dsize = params . len ;
2007-05-10 17:43:45 +10:00
2012-05-21 13:11:38 +10:00
if ( ctdb - > tunable . db_record_count_warn ! = 0 & & params . pulldata - > count > ctdb - > tunable . db_record_count_warn ) {
DEBUG ( DEBUG_ERR , ( " Database %s is big. Contains %d records \n " , ctdb_db - > db_name , params . pulldata - > count ) ) ;
}
if ( ctdb - > tunable . db_size_warn ! = 0 & & outdata - > dsize > ctdb - > tunable . db_size_warn ) {
DEBUG ( DEBUG_ERR , ( " Database %s is big. Contains %d bytes \n " , ctdb_db - > db_name , ( int ) outdata - > dsize ) ) ;
}
2007-05-10 17:43:45 +10:00
return 0 ;
}
2016-02-19 17:32:09 +11:00
struct db_pull_state {
struct ctdb_context * ctdb ;
struct ctdb_db_context * ctdb_db ;
struct ctdb_marshall_buffer * recs ;
uint32_t pnn ;
uint64_t srvid ;
uint32_t num_records ;
} ;
static int traverse_db_pull ( struct tdb_context * tdb , TDB_DATA key ,
TDB_DATA data , void * private_data )
{
struct db_pull_state * state = ( struct db_pull_state * ) private_data ;
struct ctdb_marshall_buffer * recs ;
recs = ctdb_marshall_add ( state - > ctdb , state - > recs ,
state - > ctdb_db - > db_id , 0 , key , NULL , data ) ;
if ( recs = = NULL ) {
TALLOC_FREE ( state - > recs ) ;
return - 1 ;
}
state - > recs = recs ;
if ( talloc_get_size ( state - > recs ) > =
state - > ctdb - > tunable . rec_buffer_size_limit ) {
TDB_DATA buffer ;
int ret ;
buffer = ctdb_marshall_finish ( state - > recs ) ;
ret = ctdb_daemon_send_message ( state - > ctdb , state - > pnn ,
state - > srvid , buffer ) ;
if ( ret ! = 0 ) {
TALLOC_FREE ( state - > recs ) ;
return - 1 ;
}
state - > num_records + = state - > recs - > count ;
TALLOC_FREE ( state - > recs ) ;
}
return 0 ;
}
int32_t ctdb_control_db_pull ( struct ctdb_context * ctdb ,
struct ctdb_req_control_old * c ,
TDB_DATA indata , TDB_DATA * outdata )
{
struct ctdb_pulldb_ext * pulldb_ext ;
struct ctdb_db_context * ctdb_db ;
struct db_pull_state state ;
int ret ;
pulldb_ext = ( struct ctdb_pulldb_ext * ) indata . dptr ;
ctdb_db = find_ctdb_db ( ctdb , pulldb_ext - > db_id ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Unknown db 0x%08x \n " ,
pulldb_ext - > db_id ) ) ;
return - 1 ;
}
if ( ! ctdb_db_frozen ( ctdb_db ) ) {
DEBUG ( DEBUG_ERR ,
( " rejecting ctdb_control_pull_db when not frozen \n " ) ) ;
return - 1 ;
}
if ( ctdb_db - > unhealthy_reason ) {
/* this is just a warning, as the tdb should be empty anyway */
DEBUG ( DEBUG_WARNING ,
( " db(%s) unhealty in ctdb_control_db_pull: %s \n " ,
ctdb_db - > db_name , ctdb_db - > unhealthy_reason ) ) ;
}
state . ctdb = ctdb ;
state . ctdb_db = ctdb_db ;
state . recs = NULL ;
state . pnn = c - > hdr . srcnode ;
state . srvid = pulldb_ext - > srvid ;
state . num_records = 0 ;
if ( ctdb_lockdb_mark ( ctdb_db ) ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( __location__ " Failed to get lock on entire db - failing \n " ) ) ;
return - 1 ;
}
ret = tdb_traverse_read ( ctdb_db - > ltdb - > tdb , traverse_db_pull , & state ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ERR ,
( __location__ " Failed to get traverse db '%s' \n " ,
ctdb_db - > db_name ) ) ;
ctdb_lockdb_unmark ( ctdb_db ) ;
return - 1 ;
}
/* Last few records */
if ( state . recs ! = NULL ) {
TDB_DATA buffer ;
buffer = ctdb_marshall_finish ( state . recs ) ;
ret = ctdb_daemon_send_message ( state . ctdb , state . pnn ,
state . srvid , buffer ) ;
if ( ret ! = 0 ) {
TALLOC_FREE ( state . recs ) ;
ctdb_lockdb_unmark ( ctdb_db ) ;
return - 1 ;
}
state . num_records + = state . recs - > count ;
TALLOC_FREE ( state . recs ) ;
}
ctdb_lockdb_unmark ( ctdb_db ) ;
outdata - > dptr = talloc_size ( outdata , sizeof ( uint32_t ) ) ;
if ( outdata - > dptr = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Memory allocation error \n " ) ) ;
return - 1 ;
}
memcpy ( outdata - > dptr , ( uint8_t * ) & state . num_records , sizeof ( uint32_t ) ) ;
outdata - > dsize = sizeof ( uint32_t ) ;
return 0 ;
}
2007-05-10 17:43:45 +10:00
/*
push a bunch of records into a ltdb , filtering by rsn
*/
int32_t ctdb_control_push_db ( struct ctdb_context * ctdb , TDB_DATA indata )
{
2008-07-30 14:24:56 +10:00
struct ctdb_marshall_buffer * reply = ( struct ctdb_marshall_buffer * ) indata . dptr ;
2007-05-10 17:43:45 +10:00
struct ctdb_db_context * ctdb_db ;
int i , ret ;
2015-10-29 17:30:30 +11:00
struct ctdb_rec_data_old * rec ;
2007-05-10 17:43:45 +10:00
2008-07-30 14:24:56 +10:00
if ( indata . dsize < offsetof ( struct ctdb_marshall_buffer , data ) ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " invalid data in pulldb reply \n " ) ) ;
2007-05-10 17:43:45 +10:00
return - 1 ;
}
ctdb_db = find_ctdb_db ( ctdb , reply - > db_id ) ;
2007-05-03 16:18:03 +10:00
if ( ! ctdb_db ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " Unknown db 0x%08x \n " , reply - > db_id ) ) ;
2007-05-03 16:18:03 +10:00
return - 1 ;
}
2015-09-15 14:01:49 +10:00
if ( ! ctdb_db_frozen ( ctdb_db ) ) {
2015-09-14 14:53:45 +10:00
DEBUG ( DEBUG_ERR ,
( " rejecting ctdb_control_push_db when not frozen \n " ) ) ;
2009-10-12 12:08:39 +11:00
return - 1 ;
}
2015-09-14 14:53:45 +10:00
if ( ctdb_lockdb_mark ( ctdb_db ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to get lock on entire db - failing \n " ) ) ;
2007-05-10 17:43:45 +10:00
return - 1 ;
}
2007-05-03 16:18:03 +10:00
2015-10-29 17:30:30 +11:00
rec = ( struct ctdb_rec_data_old * ) & reply - > data [ 0 ] ;
2007-05-10 17:43:45 +10:00
2008-02-04 17:44:24 +11:00
DEBUG ( DEBUG_INFO , ( " starting push of %u records for dbid 0x%x \n " ,
2007-06-17 23:31:44 +10:00
reply - > count , reply - > db_id ) ) ;
2007-05-10 17:43:45 +10:00
for ( i = 0 ; i < reply - > count ; i + + ) {
TDB_DATA key , data ;
2008-01-06 12:38:01 +11:00
struct ctdb_ltdb_header * hdr ;
2007-05-10 17:43:45 +10:00
key . dptr = & rec - > data [ 0 ] ;
key . dsize = rec - > keylen ;
data . dptr = & rec - > data [ key . dsize ] ;
data . dsize = rec - > datalen ;
if ( data . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_CRIT , ( __location__ " bad ltdb record \n " ) ) ;
2007-05-12 15:29:06 +10:00
goto failed ;
2007-05-10 17:43:45 +10:00
}
hdr = ( struct ctdb_ltdb_header * ) data . dptr ;
2011-07-20 13:08:21 +10:00
/* strip off any read only record flags. All readonly records
are revoked implicitely by a recovery
*/
2013-04-19 16:24:32 +02:00
hdr - > flags & = ~ CTDB_REC_RO_FLAGS ;
2011-07-20 13:08:21 +10:00
2007-05-10 17:43:45 +10:00
data . dptr + = sizeof ( * hdr ) ;
data . dsize - = sizeof ( * hdr ) ;
2008-01-06 12:38:01 +11:00
ret = ctdb_ltdb_store ( ctdb_db , key , hdr , data ) ;
2007-05-10 17:43:45 +10:00
if ( ret ! = 0 ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_CRIT , ( __location__ " Unable to store record \n " ) ) ;
2007-05-12 15:29:06 +10:00
goto failed ;
2007-05-10 17:43:45 +10:00
}
2008-01-05 09:34:47 +11:00
2015-10-29 17:30:30 +11:00
rec = ( struct ctdb_rec_data_old * ) ( rec - > length + ( uint8_t * ) rec ) ;
2007-05-10 17:43:45 +10:00
}
2008-02-04 17:44:24 +11:00
DEBUG ( DEBUG_DEBUG , ( " finished push of %u records for dbid 0x%x \n " ,
2007-06-17 23:31:44 +10:00
reply - > count , reply - > db_id ) ) ;
2011-07-20 13:20:32 +10:00
if ( ctdb_db - > readonly ) {
DEBUG ( DEBUG_CRIT , ( " Clearing the tracking database for dbid 0x%x \n " ,
ctdb_db - > db_id ) ) ;
if ( tdb_wipe_all ( ctdb_db - > rottdb ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to wipe tracking database for 0x%x. Dropping read-only delegation support \n " , ctdb_db - > db_id ) ) ;
ctdb_db - > readonly = false ;
tdb_close ( ctdb_db - > rottdb ) ;
ctdb_db - > rottdb = NULL ;
2011-08-23 10:41:52 +10:00
ctdb_db - > readonly = false ;
2011-07-20 13:20:32 +10:00
}
2011-07-20 14:25:29 +10:00
while ( ctdb_db - > revokechild_active ! = NULL ) {
talloc_free ( ctdb_db - > revokechild_active ) ;
}
2011-07-20 13:20:32 +10:00
}
2015-09-14 14:53:45 +10:00
ctdb_lockdb_unmark ( ctdb_db ) ;
2007-05-10 17:43:45 +10:00
return 0 ;
2007-05-12 15:29:06 +10:00
failed :
2015-09-14 14:53:45 +10:00
ctdb_lockdb_unmark ( ctdb_db ) ;
2007-05-12 15:29:06 +10:00
return - 1 ;
2007-05-10 17:43:45 +10:00
}
2016-02-19 17:32:09 +11:00
struct db_push_state {
struct ctdb_context * ctdb ;
struct ctdb_db_context * ctdb_db ;
uint64_t srvid ;
uint32_t num_records ;
bool failed ;
} ;
static void db_push_msg_handler ( uint64_t srvid , TDB_DATA indata ,
void * private_data )
{
struct db_push_state * state = talloc_get_type (
private_data , struct db_push_state ) ;
struct ctdb_marshall_buffer * recs ;
struct ctdb_rec_data_old * rec ;
int i , ret ;
if ( state - > failed ) {
return ;
}
recs = ( struct ctdb_marshall_buffer * ) indata . dptr ;
rec = ( struct ctdb_rec_data_old * ) & recs - > data [ 0 ] ;
DEBUG ( DEBUG_INFO , ( " starting push of %u records for dbid 0x%x \n " ,
recs - > count , recs - > db_id ) ) ;
for ( i = 0 ; i < recs - > count ; i + + ) {
TDB_DATA key , data ;
struct ctdb_ltdb_header * hdr ;
key . dptr = & rec - > data [ 0 ] ;
key . dsize = rec - > keylen ;
data . dptr = & rec - > data [ key . dsize ] ;
data . dsize = rec - > datalen ;
if ( data . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
DEBUG ( DEBUG_CRIT , ( __location__ " bad ltdb record \n " ) ) ;
goto failed ;
}
hdr = ( struct ctdb_ltdb_header * ) data . dptr ;
/* Strip off any read only record flags.
* All readonly records are revoked implicitely by a recovery .
*/
hdr - > flags & = ~ CTDB_REC_RO_FLAGS ;
data . dptr + = sizeof ( * hdr ) ;
data . dsize - = sizeof ( * hdr ) ;
ret = ctdb_ltdb_store ( state - > ctdb_db , key , hdr , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( __location__ " Unable to store record \n " ) ) ;
goto failed ;
}
rec = ( struct ctdb_rec_data_old * ) ( rec - > length + ( uint8_t * ) rec ) ;
}
DEBUG ( DEBUG_DEBUG , ( " finished push of %u records for dbid 0x%x \n " ,
recs - > count , recs - > db_id ) ) ;
state - > num_records + = recs - > count ;
return ;
failed :
state - > failed = true ;
}
int32_t ctdb_control_db_push_start ( struct ctdb_context * ctdb , TDB_DATA indata )
{
struct ctdb_pulldb_ext * pulldb_ext ;
struct ctdb_db_context * ctdb_db ;
struct db_push_state * state ;
int ret ;
pulldb_ext = ( struct ctdb_pulldb_ext * ) indata . dptr ;
ctdb_db = find_ctdb_db ( ctdb , pulldb_ext - > db_id ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR ,
( __location__ " Unknown db 0x%08x \n " , pulldb_ext - > db_id ) ) ;
return - 1 ;
}
if ( ! ctdb_db_frozen ( ctdb_db ) ) {
DEBUG ( DEBUG_ERR ,
( " rejecting ctdb_control_db_push_start when not frozen \n " ) ) ;
return - 1 ;
}
if ( ctdb_db - > push_started ) {
DEBUG ( DEBUG_WARNING ,
( __location__ " DB push already started for %s \n " ,
ctdb_db - > db_name ) ) ;
/* De-register old state */
state = ( struct db_push_state * ) ctdb_db - > push_state ;
if ( state ! = NULL ) {
srvid_deregister ( ctdb - > srv , state - > srvid , state ) ;
talloc_free ( state ) ;
ctdb_db - > push_state = NULL ;
}
}
state = talloc_zero ( ctdb_db , struct db_push_state ) ;
if ( state = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Memory allocation error \n " ) ) ;
return - 1 ;
}
state - > ctdb = ctdb ;
state - > ctdb_db = ctdb_db ;
state - > srvid = pulldb_ext - > srvid ;
state - > failed = false ;
ret = srvid_register ( ctdb - > srv , state , state - > srvid ,
db_push_msg_handler , state ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( __location__ " Failed to register srvid for db push \n " ) ) ;
talloc_free ( state ) ;
return - 1 ;
}
if ( ctdb_lockdb_mark ( ctdb_db ) ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( __location__ " Failed to get lock on entire db - failing \n " ) ) ;
srvid_deregister ( ctdb - > srv , state - > srvid , state ) ;
talloc_free ( state ) ;
return - 1 ;
}
ctdb_db - > push_started = true ;
ctdb_db - > push_state = state ;
return 0 ;
}
int32_t ctdb_control_db_push_confirm ( struct ctdb_context * ctdb ,
TDB_DATA indata , TDB_DATA * outdata )
{
uint32_t db_id ;
struct ctdb_db_context * ctdb_db ;
struct db_push_state * state ;
db_id = * ( uint32_t * ) indata . dptr ;
ctdb_db = find_ctdb_db ( ctdb , db_id ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Unknown db 0x%08x \n " , db_id ) ) ;
return - 1 ;
}
if ( ! ctdb_db_frozen ( ctdb_db ) ) {
DEBUG ( DEBUG_ERR ,
( " rejecting ctdb_control_db_push_confirm when not frozen \n " ) ) ;
return - 1 ;
}
if ( ! ctdb_db - > push_started ) {
DEBUG ( DEBUG_ERR , ( __location__ " DB push not started \n " ) ) ;
return - 1 ;
}
if ( ctdb_db - > readonly ) {
DEBUG ( DEBUG_ERR ,
( " Clearing the tracking database for dbid 0x%x \n " ,
ctdb_db - > db_id ) ) ;
if ( tdb_wipe_all ( ctdb_db - > rottdb ) ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( " Failed to wipe tracking database for 0x%x. "
" Dropping read-only delegation support \n " ,
ctdb_db - > db_id ) ) ;
ctdb_db - > readonly = false ;
tdb_close ( ctdb_db - > rottdb ) ;
ctdb_db - > rottdb = NULL ;
ctdb_db - > readonly = false ;
}
while ( ctdb_db - > revokechild_active ! = NULL ) {
talloc_free ( ctdb_db - > revokechild_active ) ;
}
}
ctdb_lockdb_unmark ( ctdb_db ) ;
state = ( struct db_push_state * ) ctdb_db - > push_state ;
if ( state = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Missing push db state \n " ) ) ;
return - 1 ;
}
srvid_deregister ( ctdb - > srv , state - > srvid , state ) ;
outdata - > dptr = talloc_size ( outdata , sizeof ( uint32_t ) ) ;
if ( outdata - > dptr = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Memory allocation error \n " ) ) ;
talloc_free ( state ) ;
ctdb_db - > push_state = NULL ;
return - 1 ;
}
memcpy ( outdata - > dptr , ( uint8_t * ) & state - > num_records , sizeof ( uint32_t ) ) ;
outdata - > dsize = sizeof ( uint32_t ) ;
talloc_free ( state ) ;
ctdb_db - > push_state = NULL ;
return 0 ;
}
2007-06-02 08:41:19 +10:00
struct ctdb_set_recmode_state {
2007-10-16 15:27:07 +10:00
struct ctdb_context * ctdb ;
2015-10-29 16:42:05 +11:00
struct ctdb_req_control_old * c ;
2007-10-16 15:27:07 +10:00
int fd [ 2 ] ;
2015-10-26 16:50:09 +11:00
struct tevent_timer * te ;
struct tevent_fd * fde ;
2007-10-16 15:27:07 +10:00
pid_t child ;
2009-05-14 10:33:25 +10:00
struct timeval start_time ;
2007-06-02 08:41:19 +10:00
} ;
2007-10-16 15:27:07 +10:00
/*
called if our set_recmode child times out . this would happen if
ctdb_recovery_lock ( ) would block .
*/
2015-10-26 16:50:09 +11:00
static void ctdb_set_recmode_timeout ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2007-10-16 15:27:07 +10:00
{
struct ctdb_set_recmode_state * state = talloc_get_type ( private_data ,
struct ctdb_set_recmode_state ) ;
2008-11-21 08:05:59 +11:00
/* we consider this a success, not a failure, as we failed to
set the recovery lock which is what we wanted . This can be
caused by the cluster filesystem being very slow to
arbitrate locks immediately after a node failure .
*/
2009-05-01 01:18:27 +10:00
DEBUG ( DEBUG_ERR , ( __location__ " set_recmode child process hung/timedout CFS slow to grant locks? (allowing recmode set anyway) \n " ) ) ;
2016-01-11 13:58:54 +11:00
state - > ctdb - > recovery_mode = CTDB_RECOVERY_NORMAL ;
2008-11-21 08:05:59 +11:00
ctdb_request_control_reply ( state - > ctdb , state - > c , NULL , 0 , NULL ) ;
2007-10-16 15:27:07 +10:00
talloc_free ( state ) ;
}
/* when we free the recmode state we must kill any child process.
*/
static int set_recmode_destructor ( struct ctdb_set_recmode_state * state )
{
2009-06-19 14:58:06 +10:00
if ( state - > fd [ 0 ] ! = - 1 ) {
state - > fd [ 0 ] = - 1 ;
}
2012-05-03 11:42:41 +10:00
ctdb_kill ( state - > ctdb , state - > child , SIGKILL ) ;
2007-10-16 15:27:07 +10:00
return 0 ;
}
/* this is called when the client process has completed ctdb_recovery_lock()
and has written data back to us through the pipe .
*/
2015-10-26 16:50:09 +11:00
static void set_recmode_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * private_data )
2007-10-16 15:27:07 +10:00
{
struct ctdb_set_recmode_state * state = talloc_get_type ( private_data ,
struct ctdb_set_recmode_state ) ;
2007-10-18 15:44:02 +10:00
char c = 0 ;
2007-10-16 15:27:07 +10:00
int ret ;
2016-01-28 14:59:18 +11:00
int status = 0 ;
const char * err = NULL ;
2007-10-16 15:27:07 +10:00
/* we got a response from our child process so we can abort the
timeout .
*/
talloc_free ( state - > te ) ;
state - > te = NULL ;
2014-07-30 21:03:53 +10:00
ret = sys_read ( state - > fd [ 0 ] , & c , 1 ) ;
2016-01-28 14:59:18 +11:00
if ( ret = = 1 ) {
2016-01-28 15:07:30 +11:00
/* Child wrote status. EACCES indicates that it was unable
2016-01-28 14:59:18 +11:00
* to take the lock , which is the expected outcome .
2016-01-28 15:07:30 +11:00
* 0 indicates that it was able to take the
2016-01-28 14:59:18 +11:00
* lock , which is an error because the recovery daemon
* should be holding the lock . */
2016-02-01 11:46:05 +11:00
double l = timeval_elapsed ( & state - > start_time ) ;
2016-01-28 15:07:30 +11:00
if ( c = = EACCES ) {
2016-01-28 14:59:18 +11:00
status = 0 ;
err = NULL ;
state - > ctdb - > recovery_mode = CTDB_RECOVERY_NORMAL ;
/* release any deferred attach calls from clients */
ctdb_process_deferred_attach ( state - > ctdb ) ;
2016-02-01 11:46:05 +11:00
CTDB_UPDATE_RECLOCK_LATENCY ( state - > ctdb , " daemon reclock " , reclock . ctdbd , l ) ;
2016-01-28 14:59:18 +11:00
} else {
status = - 1 ;
err = " Took recovery lock from daemon during recovery - probably a cluster filesystem lock coherence problem " ;
}
} else {
/* Child did not write status. Unexpected error.
* Child may have received a signal . */
status = - 1 ;
err = " Unexpected error when testing recovery lock " ;
2007-10-16 15:27:07 +10:00
}
2016-01-28 14:59:18 +11:00
ctdb_request_control_reply ( state - > ctdb , state - > c , NULL , status , err ) ;
2008-01-29 13:59:28 +11:00
talloc_free ( state ) ;
2007-10-16 15:27:07 +10:00
}
2008-10-22 11:04:41 +11:00
static void
2015-10-26 16:50:09 +11:00
ctdb_drop_all_ips_event ( struct tevent_context * ev , struct tevent_timer * te ,
struct timeval t , void * private_data )
2008-10-22 11:04:41 +11:00
{
struct ctdb_context * ctdb = talloc_get_type ( private_data , struct ctdb_context ) ;
2009-04-24 18:09:51 +10:00
DEBUG ( DEBUG_ERR , ( __location__ " Been in recovery mode for too long. Dropping all IPS \n " ) ) ;
2008-10-22 11:04:41 +11:00
talloc_free ( ctdb - > release_ips_ctx ) ;
ctdb - > release_ips_ctx = NULL ;
ctdb_release_all_ips ( ctdb ) ;
}
2010-11-09 15:19:06 +11:00
/*
* Set up an event to drop all public ips if we remain in recovery for too
* long
*/
int ctdb_deferred_drop_all_ips ( struct ctdb_context * ctdb )
{
if ( ctdb - > release_ips_ctx ! = NULL ) {
talloc_free ( ctdb - > release_ips_ctx ) ;
}
ctdb - > release_ips_ctx = talloc_new ( ctdb ) ;
CTDB_NO_MEMORY ( ctdb , ctdb - > release_ips_ctx ) ;
2015-10-26 16:50:09 +11:00
tevent_add_timer ( ctdb - > ev , ctdb - > release_ips_ctx ,
timeval_current_ofs ( ctdb - > tunable . recovery_drop_all_ips , 0 ) ,
ctdb_drop_all_ips_event , ctdb ) ;
2010-11-09 15:19:06 +11:00
return 0 ;
}
2007-05-12 14:34:21 +10:00
/*
set the recovery mode
*/
2007-06-02 08:41:19 +10:00
int32_t ctdb_control_set_recmode ( struct ctdb_context * ctdb ,
2015-10-29 16:42:05 +11:00
struct ctdb_req_control_old * c ,
2007-06-02 08:41:19 +10:00
TDB_DATA indata , bool * async_reply ,
2007-05-12 21:25:26 +10:00
const char * * errormsg )
2007-05-12 14:34:21 +10:00
{
2007-05-12 15:15:27 +10:00
uint32_t recmode = * ( uint32_t * ) indata . dptr ;
2009-10-12 12:08:39 +11:00
int i , ret ;
2007-06-02 11:36:42 +10:00
struct ctdb_set_recmode_state * state ;
2007-10-16 15:27:07 +10:00
pid_t parent = getpid ( ) ;
2015-09-11 16:14:12 +10:00
struct ctdb_db_context * ctdb_db ;
2007-06-02 11:36:42 +10:00
2008-10-22 11:04:41 +11:00
/* if we enter recovery but stay in recovery for too long
we will eventually drop all our ip addresses
*/
if ( recmode = = CTDB_RECOVERY_NORMAL ) {
talloc_free ( ctdb - > release_ips_ctx ) ;
ctdb - > release_ips_ctx = NULL ;
} else {
2010-11-09 15:19:06 +11:00
if ( ctdb_deferred_drop_all_ips ( ctdb ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to set up deferred drop all ips \n " ) ) ;
}
2008-10-22 11:04:41 +11:00
}
2008-01-08 09:30:11 +11:00
if ( recmode ! = ctdb - > recovery_mode ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_NOTICE , ( __location__ " Recovery mode set to %s \n " ,
2008-01-08 09:30:11 +11:00
recmode = = CTDB_RECOVERY_NORMAL ? " NORMAL " : " ACTIVE " ) ) ;
}
2007-06-02 11:36:42 +10:00
if ( recmode ! = CTDB_RECOVERY_NORMAL | |
ctdb - > recovery_mode ! = CTDB_RECOVERY_ACTIVE ) {
ctdb - > recovery_mode = recmode ;
return 0 ;
2007-06-02 08:41:19 +10:00
}
2007-06-02 11:36:42 +10:00
2016-01-11 13:58:54 +11:00
/* From this point: recmode == CTDB_RECOVERY_NORMAL
*
* Therefore , what follows is special handling when setting
* recovery mode back to normal */
2008-06-26 14:14:37 +10:00
2015-09-11 16:14:12 +10:00
for ( ctdb_db = ctdb - > db_list ; ctdb_db ! = NULL ; ctdb_db = ctdb_db - > next ) {
if ( ctdb_db - > generation ! = ctdb - > vnn_map - > generation ) {
DEBUG ( DEBUG_ERR ,
( " Inconsistent DB generation %u for %s \n " ,
ctdb_db - > generation , ctdb_db - > db_name ) ) ;
DEBUG ( DEBUG_ERR , ( " Recovery mode set to ACTIVE \n " ) ) ;
return - 1 ;
}
}
2009-10-12 12:08:39 +11:00
/* force the databases to thaw */
for ( i = 1 ; i < = NUM_DB_PRIORITIES ; i + + ) {
2015-09-15 12:22:17 +10:00
if ( ctdb_db_prio_frozen ( ctdb , i ) ) {
2014-05-06 14:20:44 +10:00
ctdb_control_thaw ( ctdb , i , false ) ;
2009-10-12 12:08:39 +11:00
}
2008-06-26 14:14:37 +10:00
}
2011-02-23 15:46:36 +11:00
/* release any deferred attach calls from clients */
if ( recmode = = CTDB_RECOVERY_NORMAL ) {
ctdb_process_deferred_attach ( ctdb ) ;
}
2014-12-09 13:47:42 +11:00
if ( ctdb - > recovery_lock_file = = NULL ) {
/* Not using recovery lock file */
2009-05-01 01:18:27 +10:00
ctdb - > recovery_mode = recmode ;
return 0 ;
}
2016-01-11 13:41:30 +11:00
state = talloc ( ctdb , struct ctdb_set_recmode_state ) ;
CTDB_NO_MEMORY ( ctdb , state ) ;
state - > start_time = timeval_current ( ) ;
state - > fd [ 0 ] = - 1 ;
state - > fd [ 1 ] = - 1 ;
2007-10-16 15:27:07 +10:00
/* For the rest of what needs to be done, we need to do this in
a child process since
1 , the call to ctdb_recovery_lock ( ) can block if the cluster
filesystem is in the process of recovery .
*/
ret = pipe ( state - > fd ) ;
2007-06-02 11:36:42 +10:00
if ( ret ! = 0 ) {
2007-10-16 15:27:07 +10:00
talloc_free ( state ) ;
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_CRIT , ( __location__ " Failed to open pipe for set_recmode child \n " ) ) ;
2007-06-02 11:36:42 +10:00
return - 1 ;
2007-10-16 15:27:07 +10:00
}
2007-06-02 11:36:42 +10:00
2012-05-03 11:42:41 +10:00
state - > child = ctdb_fork ( ctdb ) ;
2007-10-16 15:27:07 +10:00
if ( state - > child = = ( pid_t ) - 1 ) {
close ( state - > fd [ 0 ] ) ;
close ( state - > fd [ 1 ] ) ;
talloc_free ( state ) ;
return - 1 ;
2007-06-02 11:36:42 +10:00
}
2007-06-06 13:45:12 +10:00
2007-10-16 15:27:07 +10:00
if ( state - > child = = 0 ) {
2016-01-28 15:07:30 +11:00
char cc = EACCES ;
2007-10-16 15:27:07 +10:00
close ( state - > fd [ 0 ] ) ;
2015-09-23 16:10:59 -07:00
prctl_set_comment ( " ctdb_recmode " ) ;
2010-07-19 19:29:09 +09:30
debug_extra = talloc_asprintf ( NULL , " set_recmode: " ) ;
2014-12-17 20:33:19 +11:00
/* Daemon should not be able to get the recover lock,
* as it should be held by the recovery master */
2014-12-09 14:50:38 +11:00
if ( ctdb_recovery_lock ( ctdb ) ) {
2014-12-17 20:33:19 +11:00
DEBUG ( DEBUG_ERR ,
( " ERROR: Daemon able to take recovery lock on \" %s \" during recovery \n " ,
ctdb - > recovery_lock_file ) ) ;
2014-12-09 14:50:38 +11:00
ctdb_recovery_unlock ( ctdb ) ;
2016-01-28 15:07:30 +11:00
cc = 0 ;
2007-10-16 15:27:07 +10:00
}
2014-07-30 21:03:53 +10:00
sys_write ( state - > fd [ 1 ] , & cc , 1 ) ;
2015-12-08 14:20:59 +11:00
ctdb_wait_for_process_to_exit ( parent ) ;
2007-10-16 15:27:07 +10:00
_exit ( 0 ) ;
}
close ( state - > fd [ 1 ] ) ;
2009-10-15 11:24:54 +11:00
set_close_on_exec ( state - > fd [ 0 ] ) ;
2009-06-19 14:58:06 +10:00
state - > fd [ 1 ] = - 1 ;
2007-10-16 15:27:07 +10:00
talloc_set_destructor ( state , set_recmode_destructor ) ;
2010-02-04 06:37:41 +11:00
DEBUG ( DEBUG_DEBUG , ( __location__ " Created PIPE FD:%d for setrecmode \n " , state - > fd [ 0 ] ) ) ;
2009-10-15 11:24:54 +11:00
2015-10-26 16:50:09 +11:00
state - > te = tevent_add_timer ( ctdb - > ev , state , timeval_current_ofs ( 5 , 0 ) ,
ctdb_set_recmode_timeout , state ) ;
2007-10-16 15:27:07 +10:00
2015-10-26 16:50:09 +11:00
state - > fde = tevent_add_fd ( ctdb - > ev , state , state - > fd [ 0 ] , TEVENT_FD_READ ,
set_recmode_handler , ( void * ) state ) ;
2009-06-19 13:09:11 +10:00
2007-10-16 15:27:07 +10:00
if ( state - > fde = = NULL ) {
talloc_free ( state ) ;
return - 1 ;
2007-06-02 11:36:42 +10:00
}
2010-08-18 09:16:31 +09:30
tevent_fd_set_auto_close ( state - > fde ) ;
2007-10-16 15:27:07 +10:00
state - > ctdb = ctdb ;
state - > c = talloc_steal ( state , c ) ;
2007-06-02 11:36:42 +10:00
* async_reply = true ;
2007-05-12 15:15:27 +10:00
return 0 ;
2007-05-12 14:34:21 +10:00
}
2007-05-14 06:25:15 +10:00
2007-06-02 10:03:28 +10:00
2014-12-09 13:50:22 +11:00
bool ctdb_recovery_have_lock ( struct ctdb_context * ctdb )
{
return ctdb - > recovery_lock_fd ! = - 1 ;
}
2007-06-02 10:03:28 +10:00
/*
2007-06-02 11:36:42 +10:00
try and get the recovery lock in shared storage - should only work
on the recovery master recovery daemon . Anywhere else is a bug
2007-06-02 10:03:28 +10:00
*/
2014-12-09 14:50:38 +11:00
bool ctdb_recovery_lock ( struct ctdb_context * ctdb )
2007-06-02 10:03:28 +10:00
{
struct flock lock ;
2014-12-09 14:50:38 +11:00
ctdb - > recovery_lock_fd = open ( ctdb - > recovery_lock_file ,
O_RDWR | O_CREAT , 0600 ) ;
2007-06-02 11:36:42 +10:00
if ( ctdb - > recovery_lock_fd = = - 1 ) {
2014-12-09 14:50:38 +11:00
DEBUG ( DEBUG_ERR ,
( " ctdb_recovery_lock: Unable to open %s - (%s) \n " ,
ctdb - > recovery_lock_file , strerror ( errno ) ) ) ;
2007-06-02 10:03:28 +10:00
return false ;
}
2007-09-19 11:46:37 +10:00
set_close_on_exec ( ctdb - > recovery_lock_fd ) ;
2007-06-02 10:03:28 +10:00
lock . l_type = F_WRLCK ;
lock . l_whence = SEEK_SET ;
lock . l_start = 0 ;
lock . l_len = 1 ;
lock . l_pid = 0 ;
2007-06-02 11:36:42 +10:00
if ( fcntl ( ctdb - > recovery_lock_fd , F_SETLK , & lock ) ! = 0 ) {
2015-01-09 00:10:37 +01:00
int saved_errno = errno ;
2007-09-24 10:19:07 +10:00
close ( ctdb - > recovery_lock_fd ) ;
ctdb - > recovery_lock_fd = - 1 ;
2014-12-09 14:50:38 +11:00
/* Fail silently on these errors, since they indicate
* lock contention , but log an error for any other
* failure . */
if ( saved_errno ! = EACCES & &
saved_errno ! = EAGAIN ) {
DEBUG ( DEBUG_ERR , ( " ctdb_recovery_lock: Failed to get "
" recovery lock on '%s' - (%s) \n " ,
ctdb - > recovery_lock_file ,
strerror ( saved_errno ) ) ) ;
2007-10-18 16:27:36 +10:00
}
2007-06-02 10:03:28 +10:00
return false ;
}
return true ;
}
2008-01-06 12:38:01 +11:00
2014-12-09 14:07:20 +11:00
void ctdb_recovery_unlock ( struct ctdb_context * ctdb )
{
if ( ctdb - > recovery_lock_fd ! = - 1 ) {
DEBUG ( DEBUG_NOTICE , ( " Releasing recovery lock \n " ) ) ;
close ( ctdb - > recovery_lock_fd ) ;
ctdb - > recovery_lock_fd = - 1 ;
}
}
2008-01-08 17:23:27 +11:00
/*
delete a record as part of the vacuum process
only delete if we are not lmaster or dmaster , and our rsn is < = the provided rsn
use non - blocking locks
2008-03-13 07:53:29 +11:00
return 0 if the record was successfully deleted ( i . e . it does not exist
when the function returns )
or ! 0 is the record still exists in the tdb after returning .
2008-01-08 17:23:27 +11:00
*/
2015-10-29 17:30:30 +11:00
static int delete_tdb_record ( struct ctdb_context * ctdb , struct ctdb_db_context * ctdb_db , struct ctdb_rec_data_old * rec )
2008-01-08 17:23:27 +11:00
{
2013-08-12 15:50:30 +10:00
TDB_DATA key , data , data2 ;
2008-01-08 17:23:27 +11:00
struct ctdb_ltdb_header * hdr , * hdr2 ;
2008-01-08 22:31:48 +11:00
/* these are really internal tdb functions - but we need them here for
non - blocking lock of the freelist */
int tdb_lock_nonblock ( struct tdb_context * tdb , int list , int ltype ) ;
int tdb_unlock ( struct tdb_context * tdb , int list , int ltype ) ;
2008-01-08 17:23:27 +11:00
key . dsize = rec - > keylen ;
key . dptr = & rec - > data [ 0 ] ;
data . dsize = rec - > datalen ;
data . dptr = & rec - > data [ rec - > keylen ] ;
if ( ctdb_lmaster ( ctdb , & key ) = = ctdb - > pnn ) {
2008-02-04 17:44:24 +11:00
DEBUG ( DEBUG_INFO , ( __location__ " Called delete on record where we are lmaster \n " ) ) ;
2008-01-08 17:23:27 +11:00
return - 1 ;
}
if ( data . dsize ! = sizeof ( struct ctdb_ltdb_header ) ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " Bad record size \n " ) ) ;
2008-01-08 17:23:27 +11:00
return - 1 ;
}
hdr = ( struct ctdb_ltdb_header * ) data . dptr ;
/* use a non-blocking lock */
if ( tdb_chainlock_nonblock ( ctdb_db - > ltdb - > tdb , key ) ! = 0 ) {
return - 1 ;
}
2013-08-12 15:50:30 +10:00
data2 = tdb_fetch ( ctdb_db - > ltdb - > tdb , key ) ;
if ( data2 . dptr = = NULL ) {
2008-01-08 17:23:27 +11:00
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
return 0 ;
}
2013-08-12 15:50:30 +10:00
if ( data2 . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
2008-01-08 22:31:48 +11:00
if ( tdb_lock_nonblock ( ctdb_db - > ltdb - > tdb , - 1 , F_WRLCK ) = = 0 ) {
2012-11-19 11:20:31 +01:00
if ( tdb_delete ( ctdb_db - > ltdb - > tdb , key ) ! = 0 ) {
DEBUG ( DEBUG_CRIT , ( __location__ " Failed to delete corrupt record \n " ) ) ;
}
2008-01-08 22:31:48 +11:00
tdb_unlock ( ctdb_db - > ltdb - > tdb , - 1 , F_WRLCK ) ;
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_CRIT , ( __location__ " Deleted corrupt record \n " ) ) ;
2008-01-08 22:31:48 +11:00
}
2008-01-08 17:23:27 +11:00
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
2008-01-08 17:23:27 +11:00
return 0 ;
}
2013-08-12 15:50:30 +10:00
hdr2 = ( struct ctdb_ltdb_header * ) data2 . dptr ;
2008-01-08 17:23:27 +11:00
if ( hdr2 - > rsn > hdr - > rsn ) {
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
2008-02-04 17:44:24 +11:00
DEBUG ( DEBUG_INFO , ( __location__ " Skipping record with rsn=%llu - called with rsn=%llu \n " ,
2008-01-08 17:23:27 +11:00
( unsigned long long ) hdr2 - > rsn , ( unsigned long long ) hdr - > rsn ) ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
return - 1 ;
2008-01-08 17:23:27 +11:00
}
2012-02-29 16:09:24 +11:00
/* do not allow deleting record that have readonly flags set. */
2013-04-19 16:24:32 +02:00
if ( hdr - > flags & CTDB_REC_RO_FLAGS ) {
2012-02-29 16:09:24 +11:00
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
DEBUG ( DEBUG_INFO , ( __location__ " Skipping record with readonly flags set \n " ) ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
return - 1 ;
2012-02-29 16:09:24 +11:00
}
2013-04-19 16:24:32 +02:00
if ( hdr2 - > flags & CTDB_REC_RO_FLAGS ) {
2012-02-29 16:09:24 +11:00
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
DEBUG ( DEBUG_INFO , ( __location__ " Skipping record with readonly flags set \n " ) ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
return - 1 ;
2012-02-29 16:09:24 +11:00
}
2008-01-08 17:23:27 +11:00
if ( hdr2 - > dmaster = = ctdb - > pnn ) {
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
2008-02-04 17:44:24 +11:00
DEBUG ( DEBUG_INFO , ( __location__ " Attempted delete record where we are the dmaster \n " ) ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
return - 1 ;
2008-01-08 17:23:27 +11:00
}
2008-01-08 22:31:48 +11:00
if ( tdb_lock_nonblock ( ctdb_db - > ltdb - > tdb , - 1 , F_WRLCK ) ! = 0 ) {
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
return - 1 ;
2008-01-08 22:31:48 +11:00
}
2008-01-08 17:23:27 +11:00
if ( tdb_delete ( ctdb_db - > ltdb - > tdb , key ) ! = 0 ) {
2008-01-08 22:31:48 +11:00
tdb_unlock ( ctdb_db - > ltdb - > tdb , - 1 , F_WRLCK ) ;
2008-01-08 17:23:27 +11:00
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
2008-02-04 17:44:24 +11:00
DEBUG ( DEBUG_INFO , ( __location__ " Failed to delete record \n " ) ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
return - 1 ;
2008-01-08 17:23:27 +11:00
}
2008-01-08 22:31:48 +11:00
tdb_unlock ( ctdb_db - > ltdb - > tdb , - 1 , F_WRLCK ) ;
2008-01-08 17:23:27 +11:00
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
2013-08-12 15:50:30 +10:00
free ( data2 . dptr ) ;
return 0 ;
2008-01-08 17:23:27 +11:00
}
2008-01-29 13:59:28 +11:00
2008-03-13 07:53:29 +11:00
2008-01-29 13:59:28 +11:00
struct recovery_callback_state {
2015-10-29 16:42:05 +11:00
struct ctdb_req_control_old * c ;
2008-01-29 13:59:28 +11:00
} ;
/*
called when the ' recovered ' event script has finished
*/
static void ctdb_end_recovery_callback ( struct ctdb_context * ctdb , int status , void * p )
{
struct recovery_callback_state * state = talloc_get_type ( p , struct recovery_callback_state ) ;
ctdb_enable_monitoring ( ctdb ) ;
2010-09-29 10:38:41 +10:00
CTDB_INCREMENT_STAT ( ctdb , num_recoveries ) ;
2008-01-29 13:59:28 +11:00
if ( status ! = 0 ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " recovered event script failed (status %d) \n " , status ) ) ;
2009-12-07 23:48:57 +10:30
if ( status = = - ETIME ) {
ctdb_ban_self ( ctdb ) ;
}
2008-01-29 13:59:28 +11:00
}
ctdb_request_control_reply ( ctdb , state - > c , NULL , status , NULL ) ;
talloc_free ( state ) ;
2008-07-02 13:55:59 +10:00
gettimeofday ( & ctdb - > last_recovery_finished , NULL ) ;
2013-04-18 20:30:14 +10:00
if ( ctdb - > runstate = = CTDB_RUNSTATE_FIRST_RECOVERY ) {
ctdb_set_runstate ( ctdb , CTDB_RUNSTATE_STARTUP ) ;
}
2008-01-29 13:59:28 +11:00
}
/*
recovery has finished
*/
int32_t ctdb_control_end_recovery ( struct ctdb_context * ctdb ,
2015-10-29 16:42:05 +11:00
struct ctdb_req_control_old * c ,
2008-01-29 13:59:28 +11:00
bool * async_reply )
{
int ret ;
struct recovery_callback_state * state ;
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_NOTICE , ( " Recovery has finished \n " ) ) ;
2008-01-29 13:59:28 +11:00
2011-02-23 17:39:57 +01:00
ctdb_persistent_finish_trans3_commits ( ctdb ) ;
2008-01-29 13:59:28 +11:00
state = talloc ( ctdb , struct recovery_callback_state ) ;
CTDB_NO_MEMORY ( ctdb , state ) ;
2010-02-23 12:43:49 +11:00
state - > c = c ;
2008-01-29 13:59:28 +11:00
ctdb_disable_monitoring ( ctdb ) ;
2009-11-24 11:09:46 +10:30
ret = ctdb_event_script_callback ( ctdb , state ,
2008-01-29 13:59:28 +11:00
ctdb_end_recovery_callback ,
2009-11-26 15:49:49 +11:00
state ,
CTDB_EVENT_RECOVERED , " %s " , " " ) ;
2008-01-29 13:59:28 +11:00
if ( ret ! = 0 ) {
ctdb_enable_monitoring ( ctdb ) ;
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to end recovery \n " ) ) ;
2008-01-29 13:59:28 +11:00
talloc_free ( state ) ;
return - 1 ;
}
/* tell the control that we will be reply asynchronously */
2010-02-23 12:43:49 +11:00
state - > c = talloc_steal ( state , c ) ;
2008-01-29 13:59:28 +11:00
* async_reply = true ;
return 0 ;
}
/*
called when the ' startrecovery ' event script has finished
*/
static void ctdb_start_recovery_callback ( struct ctdb_context * ctdb , int status , void * p )
{
struct recovery_callback_state * state = talloc_get_type ( p , struct recovery_callback_state ) ;
if ( status ! = 0 ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " startrecovery event script failed (status %d) \n " , status ) ) ;
2008-01-29 13:59:28 +11:00
}
ctdb_request_control_reply ( ctdb , state - > c , NULL , status , NULL ) ;
talloc_free ( state ) ;
}
/*
2008-07-02 13:55:59 +10:00
run the startrecovery eventscript
2008-01-29 13:59:28 +11:00
*/
int32_t ctdb_control_start_recovery ( struct ctdb_context * ctdb ,
2015-10-29 16:42:05 +11:00
struct ctdb_req_control_old * c ,
2008-01-29 13:59:28 +11:00
bool * async_reply )
{
int ret ;
struct recovery_callback_state * state ;
2008-07-02 12:01:19 +10:00
DEBUG ( DEBUG_NOTICE , ( __location__ " startrecovery eventscript has been invoked \n " ) ) ;
2008-07-02 13:55:59 +10:00
gettimeofday ( & ctdb - > last_recovery_started , NULL ) ;
2008-01-29 13:59:28 +11:00
state = talloc ( ctdb , struct recovery_callback_state ) ;
CTDB_NO_MEMORY ( ctdb , state ) ;
state - > c = talloc_steal ( state , c ) ;
ctdb_disable_monitoring ( ctdb ) ;
2009-11-24 11:09:46 +10:30
ret = ctdb_event_script_callback ( ctdb , state ,
2008-01-29 13:59:28 +11:00
ctdb_start_recovery_callback ,
2013-12-16 15:57:42 +11:00
state ,
2009-11-26 15:49:49 +11:00
CTDB_EVENT_START_RECOVERY ,
2009-11-24 11:16:49 +10:30
" %s " , " " ) ;
2008-01-29 13:59:28 +11:00
if ( ret ! = 0 ) {
2008-02-04 20:07:15 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to start recovery \n " ) ) ;
2008-01-29 13:59:28 +11:00
talloc_free ( state ) ;
return - 1 ;
}
/* tell the control that we will be reply asynchronously */
* async_reply = true ;
return 0 ;
}
2008-03-13 07:53:29 +11:00
/*
try to delete all these records as part of the vacuuming process
and return the records we failed to delete
*/
int32_t ctdb_control_try_delete_records ( struct ctdb_context * ctdb , TDB_DATA indata , TDB_DATA * outdata )
{
2008-07-30 14:24:56 +10:00
struct ctdb_marshall_buffer * reply = ( struct ctdb_marshall_buffer * ) indata . dptr ;
2008-03-13 07:53:29 +11:00
struct ctdb_db_context * ctdb_db ;
int i ;
2015-10-29 17:30:30 +11:00
struct ctdb_rec_data_old * rec ;
2008-07-30 14:24:56 +10:00
struct ctdb_marshall_buffer * records ;
2008-03-13 07:53:29 +11:00
2008-07-30 14:24:56 +10:00
if ( indata . dsize < offsetof ( struct ctdb_marshall_buffer , data ) ) {
2008-03-13 07:53:29 +11:00
DEBUG ( DEBUG_ERR , ( __location__ " invalid data in try_delete_records \n " ) ) ;
return - 1 ;
}
ctdb_db = find_ctdb_db ( ctdb , reply - > db_id ) ;
if ( ! ctdb_db ) {
DEBUG ( DEBUG_ERR , ( __location__ " Unknown db 0x%08x \n " , reply - > db_id ) ) ;
return - 1 ;
}
DEBUG ( DEBUG_DEBUG , ( " starting try_delete_records of %u records for dbid 0x%x \n " ,
reply - > count , reply - > db_id ) ) ;
/* create a blob to send back the records we couldnt delete */
2008-07-30 14:24:56 +10:00
records = ( struct ctdb_marshall_buffer * )
2008-03-13 07:53:29 +11:00
talloc_zero_size ( outdata ,
2008-07-30 14:24:56 +10:00
offsetof ( struct ctdb_marshall_buffer , data ) ) ;
2008-03-13 07:53:29 +11:00
if ( records = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Out of memory \n " ) ) ;
return - 1 ;
}
records - > db_id = ctdb_db - > db_id ;
2015-10-29 17:30:30 +11:00
rec = ( struct ctdb_rec_data_old * ) & reply - > data [ 0 ] ;
2008-03-13 07:53:29 +11:00
for ( i = 0 ; i < reply - > count ; i + + ) {
TDB_DATA key , data ;
key . dptr = & rec - > data [ 0 ] ;
key . dsize = rec - > keylen ;
data . dptr = & rec - > data [ key . dsize ] ;
data . dsize = rec - > datalen ;
if ( data . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
DEBUG ( DEBUG_CRIT , ( __location__ " bad ltdb record in indata \n " ) ) ;
return - 1 ;
}
/* If we cant delete the record we must add it to the reply
so the lmaster knows it may not purge this record
*/
if ( delete_tdb_record ( ctdb , ctdb_db , rec ) ! = 0 ) {
size_t old_size ;
struct ctdb_ltdb_header * hdr ;
hdr = ( struct ctdb_ltdb_header * ) data . dptr ;
data . dptr + = sizeof ( * hdr ) ;
data . dsize - = sizeof ( * hdr ) ;
DEBUG ( DEBUG_INFO , ( __location__ " Failed to vacuum delete record with hash 0x%08x \n " , ctdb_hash ( & key ) ) ) ;
old_size = talloc_get_size ( records ) ;
records = talloc_realloc_size ( outdata , records , old_size + rec - > length ) ;
if ( records = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to expand \n " ) ) ;
return - 1 ;
}
records - > count + + ;
memcpy ( old_size + ( uint8_t * ) records , rec , rec - > length ) ;
}
2015-10-29 17:30:30 +11:00
rec = ( struct ctdb_rec_data_old * ) ( rec - > length + ( uint8_t * ) rec ) ;
2008-03-13 07:53:29 +11:00
}
2014-05-06 18:52:54 +10:00
* outdata = ctdb_marshall_finish ( records ) ;
2008-03-13 07:53:29 +11:00
return 0 ;
}
2008-05-06 15:42:59 +10:00
2012-12-21 00:24:47 +01:00
/**
* Store a record as part of the vacuum process :
* This is called from the RECEIVE_RECORD control which
* the lmaster uses to send the current empty copy
* to all nodes for storing , before it lets the other
* nodes delete the records in the second phase with
* the TRY_DELETE_RECORDS control .
*
* Only store if we are not lmaster or dmaster , and our
* rsn is < = the provided rsn . Use non - blocking locks .
*
* return 0 if the record was successfully stored .
* return ! 0 if the record still exists in the tdb after returning .
*/
static int store_tdb_record ( struct ctdb_context * ctdb ,
struct ctdb_db_context * ctdb_db ,
2015-10-29 17:30:30 +11:00
struct ctdb_rec_data_old * rec )
2012-12-21 00:24:47 +01:00
{
TDB_DATA key , data , data2 ;
struct ctdb_ltdb_header * hdr , * hdr2 ;
int ret ;
key . dsize = rec - > keylen ;
key . dptr = & rec - > data [ 0 ] ;
data . dsize = rec - > datalen ;
data . dptr = & rec - > data [ rec - > keylen ] ;
if ( ctdb_lmaster ( ctdb , & key ) = = ctdb - > pnn ) {
DEBUG ( DEBUG_INFO , ( __location__ " Called store_tdb_record "
" where we are lmaster \n " ) ) ;
return - 1 ;
}
if ( data . dsize ! = sizeof ( struct ctdb_ltdb_header ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Bad record size \n " ) ) ;
return - 1 ;
}
hdr = ( struct ctdb_ltdb_header * ) data . dptr ;
/* use a non-blocking lock */
if ( tdb_chainlock_nonblock ( ctdb_db - > ltdb - > tdb , key ) ! = 0 ) {
2013-05-24 18:07:39 +10:00
DEBUG ( DEBUG_INFO , ( __location__ " Failed to lock chain in non-blocking mode \n " ) ) ;
2012-12-21 00:24:47 +01:00
return - 1 ;
}
data2 = tdb_fetch ( ctdb_db - > ltdb - > tdb , key ) ;
if ( data2 . dptr = = NULL | | data2 . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
2013-11-11 12:39:27 +11:00
if ( tdb_store ( ctdb_db - > ltdb - > tdb , key , data , 0 ) = = - 1 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to store record \n " ) ) ;
ret = - 1 ;
goto done ;
}
2012-12-21 00:24:47 +01:00
DEBUG ( DEBUG_INFO , ( __location__ " Stored record \n " ) ) ;
ret = 0 ;
goto done ;
}
2013-08-12 15:51:00 +10:00
hdr2 = ( struct ctdb_ltdb_header * ) data2 . dptr ;
2012-12-21 00:24:47 +01:00
if ( hdr2 - > rsn > hdr - > rsn ) {
DEBUG ( DEBUG_INFO , ( __location__ " Skipping record with "
" rsn=%llu - called with rsn=%llu \n " ,
( unsigned long long ) hdr2 - > rsn ,
( unsigned long long ) hdr - > rsn ) ) ;
ret = - 1 ;
goto done ;
}
/* do not allow vacuuming of records that have readonly flags set. */
2013-04-19 16:24:32 +02:00
if ( hdr - > flags & CTDB_REC_RO_FLAGS ) {
2012-12-21 00:24:47 +01:00
DEBUG ( DEBUG_INFO , ( __location__ " Skipping record with readonly "
" flags set \n " ) ) ;
ret = - 1 ;
goto done ;
}
2013-04-19 16:24:32 +02:00
if ( hdr2 - > flags & CTDB_REC_RO_FLAGS ) {
2012-12-21 00:24:47 +01:00
DEBUG ( DEBUG_INFO , ( __location__ " Skipping record with readonly "
" flags set \n " ) ) ;
ret = - 1 ;
goto done ;
}
if ( hdr2 - > dmaster = = ctdb - > pnn ) {
DEBUG ( DEBUG_INFO , ( __location__ " Attempted to store record "
" where we are the dmaster \n " ) ) ;
ret = - 1 ;
goto done ;
}
if ( tdb_store ( ctdb_db - > ltdb - > tdb , key , data , 0 ) ! = 0 ) {
DEBUG ( DEBUG_INFO , ( __location__ " Failed to store record \n " ) ) ;
ret = - 1 ;
goto done ;
}
ret = 0 ;
done :
tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
free ( data2 . dptr ) ;
return ret ;
}
/**
* Try to store all these records as part of the vacuuming process
* and return the records we failed to store .
*/
int32_t ctdb_control_receive_records ( struct ctdb_context * ctdb ,
TDB_DATA indata , TDB_DATA * outdata )
{
struct ctdb_marshall_buffer * reply = ( struct ctdb_marshall_buffer * ) indata . dptr ;
struct ctdb_db_context * ctdb_db ;
int i ;
2015-10-29 17:30:30 +11:00
struct ctdb_rec_data_old * rec ;
2012-12-21 00:24:47 +01:00
struct ctdb_marshall_buffer * records ;
if ( indata . dsize < offsetof ( struct ctdb_marshall_buffer , data ) ) {
DEBUG ( DEBUG_ERR ,
( __location__ " invalid data in receive_records \n " ) ) ;
return - 1 ;
}
ctdb_db = find_ctdb_db ( ctdb , reply - > db_id ) ;
if ( ! ctdb_db ) {
DEBUG ( DEBUG_ERR , ( __location__ " Unknown db 0x%08x \n " ,
reply - > db_id ) ) ;
return - 1 ;
}
DEBUG ( DEBUG_DEBUG , ( " starting receive_records of %u records for "
" dbid 0x%x \n " , reply - > count , reply - > db_id ) ) ;
/* create a blob to send back the records we could not store */
records = ( struct ctdb_marshall_buffer * )
talloc_zero_size ( outdata ,
offsetof ( struct ctdb_marshall_buffer , data ) ) ;
if ( records = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Out of memory \n " ) ) ;
return - 1 ;
}
records - > db_id = ctdb_db - > db_id ;
2015-10-29 17:30:30 +11:00
rec = ( struct ctdb_rec_data_old * ) & reply - > data [ 0 ] ;
2012-12-21 00:24:47 +01:00
for ( i = 0 ; i < reply - > count ; i + + ) {
TDB_DATA key , data ;
key . dptr = & rec - > data [ 0 ] ;
key . dsize = rec - > keylen ;
data . dptr = & rec - > data [ key . dsize ] ;
data . dsize = rec - > datalen ;
if ( data . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
DEBUG ( DEBUG_CRIT , ( __location__ " bad ltdb record "
" in indata \n " ) ) ;
return - 1 ;
}
/*
* If we can not store the record we must add it to the reply
* so the lmaster knows it may not purge this record .
*/
if ( store_tdb_record ( ctdb , ctdb_db , rec ) ! = 0 ) {
size_t old_size ;
struct ctdb_ltdb_header * hdr ;
hdr = ( struct ctdb_ltdb_header * ) data . dptr ;
data . dptr + = sizeof ( * hdr ) ;
data . dsize - = sizeof ( * hdr ) ;
DEBUG ( DEBUG_INFO , ( __location__ " Failed to store "
" record with hash 0x%08x in vacuum "
" via RECEIVE_RECORDS \n " ,
ctdb_hash ( & key ) ) ) ;
old_size = talloc_get_size ( records ) ;
records = talloc_realloc_size ( outdata , records ,
old_size + rec - > length ) ;
if ( records = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to "
" expand \n " ) ) ;
return - 1 ;
}
records - > count + + ;
memcpy ( old_size + ( uint8_t * ) records , rec , rec - > length ) ;
}
2015-10-29 17:30:30 +11:00
rec = ( struct ctdb_rec_data_old * ) ( rec - > length + ( uint8_t * ) rec ) ;
2012-12-21 00:24:47 +01:00
}
2014-05-06 18:52:54 +10:00
* outdata = ctdb_marshall_finish ( records ) ;
2012-12-21 00:24:47 +01:00
return 0 ;
}
2008-05-06 15:42:59 +10:00
/*
report capabilities
*/
int32_t ctdb_control_get_capabilities ( struct ctdb_context * ctdb , TDB_DATA * outdata )
{
uint32_t * capabilities = NULL ;
capabilities = talloc ( outdata , uint32_t ) ;
CTDB_NO_MEMORY ( ctdb , capabilities ) ;
* capabilities = ctdb - > capabilities ;
outdata - > dsize = sizeof ( uint32_t ) ;
outdata - > dptr = ( uint8_t * ) capabilities ;
return 0 ;
}
2012-12-04 15:05:44 +11:00
/* The recovery daemon will ping us at regular intervals.
If we havent been pinged for a while we assume the recovery
daemon is inoperable and we restart .
*/
2015-10-26 16:50:09 +11:00
static void ctdb_recd_ping_timeout ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * p )
2008-09-09 13:44:46 +10:00
{
struct ctdb_context * ctdb = talloc_get_type ( p , struct ctdb_context ) ;
2008-09-17 14:17:41 +10:00
uint32_t * count = talloc_get_type ( ctdb - > recd_ping_count , uint32_t ) ;
2008-09-09 13:44:46 +10:00
2009-05-12 18:39:34 +10:00
DEBUG ( DEBUG_ERR , ( " Recovery daemon ping timeout. Count : %u \n " , * count ) ) ;
2008-09-17 14:17:41 +10:00
2008-09-17 14:24:12 +10:00
if ( * count < ctdb - > tunable . recd_ping_failcount ) {
2008-09-17 14:17:41 +10:00
( * count ) + + ;
2015-10-26 16:50:09 +11:00
tevent_add_timer ( ctdb - > ev , ctdb - > recd_ping_count ,
timeval_current_ofs ( ctdb - > tunable . recd_ping_timeout , 0 ) ,
ctdb_recd_ping_timeout , ctdb ) ;
2008-09-17 14:17:41 +10:00
return ;
}
2011-03-04 06:55:24 +11:00
DEBUG ( DEBUG_ERR , ( " Final timeout for recovery daemon ping. Restarting recovery daemon. (This can be caused if the cluster filesystem has hung) \n " ) ) ;
2008-09-09 13:44:46 +10:00
ctdb_stop_recoverd ( ctdb ) ;
2011-03-04 06:55:24 +11:00
ctdb_start_recoverd ( ctdb ) ;
2008-09-09 13:44:46 +10:00
}
int32_t ctdb_control_recd_ping ( struct ctdb_context * ctdb )
{
2008-09-17 14:17:41 +10:00
talloc_free ( ctdb - > recd_ping_count ) ;
2008-09-09 13:44:46 +10:00
2008-09-17 14:17:41 +10:00
ctdb - > recd_ping_count = talloc_zero ( ctdb , uint32_t ) ;
CTDB_NO_MEMORY ( ctdb , ctdb - > recd_ping_count ) ;
2008-09-09 13:44:46 +10:00
if ( ctdb - > tunable . recd_ping_timeout ! = 0 ) {
2015-10-26 16:50:09 +11:00
tevent_add_timer ( ctdb - > ev , ctdb - > recd_ping_count ,
timeval_current_ofs ( ctdb - > tunable . recd_ping_timeout , 0 ) ,
ctdb_recd_ping_timeout , ctdb ) ;
2008-09-09 13:44:46 +10:00
}
return 0 ;
}
2008-10-22 11:04:41 +11:00
int32_t ctdb_control_set_recmaster ( struct ctdb_context * ctdb , uint32_t opcode , TDB_DATA indata )
{
2013-05-14 16:20:32 +10:00
uint32_t new_recmaster ;
2008-10-22 11:04:41 +11:00
CHECK_CONTROL_DATA_SIZE ( sizeof ( uint32_t ) ) ;
2013-05-14 16:20:32 +10:00
new_recmaster = ( ( uint32_t * ) ( & indata . dptr [ 0 ] ) ) [ 0 ] ;
if ( ctdb - > pnn ! = new_recmaster & & ctdb - > recovery_master = = ctdb - > pnn ) {
DEBUG ( DEBUG_NOTICE ,
( " This node (%u) is no longer the recovery master \n " , ctdb - > pnn ) ) ;
}
if ( ctdb - > pnn = = new_recmaster & & ctdb - > recovery_master ! = new_recmaster ) {
DEBUG ( DEBUG_NOTICE ,
( " This node (%u) is now the recovery master \n " , ctdb - > pnn ) ) ;
}
2008-11-21 16:24:12 +11:00
2013-05-14 16:20:32 +10:00
ctdb - > recovery_master = new_recmaster ;
2008-10-22 11:04:41 +11:00
return 0 ;
}
2009-07-09 12:22:46 +10:00
2009-07-17 12:26:16 +10:00
2013-02-21 14:28:13 +11:00
int32_t ctdb_control_stop_node ( struct ctdb_context * ctdb )
2009-07-09 12:22:46 +10:00
{
2013-05-29 12:11:49 +10:00
DEBUG ( DEBUG_NOTICE , ( " Stopping node \n " ) ) ;
2009-07-17 12:26:16 +10:00
ctdb_disable_monitoring ( ctdb ) ;
2009-07-09 12:22:46 +10:00
ctdb - > nodes [ ctdb - > pnn ] - > flags | = NODE_FLAGS_STOPPED ;
return 0 ;
}
int32_t ctdb_control_continue_node ( struct ctdb_context * ctdb )
{
2013-05-29 12:11:49 +10:00
DEBUG ( DEBUG_NOTICE , ( " Continue node \n " ) ) ;
2009-07-09 12:22:46 +10:00
ctdb - > nodes [ ctdb - > pnn ] - > flags & = ~ NODE_FLAGS_STOPPED ;
return 0 ;
}
2011-09-01 11:08:18 +10:00