2006-11-28 09:56:10 +03:00
/*
ctdb_call protocol code
Copyright ( C ) Andrew Tridgell 2006
2007-05-31 07:50:53 +04: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 09:29:31 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-05-31 07:50:53 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
2006-11-28 09:56:10 +03:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2007-05-31 07:50:53 +04: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 09:29:31 +04:00
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2006-11-28 09:56:10 +03:00
*/
2006-12-18 08:01:11 +03:00
/*
see http : //wiki.samba.org/index.php/Samba_%26_Clustering for
protocol design and packet details
*/
2015-10-26 08:50:46 +03:00
# include "replace.h"
2006-11-28 09:56:10 +03:00
# include "system/network.h"
# include "system/filesys.h"
2015-10-26 08:50:46 +03:00
# include <talloc.h>
# include <tevent.h>
# include "lib/util/dlinklist.h"
# include "lib/util/debug.h"
# include "lib/util/samba_util.h"
2016-11-29 04:55:06 +03:00
# include "lib/util/sys_rw.h"
2015-09-24 02:10:59 +03:00
# include "lib/util/util_process.h"
2015-10-26 08:50:46 +03:00
# include "ctdb_private.h"
# include "ctdb_client.h"
# include "common/rb_tree.h"
2015-03-17 06:30:18 +03:00
# include "common/reqid.h"
2015-10-23 06:11:53 +03:00
# include "common/system.h"
2015-10-23 06:17:34 +03:00
# include "common/common.h"
2015-11-11 07:41:10 +03:00
# include "common/logging.h"
2017-03-21 08:48:45 +03:00
# include "common/hash_count.h"
2012-03-20 09:58:35 +04:00
struct ctdb_sticky_record {
struct ctdb_context * ctdb ;
struct ctdb_db_context * ctdb_db ;
TDB_CONTEXT * pindown ;
} ;
2006-11-28 09:56:10 +03:00
2007-04-12 09:46:50 +04:00
/*
find the ctdb_db from a db index
*/
struct ctdb_db_context * find_ctdb_db ( struct ctdb_context * ctdb , uint32_t id )
{
struct ctdb_db_context * ctdb_db ;
for ( ctdb_db = ctdb - > db_list ; ctdb_db ; ctdb_db = ctdb_db - > next ) {
if ( ctdb_db - > db_id = = id ) {
break ;
}
}
return ctdb_db ;
}
2007-05-19 07:45:24 +04:00
/*
2019-10-26 03:41:08 +03:00
a variant of input packet that can be used in lock requeue
2007-05-19 07:45:24 +04:00
*/
2007-06-05 11:57:07 +04:00
static void ctdb_call_input_pkt ( void * p , struct ctdb_req_header * hdr )
2007-05-19 07:45:24 +04:00
{
struct ctdb_context * ctdb = talloc_get_type ( p , struct ctdb_context ) ;
ctdb_input_pkt ( ctdb , hdr ) ;
}
2006-12-18 06:05:49 +03:00
/*
send an error reply
*/
2007-01-23 03:38:45 +03:00
static void ctdb_send_error ( struct ctdb_context * ctdb ,
struct ctdb_req_header * hdr , uint32_t status ,
const char * fmt , . . . ) PRINTF_ATTRIBUTE ( 4 , 5 ) ;
2006-12-18 06:05:49 +03:00
static void ctdb_send_error ( struct ctdb_context * ctdb ,
2006-12-18 06:27:20 +03:00
struct ctdb_req_header * hdr , uint32_t status ,
const char * fmt , . . . )
2006-12-18 06:05:49 +03:00
{
2006-12-18 06:27:20 +03:00
va_list ap ;
2015-10-29 08:30:31 +03:00
struct ctdb_reply_error_old * r ;
2006-12-18 06:27:20 +03:00
char * msg ;
2007-01-23 03:38:45 +03:00
int msglen , len ;
2006-12-18 06:27:20 +03:00
2009-06-30 06:10:27 +04:00
if ( ctdb - > methods = = NULL ) {
2010-10-28 06:38:34 +04:00
DEBUG ( DEBUG_INFO , ( __location__ " Failed to send error. Transport is DOWN \n " ) ) ;
2009-06-30 06:13:15 +04:00
return ;
2009-06-30 06:10:27 +04:00
}
2006-12-18 06:27:20 +03:00
va_start ( ap , fmt ) ;
msg = talloc_vasprintf ( ctdb , fmt , ap ) ;
if ( msg = = NULL ) {
2006-12-18 08:26:57 +03:00
ctdb_fatal ( ctdb , " Unable to allocate error in ctdb_send_error \n " ) ;
2006-12-18 06:27:20 +03:00
}
va_end ( ap ) ;
2007-01-23 03:38:45 +03:00
msglen = strlen ( msg ) + 1 ;
2015-10-29 08:30:31 +03:00
len = offsetof ( struct ctdb_reply_error_old , msg ) ;
2007-04-28 12:50:32 +04:00
r = ctdb_transport_allocate ( ctdb , msg , CTDB_REPLY_ERROR , len + msglen ,
2015-10-29 08:30:31 +03:00
struct ctdb_reply_error_old ) ;
2006-12-18 08:26:57 +03:00
CTDB_NO_MEMORY_FATAL ( ctdb , r ) ;
2007-01-23 03:38:45 +03:00
2006-12-18 06:27:20 +03:00
r - > hdr . destnode = hdr - > srcnode ;
r - > hdr . reqid = hdr - > reqid ;
r - > status = status ;
2007-01-23 03:38:45 +03:00
r - > msglen = msglen ;
memcpy ( & r - > msg [ 0 ] , msg , msglen ) ;
2006-12-18 06:27:20 +03:00
2006-12-18 08:26:57 +03:00
ctdb_queue_packet ( ctdb , & r - > hdr ) ;
2006-12-18 06:27:20 +03:00
2007-04-19 04:37:44 +04:00
talloc_free ( msg ) ;
2006-12-18 06:05:49 +03:00
}
2006-12-18 06:44:06 +03:00
2010-11-24 10:01:01 +03:00
/**
* send a redirect reply
*
* The logic behind this function is this :
*
* A client wants to grab a record and sends a CTDB_REQ_CALL packet
* to its local ctdb ( ctdb_request_call ) . If the node is not itself
* the record ' s DMASTER , it first redirects the packet to the
* record ' s LMASTER . The LMASTER then redirects the call packet to
2013-05-17 13:00:32 +04:00
* the current DMASTER . Note that this works because of this : When
2010-11-24 10:01:01 +03:00
* a record is migrated off a node , then the new DMASTER is stored
* in the record ' s copy on the former DMASTER .
*/
2012-03-20 09:58:35 +04:00
static void ctdb_call_send_redirect ( struct ctdb_context * ctdb ,
struct ctdb_db_context * ctdb_db ,
2007-04-28 20:18:33 +04:00
TDB_DATA key ,
2015-10-29 08:26:29 +03:00
struct ctdb_req_call_old * c ,
2006-12-18 06:05:49 +03:00
struct ctdb_ltdb_header * header )
{
2007-04-28 20:18:33 +04:00
uint32_t lmaster = ctdb_lmaster ( ctdb , & key ) ;
2012-03-20 09:58:35 +04:00
c - > hdr . destnode = lmaster ;
2007-09-04 04:06:36 +04:00
if ( ctdb - > pnn = = lmaster ) {
2007-04-28 20:18:33 +04:00
c - > hdr . destnode = header - > dmaster ;
}
2007-05-01 07:25:02 +04:00
c - > hopcount + + ;
2012-03-20 09:58:35 +04:00
2013-07-15 11:34:31 +04:00
if ( c - > hopcount % 100 > 95 ) {
DEBUG ( DEBUG_WARNING , ( " High hopcount %d dbid:%s "
" key:0x%08x reqid=%08x pnn:%d src:%d lmaster:%d "
2012-03-20 09:58:35 +04:00
" header->dmaster:%d dst:%d \n " ,
2013-07-15 11:34:31 +04:00
c - > hopcount , ctdb_db - > db_name , ctdb_hash ( & key ) ,
c - > hdr . reqid , ctdb - > pnn , c - > hdr . srcnode , lmaster ,
2012-03-20 09:58:35 +04:00
header - > dmaster , c - > hdr . destnode ) ) ;
}
2007-04-28 20:18:33 +04:00
ctdb_queue_packet ( ctdb , & c - > hdr ) ;
2006-12-18 06:05:49 +03:00
}
2007-04-22 16:26:45 +04:00
/*
send a dmaster reply
caller must have the chainlock before calling this routine . Caller must be
the lmaster
*/
static void ctdb_send_dmaster_reply ( struct ctdb_db_context * ctdb_db ,
struct ctdb_ltdb_header * header ,
TDB_DATA key , TDB_DATA data ,
uint32_t new_dmaster ,
uint32_t reqid )
{
struct ctdb_context * ctdb = ctdb_db - > ctdb ;
2015-10-29 08:34:01 +03:00
struct ctdb_reply_dmaster_old * r ;
2007-04-22 16:26:45 +04:00
int ret , len ;
TALLOC_CTX * tmp_ctx ;
2007-09-04 04:06:36 +04:00
if ( ctdb - > pnn ! = ctdb_lmaster ( ctdb , & key ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ALERT , ( __location__ " Caller is not lmaster! \n " ) ) ;
2007-04-22 16:26:45 +04:00
return ;
}
header - > dmaster = new_dmaster ;
ret = ctdb_ltdb_store ( ctdb_db , key , header , data ) ;
if ( ret ! = 0 ) {
2009-06-30 06:13:15 +04:00
ctdb_fatal ( ctdb , " ctdb_send_dmaster_reply unable to update dmaster " ) ;
return ;
}
if ( ctdb - > methods = = NULL ) {
2010-01-06 16:59:23 +03:00
ctdb_fatal ( ctdb , " ctdb_send_dmaster_reply cant update dmaster since transport is down " ) ;
2007-04-22 16:26:45 +04:00
return ;
}
/* put the packet on a temporary context, allowing us to safely free
it below even if ctdb_reply_dmaster ( ) has freed it already */
tmp_ctx = talloc_new ( ctdb ) ;
/* send the CTDB_REPLY_DMASTER */
2015-10-29 08:34:01 +03:00
len = offsetof ( struct ctdb_reply_dmaster_old , data ) + key . dsize + data . dsize + sizeof ( uint32_t ) ;
2007-04-28 12:50:32 +04:00
r = ctdb_transport_allocate ( ctdb , tmp_ctx , CTDB_REPLY_DMASTER , len ,
2015-10-29 08:34:01 +03:00
struct ctdb_reply_dmaster_old ) ;
2007-04-22 16:26:45 +04:00
CTDB_NO_MEMORY_FATAL ( ctdb , r ) ;
r - > hdr . destnode = new_dmaster ;
r - > hdr . reqid = reqid ;
2015-09-15 09:50:19 +03:00
r - > hdr . generation = ctdb_db - > generation ;
2007-04-29 18:19:40 +04:00
r - > rsn = header - > rsn ;
r - > keylen = key . dsize ;
2007-04-22 16:26:45 +04:00
r - > datalen = data . dsize ;
2007-04-29 18:19:40 +04:00
r - > db_id = ctdb_db - > db_id ;
memcpy ( & r - > data [ 0 ] , key . dptr , key . dsize ) ;
memcpy ( & r - > data [ key . dsize ] , data . dptr , data . dsize ) ;
2010-12-10 16:02:33 +03:00
memcpy ( & r - > data [ key . dsize + data . dsize ] , & header - > flags , sizeof ( uint32_t ) ) ;
2007-04-22 16:26:45 +04:00
ctdb_queue_packet ( ctdb , & r - > hdr ) ;
talloc_free ( tmp_ctx ) ;
}
2006-12-18 08:01:11 +03:00
/*
send a dmaster request ( give another node the dmaster for a record )
This is always sent to the lmaster , which ensures that the lmaster
always knows who the dmaster is . The lmaster will then send a
CTDB_REPLY_DMASTER to the new dmaster
*/
2007-04-03 13:41:00 +04:00
static void ctdb_call_send_dmaster ( struct ctdb_db_context * ctdb_db ,
2015-10-29 08:26:29 +03:00
struct ctdb_req_call_old * c ,
2006-12-18 08:01:11 +03:00
struct ctdb_ltdb_header * header ,
TDB_DATA * key , TDB_DATA * data )
{
2015-10-29 08:32:09 +03:00
struct ctdb_req_dmaster_old * r ;
2007-04-03 13:41:00 +04:00
struct ctdb_context * ctdb = ctdb_db - > ctdb ;
2006-12-18 08:01:11 +03:00
int len ;
2007-04-22 16:26:45 +04:00
uint32_t lmaster = ctdb_lmaster ( ctdb , key ) ;
2009-06-30 06:14:58 +04:00
if ( ctdb - > methods = = NULL ) {
ctdb_fatal ( ctdb , " Failed ctdb_call_send_dmaster since transport is down " ) ;
return ;
}
2010-12-03 17:21:51 +03:00
if ( data - > dsize ! = 0 ) {
header - > flags | = CTDB_REC_FLAG_MIGRATED_WITH_DATA ;
}
2007-09-04 04:06:36 +04:00
if ( lmaster = = ctdb - > pnn ) {
2007-04-22 16:26:45 +04:00
ctdb_send_dmaster_reply ( ctdb_db , header , * key , * data ,
c - > hdr . srcnode , c - > hdr . reqid ) ;
return ;
}
2006-12-18 08:01:11 +03:00
2015-10-29 08:32:09 +03:00
len = offsetof ( struct ctdb_req_dmaster_old , data ) + key - > dsize + data - > dsize
2010-12-10 16:02:33 +03:00
+ sizeof ( uint32_t ) ;
2007-04-28 12:50:32 +04:00
r = ctdb_transport_allocate ( ctdb , ctdb , CTDB_REQ_DMASTER , len ,
2015-10-29 08:32:09 +03:00
struct ctdb_req_dmaster_old ) ;
2006-12-18 08:26:57 +03:00
CTDB_NO_MEMORY_FATAL ( ctdb , r ) ;
2007-04-22 16:26:45 +04:00
r - > hdr . destnode = lmaster ;
2006-12-18 08:01:11 +03:00
r - > hdr . reqid = c - > hdr . reqid ;
2015-09-15 09:50:19 +03:00
r - > hdr . generation = ctdb_db - > generation ;
2007-04-03 13:41:00 +04:00
r - > db_id = c - > db_id ;
2007-04-29 18:19:40 +04:00
r - > rsn = header - > rsn ;
2007-04-05 07:18:31 +04:00
r - > dmaster = c - > hdr . srcnode ;
2006-12-18 08:01:11 +03:00
r - > keylen = key - > dsize ;
r - > datalen = data - > dsize ;
memcpy ( & r - > data [ 0 ] , key - > dptr , key - > dsize ) ;
memcpy ( & r - > data [ key - > dsize ] , data - > dptr , data - > dsize ) ;
2010-12-10 16:02:33 +03:00
memcpy ( & r - > data [ key - > dsize + data - > dsize ] , & header - > flags , sizeof ( uint32_t ) ) ;
2006-12-18 08:01:11 +03:00
2007-04-22 16:26:45 +04:00
header - > dmaster = c - > hdr . srcnode ;
2010-12-13 06:23:32 +03:00
if ( ctdb_ltdb_store ( ctdb_db , * key , header , * data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to store record in ctdb_call_send_dmaster " ) ;
2007-05-15 04:16:59 +04:00
}
2010-12-13 06:23:32 +03:00
2007-04-20 11:58:37 +04:00
ctdb_queue_packet ( ctdb , & r - > hdr ) ;
2006-12-18 08:01:11 +03:00
talloc_free ( r ) ;
}
2015-10-26 08:50:09 +03:00
static void ctdb_sticky_pindown_timeout ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2012-03-20 09:58:35 +04:00
{
struct ctdb_sticky_record * sr = talloc_get_type ( private_data ,
struct ctdb_sticky_record ) ;
DEBUG ( DEBUG_ERR , ( " Pindown timeout db:%s unstick record \n " , sr - > ctdb_db - > db_name ) ) ;
if ( sr - > pindown ! = NULL ) {
talloc_free ( sr - > pindown ) ;
sr - > pindown = NULL ;
}
}
static int
ctdb_set_sticky_pindown ( struct ctdb_context * ctdb , struct ctdb_db_context * ctdb_db , TDB_DATA key )
{
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
uint32_t * k ;
struct ctdb_sticky_record * sr ;
2014-08-15 07:33:24 +04:00
k = ctdb_key_to_idkey ( tmp_ctx , key ) ;
2012-03-20 09:58:35 +04:00
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for sticky record \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
sr = trbt_lookuparray32 ( ctdb_db - > sticky_records , k [ 0 ] , & k [ 0 ] ) ;
if ( sr = = NULL ) {
talloc_free ( tmp_ctx ) ;
return 0 ;
}
talloc_free ( tmp_ctx ) ;
if ( sr - > pindown = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Pinning down record in %s for %d ms \n " , ctdb_db - > db_name , ctdb - > tunable . sticky_pindown ) ) ;
sr - > pindown = talloc_new ( sr ) ;
if ( sr - > pindown = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate pindown context for sticky record \n " ) ) ;
return - 1 ;
}
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , sr - > pindown ,
timeval_current_ofs ( ctdb - > tunable . sticky_pindown / 1000 ,
( ctdb - > tunable . sticky_pindown * 1000 ) % 1000000 ) ,
ctdb_sticky_pindown_timeout , sr ) ;
2012-03-20 09:58:35 +04:00
}
return 0 ;
}
2007-04-22 20:19:49 +04:00
/*
called when a CTDB_REPLY_DMASTER packet comes in , or when the lmaster
gets a CTDB_REQUEST_DMASTER for itself . We become the dmaster .
must be called with the chainlock held . This function releases the chainlock
*/
2010-12-10 16:02:33 +03:00
static void ctdb_become_dmaster ( struct ctdb_db_context * ctdb_db ,
2007-07-11 03:44:52 +04:00
struct ctdb_req_header * hdr ,
TDB_DATA key , TDB_DATA data ,
2010-12-10 16:02:33 +03:00
uint64_t rsn , uint32_t record_flags )
2007-04-22 20:19:49 +04:00
{
struct ctdb_call_state * state ;
2007-04-29 18:19:40 +04:00
struct ctdb_context * ctdb = ctdb_db - > ctdb ;
struct ctdb_ltdb_header header ;
2010-06-09 08:17:35 +04:00
int ret ;
2007-04-29 18:19:40 +04:00
2010-02-11 03:49:48 +03:00
DEBUG ( DEBUG_DEBUG , ( " pnn %u dmaster response %08x \n " , ctdb - > pnn , ctdb_hash ( & key ) ) ) ;
2007-04-29 18:19:40 +04:00
ZERO_STRUCT ( header ) ;
2013-04-03 14:02:59 +04:00
header . rsn = rsn ;
2007-09-04 04:06:36 +04:00
header . dmaster = ctdb - > pnn ;
2010-12-10 16:07:21 +03:00
header . flags = record_flags ;
2007-04-29 18:19:40 +04:00
2015-03-17 06:30:18 +03:00
state = reqid_find ( ctdb - > idr , hdr - > reqid , struct ctdb_call_state ) ;
2010-12-10 16:11:38 +03:00
if ( state ) {
if ( state - > call - > flags & CTDB_CALL_FLAG_VACUUM_MIGRATION ) {
/*
* We temporarily add the VACUUM_MIGRATED flag to
* the record flags , so that ctdb_ltdb_store can
* decide whether the record should be stored or
* deleted .
*/
header . flags | = CTDB_REC_FLAG_VACUUM_MIGRATED ;
}
}
2007-04-29 18:19:40 +04:00
if ( ctdb_ltdb_store ( ctdb_db , key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " ctdb_reply_dmaster store failed \n " ) ;
2010-06-09 08:17:35 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2007-04-29 18:19:40 +04:00
return ;
}
2007-04-22 20:19:49 +04:00
2012-03-20 09:58:35 +04:00
/* we just became DMASTER and this database is "sticky",
see if the record is flagged as " hot " and set up a pin - down
context to stop migrations for a little while if so
*/
2017-03-02 07:47:46 +03:00
if ( ctdb_db_sticky ( ctdb_db ) ) {
2012-03-20 09:58:35 +04:00
ctdb_set_sticky_pindown ( ctdb , ctdb_db , key ) ;
}
2007-04-23 12:19:50 +04:00
2007-04-22 20:19:49 +04:00
if ( state = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " pnn %u Invalid reqid %u in ctdb_become_dmaster from node %u \n " ,
2007-09-04 04:06:36 +04:00
ctdb - > pnn , hdr - > reqid , hdr - > srcnode ) ) ;
2010-06-09 08:17:35 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2007-04-22 20:19:49 +04:00
return ;
}
2010-06-09 10:12:36 +04:00
if ( key . dsize ! = state - > call - > key . dsize | | memcmp ( key . dptr , state - > call - > key . dptr , key . dsize ) ) {
2010-06-09 10:22:01 +04:00
DEBUG ( DEBUG_ERR , ( " Got bogus DMASTER packet reqid:%u from node %u. Key does not match key held in matching idr. \n " , hdr - > reqid , hdr - > srcnode ) ) ;
2010-06-09 10:12:36 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
return ;
}
2007-07-11 03:44:52 +04:00
if ( hdr - > reqid ! = state - > reqid ) {
2007-04-23 12:19:50 +04:00
/* we found a record but it was the wrong one */
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Dropped orphan in ctdb_become_dmaster with reqid:%u \n from node %u " , hdr - > reqid , hdr - > srcnode ) ) ;
2010-06-09 08:17:35 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2007-04-22 20:19:49 +04:00
return ;
}
2017-03-21 08:48:45 +03:00
( void ) hash_count_increment ( ctdb_db - > migratedb , key ) ;
2013-08-19 09:04:46 +04:00
ctdb_call_local ( ctdb_db , state - > call , & header , state , & data , true ) ;
2007-04-22 20:19:49 +04:00
2010-06-09 10:12:36 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , state - > call - > key ) ;
2010-06-09 08:17:35 +04:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2007-04-22 20:19:49 +04:00
state - > state = CTDB_CALL_DONE ;
if ( state - > async . fn ) {
state - > async . fn ( state ) ;
}
}
2014-08-15 09:20:36 +04:00
struct dmaster_defer_call {
struct dmaster_defer_call * next , * prev ;
struct ctdb_context * ctdb ;
struct ctdb_req_header * hdr ;
} ;
struct dmaster_defer_queue {
2015-09-15 09:50:19 +03:00
struct ctdb_db_context * ctdb_db ;
2014-09-02 10:10:20 +04:00
uint32_t generation ;
2014-08-15 09:20:36 +04:00
struct dmaster_defer_call * deferred_calls ;
} ;
2007-04-22 20:19:49 +04:00
2014-08-15 09:20:36 +04:00
static void dmaster_defer_reprocess ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t ,
void * private_data )
{
struct dmaster_defer_call * call = talloc_get_type (
private_data , struct dmaster_defer_call ) ;
ctdb_input_pkt ( call - > ctdb , call - > hdr ) ;
talloc_free ( call ) ;
}
static int dmaster_defer_queue_destructor ( struct dmaster_defer_queue * ddq )
{
2014-09-02 10:10:20 +04:00
/* Ignore requests, if database recovery happens in-between. */
2015-09-15 09:50:19 +03:00
if ( ddq - > generation ! = ddq - > ctdb_db - > generation ) {
2014-09-02 10:10:20 +04:00
return 0 ;
}
2014-08-15 09:20:36 +04:00
while ( ddq - > deferred_calls ! = NULL ) {
struct dmaster_defer_call * call = ddq - > deferred_calls ;
DLIST_REMOVE ( ddq - > deferred_calls , call ) ;
talloc_steal ( call - > ctdb , call ) ;
tevent_add_timer ( call - > ctdb - > ev , call , timeval_zero ( ) ,
dmaster_defer_reprocess , call ) ;
}
return 0 ;
}
static void * insert_ddq_callback ( void * parm , void * data )
{
if ( data ) {
talloc_free ( data ) ;
}
return parm ;
}
/**
2019-10-26 03:41:08 +03:00
* This function is used to register a key in database that needs to be updated .
2014-08-15 09:20:36 +04:00
* Any requests for that key should get deferred till this is completed .
*/
static int dmaster_defer_setup ( struct ctdb_db_context * ctdb_db ,
struct ctdb_req_header * hdr ,
TDB_DATA key )
{
uint32_t * k ;
struct dmaster_defer_queue * ddq ;
k = ctdb_key_to_idkey ( hdr , key ) ;
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for dmaster defer setup \n " ) ) ;
return - 1 ;
}
/* Already exists */
ddq = trbt_lookuparray32 ( ctdb_db - > defer_dmaster , k [ 0 ] , k ) ;
if ( ddq ! = NULL ) {
2015-09-23 07:47:58 +03:00
if ( ddq - > generation = = ctdb_db - > generation ) {
talloc_free ( k ) ;
return 0 ;
}
2019-10-26 03:41:08 +03:00
/* Recovery occurred - get rid of old queue. All the deferred
2015-09-23 07:47:58 +03:00
* requests will be resent anyway from ctdb_call_resend_db .
*/
talloc_free ( ddq ) ;
2014-08-15 09:20:36 +04:00
}
ddq = talloc ( hdr , struct dmaster_defer_queue ) ;
if ( ddq = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate dmaster defer queue \n " ) ) ;
talloc_free ( k ) ;
return - 1 ;
}
2015-09-15 09:50:19 +03:00
ddq - > ctdb_db = ctdb_db ;
2014-09-02 10:10:20 +04:00
ddq - > generation = hdr - > generation ;
2014-08-15 09:20:36 +04:00
ddq - > deferred_calls = NULL ;
trbt_insertarray32_callback ( ctdb_db - > defer_dmaster , k [ 0 ] , k ,
insert_ddq_callback , ddq ) ;
talloc_set_destructor ( ddq , dmaster_defer_queue_destructor ) ;
talloc_free ( k ) ;
return 0 ;
}
static int dmaster_defer_add ( struct ctdb_db_context * ctdb_db ,
struct ctdb_req_header * hdr ,
TDB_DATA key )
{
struct dmaster_defer_queue * ddq ;
struct dmaster_defer_call * call ;
uint32_t * k ;
k = ctdb_key_to_idkey ( hdr , key ) ;
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for dmaster defer add \n " ) ) ;
return - 1 ;
}
ddq = trbt_lookuparray32 ( ctdb_db - > defer_dmaster , k [ 0 ] , k ) ;
if ( ddq = = NULL ) {
talloc_free ( k ) ;
return - 1 ;
}
talloc_free ( k ) ;
2014-09-02 10:10:20 +04:00
if ( ddq - > generation ! = hdr - > generation ) {
talloc_set_destructor ( ddq , NULL ) ;
talloc_free ( ddq ) ;
return - 1 ;
}
2014-08-15 09:20:36 +04:00
call = talloc ( ddq , struct dmaster_defer_call ) ;
if ( call = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate dmaster defer call \n " ) ) ;
return - 1 ;
}
call - > ctdb = ctdb_db - > ctdb ;
call - > hdr = talloc_steal ( call , hdr ) ;
2016-02-05 13:32:18 +03:00
DLIST_ADD_END ( ddq - > deferred_calls , call ) ;
2014-08-15 09:20:36 +04:00
return 0 ;
}
2006-12-18 08:01:11 +03:00
/*
called when a CTDB_REQ_DMASTER packet comes in
this comes into the lmaster for a record when the current dmaster
wants to give up the dmaster role and give it to someone else
*/
void ctdb_request_dmaster ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
{
2015-10-29 08:32:09 +03:00
struct ctdb_req_dmaster_old * c = ( struct ctdb_req_dmaster_old * ) hdr ;
2007-01-23 03:38:45 +03:00
TDB_DATA key , data , data2 ;
2006-12-18 08:01:11 +03:00
struct ctdb_ltdb_header header ;
2007-04-03 13:41:00 +04:00
struct ctdb_db_context * ctdb_db ;
2010-12-10 16:02:33 +03:00
uint32_t record_flags = 0 ;
size_t len ;
2007-04-22 16:26:45 +04:00
int ret ;
2006-12-18 08:01:11 +03:00
key . dptr = c - > data ;
key . dsize = c - > keylen ;
data . dptr = c - > data + c - > keylen ;
data . dsize = c - > datalen ;
2015-10-29 08:32:09 +03:00
len = offsetof ( struct ctdb_req_dmaster_old , data ) + key . dsize + data . dsize
2010-12-10 16:02:33 +03:00
+ sizeof ( uint32_t ) ;
if ( len < = c - > hdr . length ) {
2014-08-04 08:50:17 +04:00
memcpy ( & record_flags , & c - > data [ c - > keylen + c - > datalen ] ,
sizeof ( record_flags ) ) ;
2010-12-10 16:02:33 +03:00
}
2006-12-18 08:01:11 +03:00
2016-02-02 07:58:37 +03:00
ctdb_db = find_ctdb_db ( ctdb , c - > db_id ) ;
if ( ! ctdb_db ) {
ctdb_send_error ( ctdb , hdr , - 1 ,
" Unknown database in request. db_id==0x%08x " ,
c - > db_id ) ;
return ;
}
2014-08-15 09:20:36 +04:00
dmaster_defer_setup ( ctdb_db , hdr , key ) ;
2007-04-19 10:27:56 +04:00
/* fetch the current record */
ret = ctdb_ltdb_lock_fetch_requeue ( ctdb_db , key , & header , hdr , & data2 ,
2012-05-17 10:08:37 +04:00
ctdb_call_input_pkt , ctdb , false ) ;
2007-04-19 10:27:56 +04:00
if ( ret = = - 1 ) {
ctdb_fatal ( ctdb , " ctdb_req_dmaster failed to fetch record " ) ;
return ;
}
if ( ret = = - 2 ) {
2008-02-04 09:44:24 +03:00
DEBUG ( DEBUG_INFO , ( __location__ " deferring ctdb_request_dmaster \n " ) ) ;
2007-04-19 10:27:56 +04:00
return ;
}
2007-04-22 20:19:49 +04:00
2007-09-04 04:06:36 +04:00
if ( ctdb_lmaster ( ctdb , & key ) ! = ctdb - > pnn ) {
2015-12-03 09:43:44 +03:00
DEBUG ( DEBUG_ERR , ( " dmaster request to non-lmaster "
" db=%s lmaster=%u gen=%u curgen=%u \n " ,
ctdb_db - > db_name , ctdb_lmaster ( ctdb , & key ) ,
hdr - > generation , ctdb_db - > generation ) ) ;
2007-04-22 20:19:49 +04:00
ctdb_fatal ( ctdb , " ctdb_req_dmaster to non-lmaster " ) ;
}
2010-02-11 03:49:48 +03:00
DEBUG ( DEBUG_DEBUG , ( " pnn %u dmaster request on %08x for %u from %u \n " ,
2007-09-04 04:06:36 +04:00
ctdb - > pnn , ctdb_hash ( & key ) , c - > dmaster , c - > hdr . srcnode ) ) ;
2007-04-22 20:19:49 +04:00
2007-04-19 10:27:56 +04:00
/* its a protocol error if the sending node is not the current dmaster */
2007-04-22 16:26:45 +04:00
if ( header . dmaster ! = hdr - > srcnode ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ALERT , ( " pnn %u dmaster request for new-dmaster %u from non-master %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u keyval=0x%08x \n " ,
2008-01-05 01:32:29 +03:00
ctdb - > pnn , c - > dmaster , hdr - > srcnode , header . dmaster , ctdb_hash ( & key ) ,
2016-02-02 07:58:37 +03:00
ctdb_db - > db_id , hdr - > generation , ctdb - > vnn_map - > generation ,
2008-01-05 01:32:29 +03:00
( unsigned long long ) c - > rsn , ( unsigned long long ) header . rsn , c - > hdr . reqid ,
( key . dsize > = 4 ) ? ( * ( uint32_t * ) key . dptr ) : 0 ) ) ;
2009-10-29 05:44:12 +03:00
if ( header . rsn ! = 0 | | header . dmaster ! = ctdb - > pnn ) {
2011-02-18 03:21:19 +03:00
DEBUG ( DEBUG_ERR , ( " ctdb_req_dmaster from non-master. Force a recovery. \n " ) ) ;
ctdb - > recovery_mode = CTDB_RECOVERY_ACTIVE ;
2011-03-21 05:33:01 +03:00
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2009-10-29 05:44:12 +03:00
return ;
}
2008-01-05 01:32:29 +03:00
}
if ( header . rsn > c - > rsn ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ALERT , ( " pnn %u dmaster request with older RSN new-dmaster %u from %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u \n " ,
2008-01-05 01:32:29 +03:00
ctdb - > pnn , c - > dmaster , hdr - > srcnode , header . dmaster , ctdb_hash ( & key ) ,
2016-02-02 07:58:37 +03:00
ctdb_db - > db_id , hdr - > generation , ctdb - > vnn_map - > generation ,
2008-01-05 01:32:29 +03:00
( unsigned long long ) c - > rsn , ( unsigned long long ) header . rsn , c - > hdr . reqid ) ) ;
2006-12-18 08:01:11 +03:00
}
2007-05-12 13:55:18 +04:00
/* use the rsn from the sending node */
header . rsn = c - > rsn ;
2010-12-10 16:02:33 +03:00
/* store the record flags from the sending node */
header . flags = record_flags ;
2007-04-22 20:19:49 +04:00
/* check if the new dmaster is the lmaster, in which case we
skip the dmaster reply */
2007-09-04 04:06:36 +04:00
if ( c - > dmaster = = ctdb - > pnn ) {
2010-12-10 16:02:33 +03:00
ctdb_become_dmaster ( ctdb_db , hdr , key , data , c - > rsn , record_flags ) ;
2007-04-22 20:19:49 +04:00
} else {
ctdb_send_dmaster_reply ( ctdb_db , & header , key , data , c - > dmaster , hdr - > reqid ) ;
2010-06-09 08:31:05 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2007-04-22 20:19:49 +04:00
}
2006-12-18 08:01:11 +03:00
}
2015-10-26 08:50:09 +03:00
static void ctdb_sticky_record_timeout ( struct tevent_context * ev ,
struct tevent_timer * te ,
2012-03-20 09:58:35 +04:00
struct timeval t , void * private_data )
{
struct ctdb_sticky_record * sr = talloc_get_type ( private_data ,
struct ctdb_sticky_record ) ;
talloc_free ( sr ) ;
}
static void * ctdb_make_sticky_record_callback ( void * parm , void * data )
{
if ( data ) {
DEBUG ( DEBUG_ERR , ( " Already have sticky record registered. Free old %p and create new %p \n " , data , parm ) ) ;
talloc_free ( data ) ;
}
return parm ;
}
static int
ctdb_make_record_sticky ( struct ctdb_context * ctdb , struct ctdb_db_context * ctdb_db , TDB_DATA key )
{
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
uint32_t * k ;
struct ctdb_sticky_record * sr ;
2014-08-15 07:33:24 +04:00
k = ctdb_key_to_idkey ( tmp_ctx , key ) ;
2012-03-20 09:58:35 +04:00
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for sticky record \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
sr = trbt_lookuparray32 ( ctdb_db - > sticky_records , k [ 0 ] , & k [ 0 ] ) ;
if ( sr ! = NULL ) {
talloc_free ( tmp_ctx ) ;
return 0 ;
}
sr = talloc ( ctdb_db - > sticky_records , struct ctdb_sticky_record ) ;
if ( sr = = NULL ) {
talloc_free ( tmp_ctx ) ;
DEBUG ( DEBUG_ERR , ( " Failed to allocate sticky record structure \n " ) ) ;
return - 1 ;
}
sr - > ctdb = ctdb ;
sr - > ctdb_db = ctdb_db ;
sr - > pindown = NULL ;
2013-07-31 09:59:11 +04:00
DEBUG ( DEBUG_ERR , ( " Make record sticky for %d seconds in db %s key:0x%08x. \n " ,
ctdb - > tunable . sticky_duration ,
ctdb_db - > db_name , ctdb_hash ( & key ) ) ) ;
2012-03-20 09:58:35 +04:00
trbt_insertarray32_callback ( ctdb_db - > sticky_records , k [ 0 ] , & k [ 0 ] , ctdb_make_sticky_record_callback , sr ) ;
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , sr ,
timeval_current_ofs ( ctdb - > tunable . sticky_duration , 0 ) ,
ctdb_sticky_record_timeout , sr ) ;
2012-03-20 09:58:35 +04:00
talloc_free ( tmp_ctx ) ;
return 0 ;
}
struct pinned_down_requeue_handle {
struct ctdb_context * ctdb ;
struct ctdb_req_header * hdr ;
} ;
struct pinned_down_deferred_call {
struct ctdb_context * ctdb ;
struct ctdb_req_header * hdr ;
} ;
2015-10-26 08:50:09 +03:00
static void pinned_down_requeue ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2012-03-20 09:58:35 +04:00
{
struct pinned_down_requeue_handle * handle = talloc_get_type ( private_data , struct pinned_down_requeue_handle ) ;
struct ctdb_context * ctdb = handle - > ctdb ;
talloc_steal ( ctdb , handle - > hdr ) ;
ctdb_call_input_pkt ( ctdb , handle - > hdr ) ;
talloc_free ( handle ) ;
}
static int pinned_down_destructor ( struct pinned_down_deferred_call * pinned_down )
{
struct ctdb_context * ctdb = pinned_down - > ctdb ;
struct pinned_down_requeue_handle * handle = talloc ( ctdb , struct pinned_down_requeue_handle ) ;
handle - > ctdb = pinned_down - > ctdb ;
handle - > hdr = pinned_down - > hdr ;
talloc_steal ( handle , handle - > hdr ) ;
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , handle , timeval_zero ( ) ,
pinned_down_requeue , handle ) ;
2012-03-20 09:58:35 +04:00
return 0 ;
}
static int
ctdb_defer_pinned_down_request ( struct ctdb_context * ctdb , struct ctdb_db_context * ctdb_db , TDB_DATA key , struct ctdb_req_header * hdr )
{
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
uint32_t * k ;
struct ctdb_sticky_record * sr ;
struct pinned_down_deferred_call * pinned_down ;
2014-08-15 07:33:24 +04:00
k = ctdb_key_to_idkey ( tmp_ctx , key ) ;
2012-03-20 09:58:35 +04:00
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for sticky record \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
sr = trbt_lookuparray32 ( ctdb_db - > sticky_records , k [ 0 ] , & k [ 0 ] ) ;
if ( sr = = NULL ) {
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
if ( sr - > pindown = = NULL ) {
return - 1 ;
}
pinned_down = talloc ( sr - > pindown , struct pinned_down_deferred_call ) ;
if ( pinned_down = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate structure for deferred pinned down request \n " ) ) ;
return - 1 ;
}
pinned_down - > ctdb = ctdb ;
pinned_down - > hdr = hdr ;
talloc_set_destructor ( pinned_down , pinned_down_destructor ) ;
talloc_steal ( pinned_down , hdr ) ;
return 0 ;
}
2006-12-18 08:01:11 +03:00
2012-06-13 10:17:18 +04:00
static void
2017-04-03 10:32:32 +03:00
ctdb_update_db_stat_hot_keys ( struct ctdb_db_context * ctdb_db , TDB_DATA key ,
2019-08-01 03:55:39 +03:00
unsigned int count )
2012-06-13 10:17:18 +04:00
{
2013-07-12 11:33:13 +04:00
int i , id ;
2017-02-17 02:23:39 +03:00
char * keystr ;
2012-06-13 10:17:18 +04:00
/* smallest value is always at index 0 */
2017-04-03 10:32:32 +03:00
if ( count < = ctdb_db - > statistics . hot_keys [ 0 ] . count ) {
2012-06-13 10:17:18 +04:00
return ;
}
/* see if we already know this key */
for ( i = 0 ; i < MAX_HOT_KEYS ; i + + ) {
if ( key . dsize ! = ctdb_db - > statistics . hot_keys [ i ] . key . dsize ) {
continue ;
}
if ( memcmp ( key . dptr , ctdb_db - > statistics . hot_keys [ i ] . key . dptr , key . dsize ) ) {
continue ;
}
/* found an entry for this key */
2017-04-03 10:32:32 +03:00
if ( count < = ctdb_db - > statistics . hot_keys [ i ] . count ) {
2012-06-13 10:17:18 +04:00
return ;
}
2017-04-03 10:32:32 +03:00
ctdb_db - > statistics . hot_keys [ i ] . count = count ;
2012-06-13 10:17:18 +04:00
goto sort_keys ;
}
2013-07-12 11:33:13 +04:00
if ( ctdb_db - > statistics . num_hot_keys < MAX_HOT_KEYS ) {
id = ctdb_db - > statistics . num_hot_keys ;
ctdb_db - > statistics . num_hot_keys + + ;
} else {
id = 0 ;
2012-06-13 10:17:18 +04:00
}
2013-07-12 11:33:13 +04:00
if ( ctdb_db - > statistics . hot_keys [ id ] . key . dptr ! = NULL ) {
talloc_free ( ctdb_db - > statistics . hot_keys [ id ] . key . dptr ) ;
}
ctdb_db - > statistics . hot_keys [ id ] . key . dsize = key . dsize ;
ctdb_db - > statistics . hot_keys [ id ] . key . dptr = talloc_memdup ( ctdb_db , key . dptr , key . dsize ) ;
2017-04-03 10:32:32 +03:00
ctdb_db - > statistics . hot_keys [ id ] . count = count ;
2017-02-17 02:23:39 +03:00
keystr = hex_encode_talloc ( ctdb_db ,
( unsigned char * ) key . dptr , key . dsize ) ;
DEBUG ( DEBUG_NOTICE , ( " Updated hot key database=%s key=%s id=%d "
" count=%d \n " , ctdb_db - > db_name ,
keystr ? keystr : " " , id , count ) ) ;
talloc_free ( keystr ) ;
2012-06-13 10:17:18 +04:00
sort_keys :
2013-07-12 11:33:13 +04:00
for ( i = 1 ; i < MAX_HOT_KEYS ; i + + ) {
2013-07-15 10:32:40 +04:00
if ( ctdb_db - > statistics . hot_keys [ i ] . count = = 0 ) {
continue ;
}
2012-06-13 10:17:18 +04:00
if ( ctdb_db - > statistics . hot_keys [ i ] . count < ctdb_db - > statistics . hot_keys [ 0 ] . count ) {
2017-04-03 10:32:32 +03:00
count = ctdb_db - > statistics . hot_keys [ i ] . count ;
2012-06-13 10:17:18 +04:00
ctdb_db - > statistics . hot_keys [ i ] . count = ctdb_db - > statistics . hot_keys [ 0 ] . count ;
2017-04-03 10:32:32 +03:00
ctdb_db - > statistics . hot_keys [ 0 ] . count = count ;
2012-06-13 10:17:18 +04:00
key = ctdb_db - > statistics . hot_keys [ i ] . key ;
ctdb_db - > statistics . hot_keys [ i ] . key = ctdb_db - > statistics . hot_keys [ 0 ] . key ;
ctdb_db - > statistics . hot_keys [ 0 ] . key = key ;
}
}
}
2006-11-28 09:56:10 +03:00
/*
2006-12-01 07:45:24 +03:00
called when a CTDB_REQ_CALL packet comes in
2006-11-28 09:56:10 +03:00
*/
2006-12-01 07:45:24 +03:00
void ctdb_request_call ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
2006-11-28 09:56:10 +03:00
{
2015-10-29 08:26:29 +03:00
struct ctdb_req_call_old * c = ( struct ctdb_req_call_old * ) hdr ;
2007-01-25 08:13:17 +03:00
TDB_DATA data ;
2015-10-29 08:29:01 +03:00
struct ctdb_reply_call_old * r ;
2007-01-23 03:38:45 +03:00
int ret , len ;
2006-12-18 06:05:49 +03:00
struct ctdb_ltdb_header header ;
2008-03-19 05:54:17 +03:00
struct ctdb_call * call ;
2007-04-03 13:41:00 +04:00
struct ctdb_db_context * ctdb_db ;
2012-03-07 10:02:41 +04:00
int tmp_count , bucket ;
2007-04-03 13:41:00 +04:00
2009-06-30 06:16:13 +04:00
if ( ctdb - > methods = = NULL ) {
2010-10-28 06:38:34 +04:00
DEBUG ( DEBUG_INFO , ( __location__ " Failed ctdb_request_call. Transport is DOWN \n " ) ) ;
2009-06-30 06:16:13 +04:00
return ;
}
2016-02-02 07:58:37 +03:00
2007-04-12 09:46:50 +04:00
ctdb_db = find_ctdb_db ( ctdb , c - > db_id ) ;
2007-04-03 13:41:00 +04:00
if ( ! ctdb_db ) {
2007-04-11 14:49:10 +04:00
ctdb_send_error ( ctdb , hdr , - 1 ,
" Unknown database in request. db_id==0x%08x " ,
c - > db_id ) ;
2007-04-03 13:41:00 +04:00
return ;
}
2006-12-01 07:45:24 +03:00
2008-03-19 05:54:17 +03:00
call = talloc ( hdr , struct ctdb_call ) ;
CTDB_NO_MEMORY_FATAL ( ctdb , call ) ;
call - > call_id = c - > callid ;
call - > key . dptr = c - > data ;
call - > key . dsize = c - > keylen ;
call - > call_data . dptr = c - > data + c - > keylen ;
call - > call_data . dsize = c - > calldatalen ;
2011-07-20 09:13:47 +04:00
call - > reply_data . dptr = NULL ;
call - > reply_data . dsize = 0 ;
2006-12-01 07:45:24 +03:00
2012-03-20 09:58:35 +04:00
/* If this record is pinned down we should defer the
request until the pindown times out
*/
2017-03-02 07:47:46 +03:00
if ( ctdb_db_sticky ( ctdb_db ) ) {
2012-03-20 09:58:35 +04:00
if ( ctdb_defer_pinned_down_request ( ctdb , ctdb_db , call - > key , hdr ) = = 0 ) {
2013-07-23 10:00:15 +04:00
DEBUG ( DEBUG_WARNING ,
( " Defer request for pinned down record in %s \n " , ctdb_db - > db_name ) ) ;
talloc_free ( call ) ;
2012-03-20 09:58:35 +04:00
return ;
}
}
2014-08-15 09:20:36 +04:00
if ( dmaster_defer_add ( ctdb_db , hdr , call - > key ) = = 0 ) {
talloc_free ( call ) ;
return ;
}
2012-03-20 09:58:35 +04:00
2006-12-18 06:05:49 +03:00
/* determine if we are the dmaster for this key. This also
fetches the record data ( if any ) , thus avoiding a 2 nd fetch of the data
if the call will be answered locally */
2007-01-29 14:11:16 +03:00
2008-03-19 05:54:17 +03:00
ret = ctdb_ltdb_lock_fetch_requeue ( ctdb_db , call - > key , & header , hdr , & data ,
2012-05-17 10:08:37 +04:00
ctdb_call_input_pkt , ctdb , false ) ;
2007-04-17 10:54:03 +04:00
if ( ret = = - 1 ) {
2006-12-18 06:27:20 +03:00
ctdb_send_error ( ctdb , hdr , ret , " ltdb fetch failed in ctdb_request_call " ) ;
2013-07-23 10:00:15 +04:00
talloc_free ( call ) ;
2006-12-18 06:05:49 +03:00
return ;
}
2007-04-17 10:54:03 +04:00
if ( ret = = - 2 ) {
2008-02-04 09:44:24 +03:00
DEBUG ( DEBUG_INFO , ( __location__ " deferred ctdb_request_call \n " ) ) ;
2013-07-23 10:00:15 +04:00
talloc_free ( call ) ;
2007-04-17 10:54:03 +04:00
return ;
}
2006-12-18 06:05:49 +03:00
2015-07-27 00:02:57 +03:00
/* Dont do READONLY if we don't have a tracking database */
2017-03-02 07:44:48 +03:00
if ( ( c - > flags & CTDB_WANT_READONLY ) & & ! ctdb_db_readonly ( ctdb_db ) ) {
2011-07-20 09:13:47 +04:00
c - > flags & = ~ CTDB_WANT_READONLY ;
}
if ( header . flags & CTDB_REC_RO_REVOKE_COMPLETE ) {
2013-04-19 18:22:49 +04:00
header . flags & = ~ CTDB_REC_RO_FLAGS ;
2012-02-08 06:42:30 +04:00
CTDB_INCREMENT_STAT ( ctdb , total_ro_revokes ) ;
2012-02-08 08:29:27 +04:00
CTDB_INCREMENT_DB_STAT ( ctdb_db , db_ro_revokes ) ;
2011-07-20 09:13:47 +04:00
if ( ctdb_ltdb_store ( ctdb_db , call - > key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to write header with cleared REVOKE flag " ) ;
}
2011-08-17 10:14:57 +04:00
/* and clear out the tracking data */
if ( tdb_delete ( ctdb_db - > rottdb , call - > key ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to clear out trackingdb record \n " ) ) ;
}
2011-07-20 09:13:47 +04:00
}
/* if we are revoking, we must defer all other calls until the revoke
* had completed .
*/
if ( header . flags & CTDB_REC_RO_REVOKING_READONLY ) {
talloc_free ( data . dptr ) ;
ret = ctdb_ltdb_unlock ( ctdb_db , call - > key ) ;
if ( ctdb_add_revoke_deferred_call ( ctdb , ctdb_db , call - > key , hdr , ctdb_call_input_pkt , ctdb ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to add deferred call for revoke child " ) ;
}
talloc_free ( call ) ;
return ;
}
2013-05-17 13:05:44 +04:00
/*
* If we are not the dmaster and are not hosting any delegations ,
* then we redirect the request to the node than can answer it
* ( the lmaster or the dmaster ) .
*/
2011-07-20 09:13:47 +04:00
if ( ( header . dmaster ! = ctdb - > pnn )
& & ( ! ( header . flags & CTDB_REC_RO_HAVE_DELEGATIONS ) ) ) {
2006-12-18 06:05:49 +03:00
talloc_free ( data . dptr ) ;
2012-03-20 09:58:35 +04:00
ctdb_call_send_redirect ( ctdb , ctdb_db , call - > key , c , & header ) ;
2010-06-09 08:31:05 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , call - > key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2013-07-23 10:00:15 +04:00
talloc_free ( call ) ;
2006-12-18 06:05:49 +03:00
return ;
}
2011-07-20 09:13:47 +04:00
if ( ( ! ( c - > flags & CTDB_WANT_READONLY ) )
& & ( header . flags & ( CTDB_REC_RO_HAVE_DELEGATIONS | CTDB_REC_RO_HAVE_READONLY ) ) ) {
header . flags | = CTDB_REC_RO_REVOKING_READONLY ;
if ( ctdb_ltdb_store ( ctdb_db , call - > key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to store record with HAVE_DELEGATIONS set " ) ;
}
ret = ctdb_ltdb_unlock ( ctdb_db , call - > key ) ;
if ( ctdb_start_revoke_ro_record ( ctdb , ctdb_db , call - > key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to start record revoke " ) ;
}
talloc_free ( data . dptr ) ;
if ( ctdb_add_revoke_deferred_call ( ctdb , ctdb_db , call - > key , hdr , ctdb_call_input_pkt , ctdb ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to add deferred call for revoke child " ) ;
}
talloc_free ( call ) ;
return ;
}
/* If this is the first request for delegation. bump rsn and set
* the delegations flag
*/
if ( ( c - > flags & CTDB_WANT_READONLY )
& & ( c - > callid = = CTDB_FETCH_WITH_HEADER_FUNC )
& & ( ! ( header . flags & CTDB_REC_RO_HAVE_DELEGATIONS ) ) ) {
header . rsn + = 3 ;
header . flags | = CTDB_REC_RO_HAVE_DELEGATIONS ;
if ( ctdb_ltdb_store ( ctdb_db , call - > key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to store record with HAVE_DELEGATIONS set " ) ;
}
}
if ( ( c - > flags & CTDB_WANT_READONLY )
2019-08-01 03:58:42 +03:00
& & ( ( unsigned int ) call - > call_id = = CTDB_FETCH_WITH_HEADER_FUNC ) ) {
2011-07-20 09:13:47 +04:00
TDB_DATA tdata ;
tdata = tdb_fetch ( ctdb_db - > rottdb , call - > key ) ;
if ( ctdb_trackingdb_add_pnn ( ctdb , & tdata , c - > hdr . srcnode ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to add node to trackingdb " ) ;
}
if ( tdb_store ( ctdb_db - > rottdb , call - > key , tdata , TDB_REPLACE ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to store trackingdb data " ) ;
}
free ( tdata . dptr ) ;
ret = ctdb_ltdb_unlock ( ctdb_db , call - > key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2015-10-29 08:29:01 +03:00
len = offsetof ( struct ctdb_reply_call_old , data ) + data . dsize + sizeof ( struct ctdb_ltdb_header ) ;
2011-07-20 09:13:47 +04:00
r = ctdb_transport_allocate ( ctdb , ctdb , CTDB_REPLY_CALL , len ,
2015-10-29 08:29:01 +03:00
struct ctdb_reply_call_old ) ;
2011-07-20 09:13:47 +04:00
CTDB_NO_MEMORY_FATAL ( ctdb , r ) ;
r - > hdr . destnode = c - > hdr . srcnode ;
r - > hdr . reqid = c - > hdr . reqid ;
2015-09-15 09:50:19 +03:00
r - > hdr . generation = ctdb_db - > generation ;
2011-07-20 09:13:47 +04:00
r - > status = 0 ;
r - > datalen = data . dsize + sizeof ( struct ctdb_ltdb_header ) ;
header . rsn - = 2 ;
header . flags | = CTDB_REC_RO_HAVE_READONLY ;
header . flags & = ~ CTDB_REC_RO_HAVE_DELEGATIONS ;
memcpy ( & r - > data [ 0 ] , & header , sizeof ( struct ctdb_ltdb_header ) ) ;
if ( data . dsize ) {
memcpy ( & r - > data [ sizeof ( struct ctdb_ltdb_header ) ] , data . dptr , data . dsize ) ;
}
ctdb_queue_packet ( ctdb , & r - > hdr ) ;
2012-02-08 06:42:30 +04:00
CTDB_INCREMENT_STAT ( ctdb , total_ro_delegations ) ;
2012-02-08 08:29:27 +04:00
CTDB_INCREMENT_DB_STAT ( ctdb_db , db_ro_delegations ) ;
2011-07-20 09:13:47 +04:00
talloc_free ( r ) ;
2013-07-23 10:00:15 +04:00
talloc_free ( call ) ;
2011-07-20 09:13:47 +04:00
return ;
}
2010-09-29 04:38:41 +04:00
CTDB_UPDATE_STAT ( ctdb , max_hop_count , c - > hopcount ) ;
2012-03-07 10:02:41 +04:00
tmp_count = c - > hopcount ;
bucket = 0 ;
while ( tmp_count ) {
2018-11-15 05:58:53 +03:00
tmp_count > > = 1 ;
2012-03-07 10:02:41 +04:00
bucket + + ;
}
2012-03-20 05:08:12 +04:00
if ( bucket > = MAX_COUNT_BUCKETS ) {
bucket = MAX_COUNT_BUCKETS - 1 ;
2012-03-07 10:02:41 +04:00
}
CTDB_INCREMENT_STAT ( ctdb , hop_count_bucket [ bucket ] ) ;
2012-03-20 05:08:12 +04:00
CTDB_INCREMENT_DB_STAT ( ctdb_db , hop_count_bucket [ bucket ] ) ;
2007-05-01 07:25:02 +04:00
2012-03-20 09:58:35 +04:00
/* If this database supports sticky records, then check if the
hopcount is big . If it is it means the record is hot and we
should make it sticky .
*/
2017-03-02 07:47:46 +03:00
if ( ctdb_db_sticky ( ctdb_db ) & &
c - > hopcount > = ctdb - > tunable . hopcount_make_sticky ) {
2012-03-20 09:58:35 +04:00
ctdb_make_record_sticky ( ctdb , ctdb_db , call - > key ) ;
}
2013-08-19 09:04:46 +04:00
/* Try if possible to migrate the record off to the caller node.
* From the clients perspective a fetch of the data is just as
* expensive as a migration .
*/
if ( c - > hdr . srcnode ! = ctdb - > pnn ) {
2013-09-12 10:43:43 +04:00
if ( ctdb_db - > persistent_state ) {
2009-12-09 15:43:38 +03:00
DEBUG ( DEBUG_INFO , ( __location__ " refusing migration "
2009-07-21 13:30:38 +04:00
" of key %s while transaction is active \n " ,
( char * ) call - > key . dptr ) ) ;
} else {
2010-02-11 03:54:46 +03:00
DEBUG ( DEBUG_DEBUG , ( " pnn %u starting migration of %08x to %u \n " ,
2009-07-21 13:30:38 +04:00
ctdb - > pnn , ctdb_hash ( & ( call - > key ) ) , c - > hdr . srcnode ) ) ;
ctdb_call_send_dmaster ( ctdb_db , c , & header , & ( call - > key ) , & data ) ;
talloc_free ( data . dptr ) ;
2010-06-09 08:31:05 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , call - > key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2009-07-21 13:30:38 +04:00
}
2013-07-23 10:00:15 +04:00
talloc_free ( call ) ;
return ;
2006-12-18 08:01:11 +03:00
}
2013-08-19 09:04:46 +04:00
ret = ctdb_call_local ( ctdb_db , call , & header , hdr , & data , true ) ;
2011-07-20 07:30:12 +04:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_call_local failed \n " ) ) ;
call - > status = - 1 ;
}
2006-12-01 07:45:24 +03:00
2010-06-09 08:31:05 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , call - > key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2007-04-17 10:54:03 +04:00
2015-10-29 08:29:01 +03:00
len = offsetof ( struct ctdb_reply_call_old , data ) + call - > reply_data . dsize ;
2007-04-28 12:50:32 +04:00
r = ctdb_transport_allocate ( ctdb , ctdb , CTDB_REPLY_CALL , len ,
2015-10-29 08:29:01 +03:00
struct ctdb_reply_call_old ) ;
2006-12-18 08:26:57 +03:00
CTDB_NO_MEMORY_FATAL ( ctdb , r ) ;
2006-12-01 07:45:24 +03:00
r - > hdr . destnode = hdr - > srcnode ;
r - > hdr . reqid = hdr - > reqid ;
2015-09-15 09:50:19 +03:00
r - > hdr . generation = ctdb_db - > generation ;
2008-03-19 05:54:17 +03:00
r - > status = call - > status ;
r - > datalen = call - > reply_data . dsize ;
if ( call - > reply_data . dsize ) {
memcpy ( & r - > data [ 0 ] , call - > reply_data . dptr , call - > reply_data . dsize ) ;
2007-01-29 14:30:06 +03:00
}
2006-12-01 07:45:24 +03:00
2006-12-18 08:26:57 +03:00
ctdb_queue_packet ( ctdb , & r - > hdr ) ;
2006-12-01 07:45:24 +03:00
talloc_free ( r ) ;
2013-07-23 10:00:15 +04:00
talloc_free ( call ) ;
2006-12-01 07:45:24 +03:00
}
2013-08-19 19:07:19 +04:00
/**
* called when a CTDB_REPLY_CALL packet comes in
*
* This packet comes in response to a CTDB_REQ_CALL request packet . It
* contains any reply data from the call
*/
2006-12-01 07:45:24 +03:00
void ctdb_reply_call ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
{
2015-10-29 08:29:01 +03:00
struct ctdb_reply_call_old * c = ( struct ctdb_reply_call_old * ) hdr ;
2006-12-01 07:45:24 +03:00
struct ctdb_call_state * state ;
2015-03-17 06:30:18 +03:00
state = reqid_find ( ctdb - > idr , hdr - > reqid , struct ctdb_call_state ) ;
2007-04-18 01:03:30 +04:00
if ( state = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " reqid %u not found \n " , hdr - > reqid ) ) ;
2007-04-18 01:03:30 +04:00
return ;
}
2006-12-01 07:45:24 +03:00
2007-04-23 12:19:50 +04:00
if ( hdr - > reqid ! = state - > reqid ) {
/* we found a record but it was the wrong one */
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Dropped orphaned call reply with reqid:%u \n " , hdr - > reqid ) ) ;
2007-04-23 12:19:50 +04:00
return ;
}
2011-10-24 06:14:26 +04:00
/* read only delegation processing */
/* If we got a FETCH_WITH_HEADER we should check if this is a ro
* delegation since we may need to update the record header
*/
if ( state - > c - > callid = = CTDB_FETCH_WITH_HEADER_FUNC ) {
struct ctdb_db_context * ctdb_db = state - > ctdb_db ;
struct ctdb_ltdb_header * header = ( struct ctdb_ltdb_header * ) & c - > data [ 0 ] ;
struct ctdb_ltdb_header oldheader ;
TDB_DATA key , data , olddata ;
int ret ;
if ( ! ( header - > flags & CTDB_REC_RO_HAVE_READONLY ) ) {
goto finished_ro ;
return ;
}
key . dsize = state - > c - > keylen ;
key . dptr = state - > c - > data ;
ret = ctdb_ltdb_lock_requeue ( ctdb_db , key , hdr ,
2012-05-17 10:08:37 +04:00
ctdb_call_input_pkt , ctdb , false ) ;
2011-10-24 06:14:26 +04:00
if ( ret = = - 2 ) {
return ;
}
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to get lock in ctdb_reply_call \n " ) ) ;
return ;
}
ret = ctdb_ltdb_fetch ( ctdb_db , key , & oldheader , state , & olddata ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to fetch old record in ctdb_reply_call \n " ) ) ;
ctdb_ltdb_unlock ( ctdb_db , key ) ;
goto finished_ro ;
}
if ( header - > rsn < = oldheader . rsn ) {
ctdb_ltdb_unlock ( ctdb_db , key ) ;
goto finished_ro ;
}
2011-10-28 04:44:19 +04:00
if ( c - > datalen < sizeof ( struct ctdb_ltdb_header ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Got FETCH_WITH_HEADER reply with too little data: %d bytes \n " , c - > datalen ) ) ;
ctdb_ltdb_unlock ( ctdb_db , key ) ;
goto finished_ro ;
}
data . dsize = c - > datalen - sizeof ( struct ctdb_ltdb_header ) ;
2011-10-24 06:14:26 +04:00
data . dptr = & c - > data [ sizeof ( struct ctdb_ltdb_header ) ] ;
ret = ctdb_ltdb_store ( ctdb_db , key , header , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to store new record in ctdb_reply_call \n " ) ) ;
ctdb_ltdb_unlock ( ctdb_db , key ) ;
goto finished_ro ;
}
ctdb_ltdb_unlock ( ctdb_db , key ) ;
}
finished_ro :
2008-03-19 05:54:17 +03:00
state - > call - > reply_data . dptr = c - > data ;
state - > call - > reply_data . dsize = c - > datalen ;
state - > call - > status = c - > status ;
2006-12-01 07:45:24 +03:00
talloc_steal ( state , c ) ;
state - > state = CTDB_CALL_DONE ;
2007-04-12 09:46:50 +04:00
if ( state - > async . fn ) {
state - > async . fn ( state ) ;
}
2006-12-01 07:45:24 +03:00
}
2007-04-22 20:19:49 +04:00
2013-08-22 18:17:09 +04:00
/**
* called when a CTDB_REPLY_DMASTER packet comes in
*
* This packet comes in from the lmaster in response to a CTDB_REQ_CALL
* request packet . It means that the current dmaster wants to give us
* the dmaster role .
*/
2006-12-18 08:01:11 +03:00
void ctdb_reply_dmaster ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
{
2015-10-29 08:34:01 +03:00
struct ctdb_reply_dmaster_old * c = ( struct ctdb_reply_dmaster_old * ) hdr ;
2007-04-03 13:41:00 +04:00
struct ctdb_db_context * ctdb_db ;
2007-04-29 18:19:40 +04:00
TDB_DATA key , data ;
2010-12-10 16:02:33 +03:00
uint32_t record_flags = 0 ;
size_t len ;
2007-04-19 11:43:27 +04:00
int ret ;
2006-12-18 08:01:11 +03:00
2007-04-29 18:19:40 +04:00
ctdb_db = find_ctdb_db ( ctdb , c - > db_id ) ;
if ( ctdb_db = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unknown db_id 0x%x in ctdb_reply_dmaster \n " , c - > db_id ) ) ;
2007-04-23 12:19:50 +04:00
return ;
}
2016-02-02 07:58:37 +03:00
2007-04-29 18:19:40 +04:00
key . dptr = c - > data ;
key . dsize = c - > keylen ;
data . dptr = & c - > data [ key . dsize ] ;
data . dsize = c - > datalen ;
2015-10-29 08:34:01 +03:00
len = offsetof ( struct ctdb_reply_dmaster_old , data ) + key . dsize + data . dsize
2010-12-10 16:02:33 +03:00
+ sizeof ( uint32_t ) ;
if ( len < = c - > hdr . length ) {
2014-08-04 08:50:17 +04:00
memcpy ( & record_flags , & c - > data [ c - > keylen + c - > datalen ] ,
sizeof ( record_flags ) ) ;
2010-12-10 16:02:33 +03:00
}
2007-04-23 12:19:50 +04:00
2014-08-15 09:20:36 +04:00
dmaster_defer_setup ( ctdb_db , hdr , key ) ;
2007-04-29 18:19:40 +04:00
ret = ctdb_ltdb_lock_requeue ( ctdb_db , key , hdr ,
2012-05-17 10:08:37 +04:00
ctdb_call_input_pkt , ctdb , false ) ;
2007-04-19 11:43:27 +04:00
if ( ret = = - 2 ) {
return ;
}
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to get lock in ctdb_reply_dmaster \n " ) ) ;
2007-04-19 11:43:27 +04:00
return ;
}
2010-12-10 16:02:33 +03:00
ctdb_become_dmaster ( ctdb_db , hdr , key , data , c - > rsn , record_flags ) ;
2006-12-18 08:01:11 +03:00
}
2006-12-18 06:27:20 +03:00
/*
called when a CTDB_REPLY_ERROR packet comes in
*/
void ctdb_reply_error ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
{
2015-10-29 08:30:31 +03:00
struct ctdb_reply_error_old * c = ( struct ctdb_reply_error_old * ) hdr ;
2006-12-18 06:27:20 +03:00
struct ctdb_call_state * state ;
2015-03-17 06:30:18 +03:00
state = reqid_find ( ctdb - > idr , hdr - > reqid , struct ctdb_call_state ) ;
2007-04-23 12:19:50 +04:00
if ( state = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " pnn %u Invalid reqid %u in ctdb_reply_error \n " ,
2007-09-04 04:06:36 +04:00
ctdb - > pnn , hdr - > reqid ) ) ;
2007-04-23 12:19:50 +04:00
return ;
}
if ( hdr - > reqid ! = state - > reqid ) {
/* we found a record but it was the wrong one */
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Dropped orphaned error reply with reqid:%u \n " , hdr - > reqid ) ) ;
2007-04-23 12:19:50 +04:00
return ;
}
2006-12-18 06:27:20 +03:00
talloc_steal ( state , c ) ;
state - > state = CTDB_CALL_ERROR ;
state - > errmsg = ( char * ) c - > msg ;
2007-04-12 09:46:50 +04:00
if ( state - > async . fn ) {
state - > async . fn ( state ) ;
}
2006-12-18 06:27:20 +03:00
}
2006-12-18 06:44:06 +03:00
2006-12-01 07:45:24 +03:00
/*
destroy a ctdb_call
*/
static int ctdb_call_destructor ( struct ctdb_call_state * state )
{
2014-08-05 08:42:00 +04:00
DLIST_REMOVE ( state - > ctdb_db - > pending_calls , state ) ;
2015-03-17 06:30:18 +03:00
reqid_remove ( state - > ctdb_db - > ctdb - > idr , state - > reqid ) ;
2006-12-01 07:45:24 +03:00
return 0 ;
}
2006-12-18 06:49:32 +03:00
2006-12-01 07:45:24 +03:00
/*
2007-05-18 18:56:49 +04:00
called when a ctdb_call needs to be resent after a reconfigure event
2006-12-01 07:45:24 +03:00
*/
2007-05-18 18:56:49 +04:00
static void ctdb_call_resend ( struct ctdb_call_state * state )
2006-12-01 07:45:24 +03:00
{
2007-05-10 08:06:48 +04:00
struct ctdb_context * ctdb = state - > ctdb_db - > ctdb ;
2015-09-15 09:50:19 +03:00
state - > generation = state - > ctdb_db - > generation ;
2007-05-10 08:06:48 +04:00
/* use a new reqid, in case the old reply does eventually come in */
2015-03-17 06:30:18 +03:00
reqid_remove ( ctdb - > idr , state - > reqid ) ;
state - > reqid = reqid_new ( ctdb - > idr , state ) ;
2007-05-10 08:06:48 +04:00
state - > c - > hdr . reqid = state - > reqid ;
2007-05-10 11:43:45 +04:00
/* update the generation count for this request, so its valid with the new vnn_map */
state - > c - > hdr . generation = state - > generation ;
2007-05-10 08:06:48 +04:00
/* send the packet to ourselves, it will be redirected appropriately */
2007-09-04 04:06:36 +04:00
state - > c - > hdr . destnode = ctdb - > pnn ;
2007-05-10 08:06:48 +04:00
ctdb_queue_packet ( ctdb , & state - > c - > hdr ) ;
2015-09-21 10:12:25 +03:00
DEBUG ( DEBUG_NOTICE , ( " resent ctdb_call for db %s reqid %u generation %u \n " ,
state - > ctdb_db - > db_name , state - > reqid , state - > generation ) ) ;
2007-05-18 18:56:49 +04:00
}
/*
resend all pending calls on recovery
*/
2014-08-05 08:42:00 +04:00
void ctdb_call_resend_db ( struct ctdb_db_context * ctdb_db )
2007-05-18 18:56:49 +04:00
{
struct ctdb_call_state * state , * next ;
2014-08-05 08:42:00 +04:00
for ( state = ctdb_db - > pending_calls ; state ; state = next ) {
2007-05-18 18:56:49 +04:00
next = state - > next ;
ctdb_call_resend ( state ) ;
}
2006-12-01 07:45:24 +03:00
}
2014-08-05 08:42:00 +04:00
void ctdb_call_resend_all ( struct ctdb_context * ctdb )
{
struct ctdb_db_context * ctdb_db ;
for ( ctdb_db = ctdb - > db_list ; ctdb_db ; ctdb_db = ctdb_db - > next ) {
ctdb_call_resend_db ( ctdb_db ) ;
}
}
2007-04-12 09:46:50 +04:00
/*
this allows the caller to setup a async . fn
*/
2015-10-26 08:50:09 +03:00
static void call_local_trigger ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2007-04-12 09:46:50 +04:00
{
2007-04-13 14:38:24 +04:00
struct ctdb_call_state * state = talloc_get_type ( private_data , struct ctdb_call_state ) ;
2007-04-12 09:46:50 +04:00
if ( state - > async . fn ) {
state - > async . fn ( state ) ;
}
}
2006-12-01 07:45:24 +03:00
/*
2006-12-18 06:49:32 +03:00
construct an event driven local ctdb_call
this is used so that locally processed ctdb_call requests are processed
in an event driven manner
2006-12-01 07:45:24 +03:00
*/
2007-04-03 13:41:00 +04:00
struct ctdb_call_state * ctdb_call_local_send ( struct ctdb_db_context * ctdb_db ,
2007-01-25 08:13:17 +03:00
struct ctdb_call * call ,
2006-12-18 06:05:49 +03:00
struct ctdb_ltdb_header * header ,
TDB_DATA * data )
2006-12-01 07:45:24 +03:00
{
struct ctdb_call_state * state ;
2007-04-03 13:41:00 +04:00
struct ctdb_context * ctdb = ctdb_db - > ctdb ;
2006-12-01 07:45:24 +03:00
int ret ;
2007-04-03 13:41:00 +04:00
state = talloc_zero ( ctdb_db , struct ctdb_call_state ) ;
2006-12-01 12:26:21 +03:00
CTDB_NO_MEMORY_NULL ( ctdb , state ) ;
2006-12-01 07:45:24 +03:00
2007-04-07 04:58:14 +04:00
talloc_steal ( state , data - > dptr ) ;
2006-12-01 07:45:24 +03:00
state - > state = CTDB_CALL_DONE ;
2008-03-19 05:54:17 +03:00
state - > call = talloc ( state , struct ctdb_call ) ;
CTDB_NO_MEMORY_NULL ( ctdb , state - > call ) ;
* ( state - > call ) = * call ;
2007-04-03 13:41:00 +04:00
state - > ctdb_db = ctdb_db ;
2007-01-29 14:11:16 +03:00
2013-08-19 09:04:46 +04:00
ret = ctdb_call_local ( ctdb_db , state - > call , header , state , data , true ) ;
2011-11-09 08:20:07 +04:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_DEBUG , ( " ctdb_call_local() failed, ignoring return code %d \n " , ret ) ) ;
}
2006-12-01 07:45:24 +03:00
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , state , timeval_zero ( ) ,
call_local_trigger , state ) ;
2007-04-12 09:46:50 +04:00
2006-12-01 07:45:24 +03:00
return state ;
}
/*
2007-04-11 05:01:42 +04:00
make a remote ctdb call - async send . Called in daemon context .
2006-12-18 06:49:32 +03:00
This constructs a ctdb_call request and queues it for processing .
This call never blocks .
2006-12-01 07:45:24 +03:00
*/
2007-04-17 10:20:32 +04:00
struct ctdb_call_state * ctdb_daemon_call_send_remote ( struct ctdb_db_context * ctdb_db ,
struct ctdb_call * call ,
struct ctdb_ltdb_header * header )
2006-12-01 07:45:24 +03:00
{
uint32_t len ;
struct ctdb_call_state * state ;
2007-04-03 13:41:00 +04:00
struct ctdb_context * ctdb = ctdb_db - > ctdb ;
2018-02-08 13:33:08 +03:00
struct ctdb_req_call_old * c ;
2006-11-28 09:56:10 +03:00
2009-06-30 05:55:42 +04:00
if ( ctdb - > methods = = NULL ) {
2010-10-28 06:38:34 +04:00
DEBUG ( DEBUG_INFO , ( __location__ " Failed send packet. Transport is down \n " ) ) ;
2009-06-30 05:55:42 +04:00
return NULL ;
}
2007-04-03 13:41:00 +04:00
state = talloc_zero ( ctdb_db , struct ctdb_call_state ) ;
2006-12-01 12:26:21 +03:00
CTDB_NO_MEMORY_NULL ( ctdb , state ) ;
2008-03-19 05:54:17 +03:00
state - > call = talloc ( state , struct ctdb_call ) ;
CTDB_NO_MEMORY_NULL ( ctdb , state - > call ) ;
2015-03-17 06:30:18 +03:00
state - > reqid = reqid_new ( ctdb - > idr , state ) ;
2007-05-10 11:43:45 +04:00
state - > ctdb_db = ctdb_db ;
2006-12-18 08:01:11 +03:00
state - > state = CTDB_CALL_WAIT ;
2015-09-15 09:50:19 +03:00
state - > generation = ctdb_db - > generation ;
2006-11-28 12:48:34 +03:00
2018-02-08 13:33:08 +03:00
len = offsetof ( struct ctdb_req_call_old , data ) + call - > key . dsize +
call - > call_data . dsize ;
c = ctdb_transport_allocate ( ctdb ,
state ,
CTDB_REQ_CALL ,
len ,
struct ctdb_req_call_old ) ;
CTDB_NO_MEMORY_NULL ( ctdb , c ) ;
state - > c = c ;
c - > hdr . destnode = header - > dmaster ;
c - > hdr . reqid = state - > reqid ;
c - > hdr . generation = ctdb_db - > generation ;
c - > flags = call - > flags ;
c - > db_id = ctdb_db - > db_id ;
c - > callid = call - > call_id ;
c - > hopcount = 0 ;
c - > keylen = call - > key . dsize ;
c - > calldatalen = call - > call_data . dsize ;
memcpy ( & c - > data [ 0 ] , call - > key . dptr , call - > key . dsize ) ;
memcpy ( & c - > data [ call - > key . dsize ] ,
call - > call_data . dptr ,
call - > call_data . dsize ) ;
* ( state - > call ) = * call ;
state - > call - > call_data . dptr = & c - > data [ call - > key . dsize ] ;
state - > call - > key . dptr = & c - > data [ 0 ] ;
2014-08-05 08:42:00 +04:00
DLIST_ADD ( ctdb_db - > pending_calls , state ) ;
2007-05-18 18:56:49 +04:00
2018-02-20 19:08:59 +03:00
talloc_set_destructor ( state , ctdb_call_destructor ) ;
2006-12-18 08:26:57 +03:00
ctdb_queue_packet ( ctdb , & state - > c - > hdr ) ;
2006-11-28 12:48:34 +03:00
2006-12-01 07:45:24 +03:00
return state ;
}
/*
2007-04-11 05:01:42 +04:00
make a remote ctdb call - async recv - called in daemon context
2006-12-18 06:49:32 +03:00
This is called when the program wants to wait for a ctdb_call to complete and get the
results . This call will block unless the call has already completed .
2006-12-01 07:45:24 +03:00
*/
2007-04-17 08:52:51 +04:00
int ctdb_daemon_call_recv ( struct ctdb_call_state * state , struct ctdb_call * call )
2006-12-01 07:45:24 +03:00
{
2007-04-05 07:18:31 +04:00
while ( state - > state < CTDB_CALL_DONE ) {
2015-10-26 08:50:09 +03:00
tevent_loop_once ( state - > ctdb_db - > ctdb - > ev ) ;
2007-04-05 07:18:31 +04:00
}
if ( state - > state ! = CTDB_CALL_DONE ) {
2007-04-28 20:55:37 +04:00
ctdb_set_error ( state - > ctdb_db - > ctdb , " %s " , state - > errmsg ) ;
2007-04-05 07:18:31 +04:00
talloc_free ( state ) ;
return - 1 ;
}
2008-03-19 05:54:17 +03:00
if ( state - > call - > reply_data . dsize ) {
2008-03-25 03:11:13 +03:00
call - > reply_data . dptr = talloc_memdup ( call ,
2008-03-19 05:54:17 +03:00
state - > call - > reply_data . dptr ,
state - > call - > reply_data . dsize ) ;
call - > reply_data . dsize = state - > call - > reply_data . dsize ;
2007-01-29 14:30:06 +03:00
} else {
call - > reply_data . dptr = NULL ;
call - > reply_data . dsize = 0 ;
}
2008-03-19 05:54:17 +03:00
call - > status = state - > call - > status ;
2006-12-01 07:45:24 +03:00
talloc_free ( state ) ;
return 0 ;
2006-11-28 09:56:10 +03:00
}
2007-04-11 05:01:42 +04:00
2011-07-20 07:49:17 +04:00
struct revokechild_deferred_call {
2017-05-18 04:50:09 +03:00
struct revokechild_deferred_call * prev , * next ;
2011-07-20 07:49:17 +04:00
struct ctdb_context * ctdb ;
struct ctdb_req_header * hdr ;
deferred_requeue_fn fn ;
void * ctx ;
2018-01-31 15:06:30 +03:00
struct revokechild_handle * rev_hdl ;
2011-07-20 07:49:17 +04:00
} ;
struct revokechild_handle {
struct revokechild_handle * next , * prev ;
struct ctdb_context * ctdb ;
struct ctdb_db_context * ctdb_db ;
2015-10-26 08:50:09 +03:00
struct tevent_fd * fde ;
2011-07-20 07:49:17 +04:00
int status ;
int fd [ 2 ] ;
pid_t child ;
TDB_DATA key ;
2017-05-18 04:50:09 +03:00
struct revokechild_deferred_call * deferred_call_list ;
2011-07-20 07:49:17 +04:00
} ;
2015-10-26 08:50:09 +03:00
static void deferred_call_requeue ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2011-07-20 07:49:17 +04:00
{
2017-05-18 04:50:09 +03:00
struct revokechild_deferred_call * dlist = talloc_get_type_abort (
private_data , struct revokechild_deferred_call ) ;
2011-07-20 07:49:17 +04:00
2017-05-18 04:50:09 +03:00
while ( dlist ! = NULL ) {
struct revokechild_deferred_call * dcall = dlist ;
2011-07-20 07:49:17 +04:00
2017-10-19 06:58:18 +03:00
talloc_set_destructor ( dcall , NULL ) ;
2017-05-18 04:50:09 +03:00
DLIST_REMOVE ( dlist , dcall ) ;
dcall - > fn ( dcall - > ctx , dcall - > hdr ) ;
talloc_free ( dcall ) ;
}
2011-07-20 07:49:17 +04:00
}
2017-10-19 06:58:18 +03:00
static int deferred_call_destructor ( struct revokechild_deferred_call * dcall )
{
2018-01-31 15:06:30 +03:00
struct revokechild_handle * rev_hdl = dcall - > rev_hdl ;
2017-10-19 06:58:18 +03:00
2018-01-31 15:06:30 +03:00
DLIST_REMOVE ( rev_hdl - > deferred_call_list , dcall ) ;
2017-10-19 06:58:18 +03:00
return 0 ;
}
2011-08-23 04:27:31 +04:00
2018-01-31 15:06:30 +03:00
static int revokechild_destructor ( struct revokechild_handle * rev_hdl )
2011-08-23 04:27:31 +04:00
{
2017-05-18 04:50:09 +03:00
struct revokechild_deferred_call * now_list = NULL ;
struct revokechild_deferred_call * delay_list = NULL ;
2018-01-31 15:06:30 +03:00
if ( rev_hdl - > fde ! = NULL ) {
talloc_free ( rev_hdl - > fde ) ;
2011-08-23 04:27:31 +04:00
}
2018-01-31 15:06:30 +03:00
if ( rev_hdl - > fd [ 0 ] ! = - 1 ) {
close ( rev_hdl - > fd [ 0 ] ) ;
2011-08-23 04:27:31 +04:00
}
2018-01-31 15:06:30 +03:00
if ( rev_hdl - > fd [ 1 ] ! = - 1 ) {
close ( rev_hdl - > fd [ 1 ] ) ;
2011-08-23 04:27:31 +04:00
}
2018-01-31 15:06:30 +03:00
ctdb_kill ( rev_hdl - > ctdb , rev_hdl - > child , SIGKILL ) ;
2011-08-23 04:27:31 +04:00
2018-01-31 15:06:30 +03:00
DLIST_REMOVE ( rev_hdl - > ctdb_db - > revokechild_active , rev_hdl ) ;
2017-05-18 04:50:09 +03:00
2018-01-31 15:06:30 +03:00
while ( rev_hdl - > deferred_call_list ! = NULL ) {
2017-05-18 04:50:09 +03:00
struct revokechild_deferred_call * dcall ;
2018-01-31 15:06:30 +03:00
dcall = rev_hdl - > deferred_call_list ;
DLIST_REMOVE ( rev_hdl - > deferred_call_list , dcall ) ;
2017-05-18 04:50:09 +03:00
/* If revoke is successful, then first process all the calls
* that need write access , and delay readonly requests by 1
* second grace .
*
* If revoke is unsuccessful , most likely because of node
* failure , delay all the pending requests , so database can
* be recovered .
*/
2018-01-31 15:06:30 +03:00
if ( rev_hdl - > status = = 0 ) {
2017-05-18 04:50:09 +03:00
struct ctdb_req_call_old * c ;
c = ( struct ctdb_req_call_old * ) dcall - > hdr ;
if ( c - > flags & CTDB_WANT_READONLY ) {
DLIST_ADD ( delay_list , dcall ) ;
} else {
DLIST_ADD ( now_list , dcall ) ;
}
} else {
DLIST_ADD ( delay_list , dcall ) ;
}
}
if ( now_list ! = NULL ) {
2018-01-31 15:06:30 +03:00
tevent_add_timer ( rev_hdl - > ctdb - > ev ,
rev_hdl - > ctdb_db ,
2017-05-18 04:50:09 +03:00
tevent_timeval_current_ofs ( 0 , 0 ) ,
2018-01-31 15:06:30 +03:00
deferred_call_requeue ,
now_list ) ;
2017-05-18 04:50:09 +03:00
}
if ( delay_list ! = NULL ) {
2018-01-31 15:06:30 +03:00
tevent_add_timer ( rev_hdl - > ctdb - > ev ,
rev_hdl - > ctdb_db ,
2017-05-18 04:50:09 +03:00
tevent_timeval_current_ofs ( 1 , 0 ) ,
2018-01-31 15:06:30 +03:00
deferred_call_requeue ,
delay_list ) ;
2017-05-18 04:50:09 +03:00
}
2011-08-23 04:27:31 +04:00
return 0 ;
}
2015-10-26 08:50:09 +03:00
static void revokechild_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * private_data )
2011-08-23 04:27:31 +04:00
{
2018-01-31 15:06:30 +03:00
struct revokechild_handle * rev_hdl =
talloc_get_type ( private_data , struct revokechild_handle ) ;
2011-08-23 04:27:31 +04:00
int ret ;
char c ;
2018-01-31 15:06:30 +03:00
ret = sys_read ( rev_hdl - > fd [ 0 ] , & c , 1 ) ;
2011-08-23 04:27:31 +04:00
if ( ret ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to read status from revokechild. errno:%d \n " , errno ) ) ;
2018-01-31 15:06:30 +03:00
rev_hdl - > status = - 1 ;
talloc_free ( rev_hdl ) ;
2011-08-23 04:27:31 +04:00
return ;
}
if ( c ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " revokechild returned failure. status:%d \n " , c ) ) ;
2018-01-31 15:06:30 +03:00
rev_hdl - > status = - 1 ;
talloc_free ( rev_hdl ) ;
2011-08-23 04:27:31 +04:00
return ;
}
2018-01-31 15:06:30 +03:00
talloc_free ( rev_hdl ) ;
2011-08-23 04:27:31 +04:00
}
struct ctdb_revoke_state {
struct ctdb_db_context * ctdb_db ;
TDB_DATA key ;
struct ctdb_ltdb_header * header ;
TDB_DATA data ;
int count ;
int status ;
int finished ;
} ;
static void update_record_cb ( struct ctdb_client_control_state * state )
{
struct ctdb_revoke_state * revoke_state ;
int ret ;
int32_t res ;
if ( state = = NULL ) {
return ;
}
revoke_state = state - > async . private_data ;
state - > async . fn = NULL ;
2011-07-20 09:13:47 +04:00
ret = ctdb_control_recv ( state - > ctdb , state , state , NULL , & res , NULL ) ;
if ( ( ret ! = 0 ) | | ( res ! = 0 ) ) {
2011-08-23 04:27:31 +04:00
DEBUG ( DEBUG_ERR , ( " Recv for revoke update record failed ret:%d res:%d \n " , ret , res ) ) ;
revoke_state - > status = - 1 ;
}
revoke_state - > count - - ;
if ( revoke_state - > count < = 0 ) {
revoke_state - > finished = 1 ;
}
}
static void revoke_send_cb ( struct ctdb_context * ctdb , uint32_t pnn , void * private_data )
{
struct ctdb_revoke_state * revoke_state = private_data ;
struct ctdb_client_control_state * state ;
2014-03-28 06:44:34 +04:00
state = ctdb_ctrl_updaterecord_send ( ctdb , revoke_state , timeval_current_ofs ( ctdb - > tunable . control_timeout , 0 ) , pnn , revoke_state - > ctdb_db , revoke_state - > key , revoke_state - > header , revoke_state - > data ) ;
2011-08-23 04:27:31 +04:00
if ( state = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failure to send update record to revoke readonly delegation \n " ) ) ;
revoke_state - > status = - 1 ;
return ;
}
state - > async . fn = update_record_cb ;
state - > async . private_data = revoke_state ;
revoke_state - > count + + ;
}
2015-10-26 08:50:09 +03:00
static void ctdb_revoke_timeout_handler ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval yt , void * private_data )
2011-08-23 04:27:31 +04:00
{
struct ctdb_revoke_state * state = private_data ;
DEBUG ( DEBUG_ERR , ( " Timed out waiting for revoke to finish \n " ) ) ;
state - > finished = 1 ;
state - > status = - 1 ;
}
static int ctdb_revoke_all_delegations ( struct ctdb_context * ctdb , struct ctdb_db_context * ctdb_db , TDB_DATA tdata , TDB_DATA key , struct ctdb_ltdb_header * header , TDB_DATA data )
{
struct ctdb_revoke_state * state = talloc_zero ( ctdb , struct ctdb_revoke_state ) ;
2014-08-12 17:54:39 +04:00
struct ctdb_ltdb_header new_header ;
TDB_DATA new_data ;
2011-08-23 04:27:31 +04:00
state - > ctdb_db = ctdb_db ;
state - > key = key ;
state - > header = header ;
state - > data = data ;
2011-07-20 09:13:47 +04:00
2011-08-23 04:27:31 +04:00
ctdb_trackingdb_traverse ( ctdb , tdata , revoke_send_cb , state ) ;
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , state ,
timeval_current_ofs ( ctdb - > tunable . control_timeout , 0 ) ,
ctdb_revoke_timeout_handler , state ) ;
2011-08-23 04:27:31 +04:00
while ( state - > finished = = 0 ) {
2015-10-26 08:50:09 +03:00
tevent_loop_once ( ctdb - > ev ) ;
2011-08-23 04:27:31 +04:00
}
2014-08-12 17:54:39 +04:00
if ( ctdb_ltdb_lock ( ctdb_db , key ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to chainlock the database in revokechild \n " ) ) ;
talloc_free ( state ) ;
return - 1 ;
}
if ( ctdb_ltdb_fetch ( ctdb_db , key , & new_header , state , & new_data ) ! = 0 ) {
2011-08-23 04:27:31 +04:00
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2014-08-12 17:54:39 +04:00
DEBUG ( DEBUG_ERR , ( " Failed for fetch tdb record in revokechild \n " ) ) ;
talloc_free ( state ) ;
return - 1 ;
}
header - > rsn + + ;
if ( new_header . rsn > header - > rsn ) {
ctdb_ltdb_unlock ( ctdb_db , key ) ;
DEBUG ( DEBUG_ERR , ( " RSN too high in tdb record in revokechild \n " ) ) ;
talloc_free ( state ) ;
return - 1 ;
}
if ( ( new_header . flags & ( CTDB_REC_RO_REVOKING_READONLY | CTDB_REC_RO_HAVE_DELEGATIONS ) ) ! = ( CTDB_REC_RO_REVOKING_READONLY | CTDB_REC_RO_HAVE_DELEGATIONS ) ) {
ctdb_ltdb_unlock ( ctdb_db , key ) ;
DEBUG ( DEBUG_ERR , ( " Flags are wrong in tdb record in revokechild \n " ) ) ;
talloc_free ( state ) ;
return - 1 ;
}
2014-08-12 17:58:00 +04:00
/*
* If revoke on all nodes succeed , revoke is complete . Otherwise ,
* remove CTDB_REC_RO_REVOKING_READONLY flag and retry .
*/
if ( state - > status = = 0 ) {
new_header . rsn + + ;
new_header . flags | = CTDB_REC_RO_REVOKE_COMPLETE ;
} else {
DEBUG ( DEBUG_NOTICE , ( " Revoke all delegations failed, retrying. \n " ) ) ;
new_header . flags & = ~ CTDB_REC_RO_REVOKING_READONLY ;
}
2014-08-12 17:54:39 +04:00
if ( ctdb_ltdb_store ( ctdb_db , key , & new_header , new_data ) ! = 0 ) {
ctdb_ltdb_unlock ( ctdb_db , key ) ;
DEBUG ( DEBUG_ERR , ( " Failed to write new record in revokechild \n " ) ) ;
talloc_free ( state ) ;
return - 1 ;
2011-08-23 04:27:31 +04:00
}
2014-08-12 17:54:39 +04:00
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2011-08-23 04:27:31 +04:00
talloc_free ( state ) ;
2014-08-12 17:58:00 +04:00
return 0 ;
2011-08-23 04:27:31 +04:00
}
2018-02-08 13:57:23 +03:00
int ctdb_start_revoke_ro_record ( struct ctdb_context * ctdb ,
struct ctdb_db_context * ctdb_db ,
TDB_DATA key ,
struct ctdb_ltdb_header * header ,
TDB_DATA data )
2011-08-23 04:27:31 +04:00
{
TDB_DATA tdata ;
2018-01-31 15:06:30 +03:00
struct revokechild_handle * rev_hdl ;
2011-08-23 04:27:31 +04:00
pid_t parent = getpid ( ) ;
int ret ;
2018-02-08 13:57:23 +03:00
header - > flags & = ~ ( CTDB_REC_RO_REVOKING_READONLY |
CTDB_REC_RO_HAVE_DELEGATIONS |
CTDB_REC_RO_HAVE_READONLY ) ;
2012-03-02 05:57:23 +04:00
header - > flags | = CTDB_REC_FLAG_MIGRATED_WITH_DATA ;
2011-08-23 04:27:31 +04:00
header - > rsn - = 1 ;
2018-02-08 13:57:23 +03:00
rev_hdl = talloc_zero ( ctdb_db , struct revokechild_handle ) ;
if ( rev_hdl = = NULL ) {
D_ERR ( " Failed to allocate revokechild_handle \n " ) ;
2011-08-23 04:27:31 +04:00
return - 1 ;
}
tdata = tdb_fetch ( ctdb_db - > rottdb , key ) ;
if ( tdata . dsize > 0 ) {
uint8_t * tmp ;
tmp = tdata . dptr ;
2018-01-31 15:06:30 +03:00
tdata . dptr = talloc_memdup ( rev_hdl , tdata . dptr , tdata . dsize ) ;
2011-08-23 04:27:31 +04:00
free ( tmp ) ;
}
2018-01-31 15:06:30 +03:00
rev_hdl - > status = 0 ;
rev_hdl - > ctdb = ctdb ;
rev_hdl - > ctdb_db = ctdb_db ;
rev_hdl - > fd [ 0 ] = - 1 ;
rev_hdl - > fd [ 1 ] = - 1 ;
2011-08-23 04:27:31 +04:00
2018-01-31 15:06:30 +03:00
rev_hdl - > key . dsize = key . dsize ;
rev_hdl - > key . dptr = talloc_memdup ( rev_hdl , key . dptr , key . dsize ) ;
if ( rev_hdl - > key . dptr = = NULL ) {
2018-02-08 13:57:23 +03:00
D_ERR ( " Failed to allocate key for revokechild_handle \n " ) ;
2018-02-08 14:08:45 +03:00
goto err_out ;
2011-08-23 04:27:31 +04:00
}
2018-01-31 15:06:30 +03:00
ret = pipe ( rev_hdl - > fd ) ;
2011-08-23 04:27:31 +04:00
if ( ret ! = 0 ) {
2018-02-08 13:57:23 +03:00
D_ERR ( " Failed to allocate key for revokechild_handle \n " ) ;
2018-02-08 14:08:45 +03:00
goto err_out ;
2011-08-23 04:27:31 +04:00
}
2018-01-31 15:06:30 +03:00
rev_hdl - > child = ctdb_fork ( ctdb ) ;
if ( rev_hdl - > child = = ( pid_t ) - 1 ) {
2018-02-08 13:57:23 +03:00
D_ERR ( " Failed to fork child for revokechild \n " ) ;
2018-02-08 14:08:45 +03:00
goto err_out ;
2011-08-23 04:27:31 +04:00
}
2018-01-31 15:06:30 +03:00
if ( rev_hdl - > child = = 0 ) {
2011-08-23 04:27:31 +04:00
char c = 0 ;
2018-01-31 15:06:30 +03:00
close ( rev_hdl - > fd [ 0 ] ) ;
2011-08-23 04:27:31 +04:00
2015-09-24 02:10:59 +03:00
prctl_set_comment ( " ctdb_revokechild " ) ;
2016-11-25 06:44:10 +03:00
if ( switch_from_server_to_client ( ctdb ) ! = 0 ) {
2018-02-08 13:57:23 +03:00
D_ERR ( " Failed to switch from server to client "
" for revokechild process \n " ) ;
2011-08-23 04:27:31 +04:00
c = 1 ;
goto child_finished ;
}
2018-02-08 13:57:23 +03:00
c = ctdb_revoke_all_delegations ( ctdb ,
ctdb_db ,
tdata ,
key ,
header ,
data ) ;
2011-08-23 04:27:31 +04:00
child_finished :
2018-01-31 15:06:30 +03:00
sys_write ( rev_hdl - > fd [ 1 ] , & c , 1 ) ;
2015-12-08 06:20:59 +03:00
ctdb_wait_for_process_to_exit ( parent ) ;
2011-08-23 04:27:31 +04:00
_exit ( 0 ) ;
}
2018-01-31 15:06:30 +03:00
close ( rev_hdl - > fd [ 1 ] ) ;
rev_hdl - > fd [ 1 ] = - 1 ;
set_close_on_exec ( rev_hdl - > fd [ 0 ] ) ;
2011-08-23 04:27:31 +04:00
2018-01-31 15:06:30 +03:00
rev_hdl - > fde = tevent_add_fd ( ctdb - > ev ,
rev_hdl ,
rev_hdl - > fd [ 0 ] ,
TEVENT_FD_READ ,
revokechild_handler ,
( void * ) rev_hdl ) ;
if ( rev_hdl - > fde = = NULL ) {
2018-02-08 13:57:23 +03:00
D_ERR ( " Failed to set up fd event for revokechild process \n " ) ;
2018-01-31 15:06:30 +03:00
talloc_free ( rev_hdl ) ;
2011-08-23 04:27:31 +04:00
}
2018-01-31 15:06:30 +03:00
tevent_fd_set_auto_close ( rev_hdl - > fde ) ;
2011-08-23 04:27:31 +04:00
2018-02-08 14:19:09 +03:00
/* This is an active revokechild child process */
DLIST_ADD_END ( ctdb_db - > revokechild_active , rev_hdl ) ;
talloc_set_destructor ( rev_hdl , revokechild_destructor ) ;
2011-08-23 04:27:31 +04:00
return 0 ;
2018-02-08 14:08:45 +03:00
err_out :
talloc_free ( rev_hdl ) ;
return - 1 ;
2011-08-23 04:27:31 +04:00
}
2011-07-20 07:49:17 +04:00
int ctdb_add_revoke_deferred_call ( struct ctdb_context * ctdb , struct ctdb_db_context * ctdb_db , TDB_DATA key , struct ctdb_req_header * hdr , deferred_requeue_fn fn , void * call_context )
{
2018-01-31 15:06:30 +03:00
struct revokechild_handle * rev_hdl ;
2011-07-20 07:49:17 +04:00
struct revokechild_deferred_call * deferred_call ;
2018-01-31 15:06:30 +03:00
for ( rev_hdl = ctdb_db - > revokechild_active ;
rev_hdl ;
rev_hdl = rev_hdl - > next ) {
if ( rev_hdl - > key . dsize = = 0 ) {
2011-07-20 07:49:17 +04:00
continue ;
}
2018-01-31 15:06:30 +03:00
if ( rev_hdl - > key . dsize ! = key . dsize ) {
2011-07-20 07:49:17 +04:00
continue ;
}
2018-01-31 15:06:30 +03:00
if ( ! memcmp ( rev_hdl - > key . dptr , key . dptr , key . dsize ) ) {
2011-07-20 07:49:17 +04:00
break ;
}
}
2018-01-31 15:06:30 +03:00
if ( rev_hdl = = NULL ) {
2011-07-20 07:49:17 +04:00
DEBUG ( DEBUG_ERR , ( " Failed to add deferred call to revoke list. revoke structure not found \n " ) ) ;
return - 1 ;
}
2017-10-19 06:58:18 +03:00
deferred_call = talloc ( call_context , struct revokechild_deferred_call ) ;
2011-07-20 07:49:17 +04:00
if ( deferred_call = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate deferred call structure for revoking record \n " ) ) ;
return - 1 ;
}
deferred_call - > ctdb = ctdb ;
2017-05-18 04:50:09 +03:00
deferred_call - > hdr = talloc_steal ( deferred_call , hdr ) ;
2011-07-20 07:49:17 +04:00
deferred_call - > fn = fn ;
deferred_call - > ctx = call_context ;
2018-01-31 15:06:30 +03:00
deferred_call - > rev_hdl = rev_hdl ;
2017-10-19 06:58:18 +03:00
talloc_set_destructor ( deferred_call , deferred_call_destructor ) ;
2011-07-20 07:49:17 +04:00
2018-01-31 15:06:30 +03:00
DLIST_ADD ( rev_hdl - > deferred_call_list , deferred_call ) ;
2011-07-20 07:49:17 +04:00
return 0 ;
}
2017-03-21 08:48:45 +03:00
static void ctdb_migration_count_handler ( TDB_DATA key , uint64_t counter ,
void * private_data )
{
struct ctdb_db_context * ctdb_db = talloc_get_type_abort (
private_data , struct ctdb_db_context ) ;
2019-08-01 03:55:39 +03:00
unsigned int value ;
2017-03-21 08:48:45 +03:00
value = ( counter < INT_MAX ? counter : INT_MAX ) ;
ctdb_update_db_stat_hot_keys ( ctdb_db , key , value ) ;
}
static void ctdb_migration_cleandb_event ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval current_time ,
void * private_data )
{
struct ctdb_db_context * ctdb_db = talloc_get_type_abort (
private_data , struct ctdb_db_context ) ;
if ( ctdb_db - > migratedb = = NULL ) {
return ;
}
hash_count_expire ( ctdb_db - > migratedb , NULL ) ;
te = tevent_add_timer ( ctdb_db - > ctdb - > ev , ctdb_db - > migratedb ,
tevent_timeval_current_ofs ( 10 , 0 ) ,
ctdb_migration_cleandb_event , ctdb_db ) ;
if ( te = = NULL ) {
DEBUG ( DEBUG_ERR ,
( " Memory error in migration cleandb event for %s \n " ,
ctdb_db - > db_name ) ) ;
TALLOC_FREE ( ctdb_db - > migratedb ) ;
}
}
int ctdb_migration_init ( struct ctdb_db_context * ctdb_db )
{
struct timeval one_second = { 1 , 0 } ;
struct tevent_timer * te ;
int ret ;
2017-03-02 07:39:29 +03:00
if ( ! ctdb_db_volatile ( ctdb_db ) ) {
2017-03-21 08:48:45 +03:00
return 0 ;
}
ret = hash_count_init ( ctdb_db , one_second ,
ctdb_migration_count_handler , ctdb_db ,
& ctdb_db - > migratedb ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( " Memory error in migration init for %s \n " ,
ctdb_db - > db_name ) ) ;
return - 1 ;
}
te = tevent_add_timer ( ctdb_db - > ctdb - > ev , ctdb_db - > migratedb ,
tevent_timeval_current_ofs ( 10 , 0 ) ,
ctdb_migration_cleandb_event , ctdb_db ) ;
if ( te = = NULL ) {
DEBUG ( DEBUG_ERR ,
( " Memory error in migration init for %s \n " ,
ctdb_db - > db_name ) ) ;
TALLOC_FREE ( ctdb_db - > migratedb ) ;
return - 1 ;
}
return 0 ;
}