2007-04-17 01:41:27 +04:00
/*
wait for a tdb chain lock
Copyright ( C ) Andrew Tridgell 2006
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "includes.h"
# include "lib/events/events.h"
# include "system/filesys.h"
# include "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 ) ;
talloc_free ( fde ) ;
key . dptr = talloc_memdup ( tmp_ctx , key . dptr , key . dsize ) ;
2007-04-17 01:41:27 +04:00
talloc_set_destructor ( h , NULL ) ;
2007-04-20 15:02:53 +04:00
ctdb_latency ( & h - > ctdb - > status . max_lockwait_latency , h - > start_time ) ;
2007-04-20 14:07:47 +04:00
h - > ctdb - > status . pending_lockwait_calls - - ;
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 ) ;
2007-04-17 03:10:52 +04:00
waitpid ( child , NULL , 0 ) ;
2007-05-05 11:19:59 +04:00
talloc_free ( tmp_ctx ) ;
2007-04-17 01:41:27 +04:00
}
static int lockwait_destructor ( struct lockwait_handle * h )
{
2007-04-20 14:07:47 +04:00
h - > ctdb - > status . pending_lockwait_calls - - ;
2007-04-17 01:41:27 +04:00
kill ( h - > child , SIGKILL ) ;
waitpid ( h - > child , NULL , 0 ) ;
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-04-20 14:07:47 +04:00
ctdb_db - > ctdb - > status . lockwait_calls + + ;
ctdb_db - > ctdb - > status . pending_lockwait_calls + + ;
2007-05-05 11:19:59 +04:00
if ( ! ( result = talloc_zero ( private_data , struct lockwait_handle ) ) ) {
2007-04-20 14:07:47 +04:00
ctdb_db - > ctdb - > status . 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 ) ;
2007-04-20 14:07:47 +04:00
ctdb_db - > ctdb - > status . 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 ) ;
2007-04-20 14:07:47 +04:00
ctdb_db - > ctdb - > status . 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 ] ) ;
tdb_chainlock ( ctdb_db - > ltdb - > tdb , key ) ;
2007-05-05 11:19:59 +04:00
write ( result - > fd [ 1 ] , & c , 1 ) ;
2007-05-14 07:49:01 +04:00
/* this read will exit when the parent closes its end
of the pipe , or the parent dies */
read ( result - > fd [ 1 ] , & c , 1 ) ;
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 ] ) ;
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 ] ,
2007-05-05 11:19:59 +04:00
EVENT_FD_READ | EVENT_FD_AUTOCLOSE , lockwait_handler ,
2007-04-17 05:26:59 +04:00
( void * ) result ) ;
if ( result - > fde = = NULL ) {
talloc_free ( result ) ;
2007-04-20 14:07:47 +04:00
ctdb_db - > ctdb - > status . pending_lockwait_calls - - ;
2007-04-17 01:41:27 +04:00
return NULL ;
}
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
}