2007-04-17 01:41:27 +04:00
/*
wait for a tdb chain lock
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 ,
2007-04-17 01:41:27 +04: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/>.
2007-04-17 01:41:27 +04:00
*/
# include "includes.h"
2010-08-18 03:46:31 +04:00
# include "lib/tevent/tevent.h"
2007-04-17 01:41:27 +04:00
# include "system/filesys.h"
# include "system/wait.h"
# include "db_wrap.h"
# include "lib/tdb/include/tdb.h"
2007-04-21 07:08:22 +04:00
# include "../include/ctdb_private.h"
2007-04-17 01:41:27 +04:00
struct lockwait_handle {
2007-04-20 14:07:47 +04:00
struct ctdb_context * ctdb ;
2007-05-05 11:19:59 +04:00
struct ctdb_db_context * ctdb_db ;
2007-04-17 01:41:27 +04:00
struct fd_event * fde ;
int fd [ 2 ] ;
pid_t child ;
void * private_data ;
void ( * callback ) ( void * ) ;
2007-05-05 11:19:59 +04:00
TDB_DATA key ;
2007-04-20 15:02:53 +04:00
struct timeval start_time ;
2007-04-17 01:41:27 +04:00
} ;
static void lockwait_handler ( struct event_context * ev , struct fd_event * fde ,
uint16_t flags , void * private_data )
{
struct lockwait_handle * h = talloc_get_type ( private_data ,
struct lockwait_handle ) ;
void ( * callback ) ( void * ) = h - > callback ;
void * p = h - > private_data ;
2007-04-17 03:10:52 +04:00
pid_t child = h - > child ;
2007-05-05 11:19:59 +04:00
TDB_DATA key = h - > key ;
struct tdb_context * tdb = h - > ctdb_db - > ltdb - > tdb ;
TALLOC_CTX * tmp_ctx = talloc_new ( ev ) ;
key . dptr = talloc_memdup ( tmp_ctx , key . dptr , key . dsize ) ;
2007-04-17 01:41:27 +04:00
talloc_set_destructor ( h , NULL ) ;
2010-09-29 04:38:41 +04:00
CTDB_UPDATE_LATENCY ( h - > ctdb , h - > ctdb_db , " lockwait " , max_lockwait_latency , h - > start_time ) ;
CTDB_DECREMENT_STAT ( h - > ctdb , pending_lockwait_calls ) ;
2007-05-05 11:19:59 +04:00
2007-05-15 03:44:03 +04:00
/* the handle needs to go away when the context is gone - when
the handle goes away this implicitly closes the pipe , which
2007-05-14 08:01:33 +04:00
kills the child holding the lock */
2007-05-15 03:44:03 +04:00
talloc_steal ( tmp_ctx , h ) ;
if ( h - > ctdb - > flags & CTDB_FLAG_TORTURE ) {
if ( tdb_chainlock_nonblock ( tdb , key ) = = 0 ) {
ctdb_fatal ( h - > ctdb , " got chain lock while lockwait child active " ) ;
}
}
2007-05-14 08:01:33 +04:00
2007-05-05 11:19:59 +04:00
tdb_chainlock_mark ( tdb , key ) ;
2007-04-17 01:41:27 +04:00
callback ( p ) ;
2007-05-05 11:19:59 +04:00
tdb_chainlock_unmark ( tdb , key ) ;
kill ( child , SIGKILL ) ;
talloc_free ( tmp_ctx ) ;
2007-04-17 01:41:27 +04:00
}
static int lockwait_destructor ( struct lockwait_handle * h )
{
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( h - > ctdb , pending_lockwait_calls ) ;
2007-04-17 01:41:27 +04:00
kill ( h - > child , SIGKILL ) ;
return 0 ;
}
2007-04-17 03:14:52 +04:00
/*
setup a non - blocking chainlock on a tdb record . If this function
returns NULL then it could not get the chainlock . Otherwise it
returns a opaque handle , and will call callback ( ) once it has
managed to get the chainlock . You can cancel it by using talloc_free
on the returned handle .
It is the callers responsibility to unlock the chainlock once
acquired
*/
2007-04-17 01:41:27 +04:00
struct lockwait_handle * ctdb_lockwait ( struct ctdb_db_context * ctdb_db ,
TDB_DATA key ,
2007-04-17 05:26:59 +04:00
void ( * callback ) ( void * private_data ) ,
void * private_data )
2007-04-17 01:41:27 +04:00
{
2007-04-17 05:26:59 +04:00
struct lockwait_handle * result ;
2007-04-17 01:41:27 +04:00
int ret ;
2007-05-15 03:44:03 +04:00
pid_t parent = getpid ( ) ;
2007-04-17 01:41:27 +04:00
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( ctdb_db - > ctdb , lockwait_calls ) ;
CTDB_INCREMENT_STAT ( ctdb_db - > ctdb , pending_lockwait_calls ) ;
2007-04-20 14:07:47 +04:00
2007-05-05 11:19:59 +04:00
if ( ! ( result = talloc_zero ( private_data , struct lockwait_handle ) ) ) {
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb_db - > ctdb , pending_lockwait_calls ) ;
2007-04-17 01:41:27 +04:00
return NULL ;
}
2007-04-17 05:26:59 +04:00
ret = pipe ( result - > fd ) ;
2007-04-17 01:41:27 +04:00
if ( ret ! = 0 ) {
2007-04-17 05:26:59 +04:00
talloc_free ( result ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb_db - > ctdb , pending_lockwait_calls ) ;
2007-04-17 01:41:27 +04:00
return NULL ;
}
2007-04-17 05:26:59 +04:00
result - > child = fork ( ) ;
if ( result - > child = = ( pid_t ) - 1 ) {
close ( result - > fd [ 0 ] ) ;
close ( result - > fd [ 1 ] ) ;
talloc_free ( result ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb_db - > ctdb , pending_lockwait_calls ) ;
2007-04-17 01:41:27 +04:00
return NULL ;
}
2007-04-17 05:26:59 +04:00
result - > callback = callback ;
result - > private_data = private_data ;
2007-04-20 14:07:47 +04:00
result - > ctdb = ctdb_db - > ctdb ;
2007-05-05 11:19:59 +04:00
result - > ctdb_db = ctdb_db ;
result - > key = key ;
2007-04-17 01:41:27 +04:00
2007-04-17 05:26:59 +04:00
if ( result - > child = = 0 ) {
2007-05-05 11:19:59 +04:00
char c = 0 ;
2007-04-17 05:26:59 +04:00
close ( result - > fd [ 0 ] ) ;
2010-07-19 13:59:09 +04:00
debug_extra = talloc_asprintf ( NULL , " chainlock-%s: " , ctdb_db - > db_name ) ;
2007-04-17 05:26:59 +04:00
tdb_chainlock ( ctdb_db - > ltdb - > tdb , key ) ;
2007-05-05 11:19:59 +04:00
write ( result - > fd [ 1 ] , & c , 1 ) ;
2007-05-15 03:44:03 +04:00
/* make sure we die when our parent dies */
while ( kill ( parent , 0 ) = = 0 | | errno ! = ESRCH ) {
sleep ( 5 ) ;
}
2007-04-20 11:58:37 +04:00
_exit ( 0 ) ;
2007-04-17 01:41:27 +04:00
}
2007-04-17 05:26:59 +04:00
close ( result - > fd [ 1 ] ) ;
2009-10-15 04:24:54 +04:00
set_close_on_exec ( result - > fd [ 0 ] ) ;
2010-02-03 22:37:41 +03:00
DEBUG ( DEBUG_DEBUG , ( __location__ " Created PIPE FD:%d to child lockwait process \n " , result - > fd [ 0 ] ) ) ;
2009-10-15 04:24:54 +04:00
2007-04-17 05:26:59 +04:00
talloc_set_destructor ( result , lockwait_destructor ) ;
2007-04-17 01:41:27 +04:00
2007-04-17 05:26:59 +04:00
result - > fde = event_add_fd ( ctdb_db - > ctdb - > ev , result , result - > fd [ 0 ] ,
2010-08-18 03:46:31 +04:00
EVENT_FD_READ , lockwait_handler ,
2007-04-17 05:26:59 +04:00
( void * ) result ) ;
if ( result - > fde = = NULL ) {
talloc_free ( result ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb_db - > ctdb , pending_lockwait_calls ) ;
2007-04-17 01:41:27 +04:00
return NULL ;
}
2010-08-18 03:46:31 +04:00
tevent_fd_set_auto_close ( result - > fde ) ;
2007-04-17 01:41:27 +04:00
2007-04-20 15:02:53 +04:00
result - > start_time = timeval_current ( ) ;
2007-04-20 11:58:37 +04:00
2007-04-17 05:26:59 +04:00
return result ;
2007-04-17 01:41:27 +04:00
}