2006-11-28 09:56:10 +03:00
/*
ctdb ltdb code
Copyright ( C ) Andrew Tridgell 2006
2011-07-20 05:39:50 +04:00
Copyright ( C ) Ronnie sahlberg 2011
2006-11-28 09:56:10 +03:00
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
*/
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 <tdb.h>
2014-08-15 09:46:33 +04:00
# include "lib/tdb_wrap/tdb_wrap.h"
2007-04-04 09:02:49 +04:00
# include "lib/util/dlinklist.h"
2015-10-26 08:50:46 +03:00
# include "lib/util/debug.h"
# include "ctdb_private.h"
2007-01-25 07:10:40 +03:00
2015-10-23 06:17:34 +03:00
# include "common/common.h"
2015-11-11 07:19:17 +03:00
# include "common/logging.h"
2015-10-23 06:17:34 +03:00
2017-03-21 05:50:07 +03:00
/*
* Calculate tdb flags based on databse type
*/
int ctdb_db_tdb_flags ( uint8_t db_flags , bool with_valgrind , bool with_mutex )
{
int tdb_flags = 0 ;
if ( db_flags & CTDB_DB_FLAGS_PERSISTENT ) {
tdb_flags = TDB_DEFAULT ;
2017-05-01 17:59:46 +03:00
} else if ( db_flags & CTDB_DB_FLAGS_REPLICATED ) {
tdb_flags = TDB_NOSYNC |
TDB_CLEAR_IF_FIRST |
TDB_INCOMPATIBLE_HASH ;
2017-03-21 05:50:07 +03:00
} else {
tdb_flags = TDB_NOSYNC |
TDB_CLEAR_IF_FIRST |
TDB_INCOMPATIBLE_HASH ;
# ifdef TDB_MUTEX_LOCKING
if ( with_mutex & & tdb_runtime_check_for_robust_mutexes ( ) ) {
tdb_flags | = TDB_MUTEX_LOCKING ;
}
# endif
}
tdb_flags | = TDB_DISALLOW_NESTING ;
if ( with_valgrind ) {
tdb_flags | = TDB_NOMMAP ;
}
return tdb_flags ;
}
2007-04-04 09:02:49 +04:00
/*
find an attached ctdb_db handle given a name
*/
struct ctdb_db_context * ctdb_db_handle ( struct ctdb_context * ctdb , const char * name )
{
struct ctdb_db_context * tmp_db ;
for ( tmp_db = ctdb - > db_list ; tmp_db ; tmp_db = tmp_db - > next ) {
if ( strcmp ( name , tmp_db - > db_name ) = = 0 ) {
return tmp_db ;
}
}
return NULL ;
}
2006-11-28 09:56:10 +03:00
2017-03-02 07:39:29 +03:00
bool ctdb_db_persistent ( struct ctdb_db_context * ctdb_db )
{
2017-03-02 07:53:17 +03:00
if ( ctdb_db - > db_flags & CTDB_DB_FLAGS_PERSISTENT ) {
return true ;
}
return false ;
2017-03-02 07:39:29 +03:00
}
2017-03-02 08:36:55 +03:00
bool ctdb_db_replicated ( struct ctdb_db_context * ctdb_db )
{
if ( ctdb_db - > db_flags & CTDB_DB_FLAGS_REPLICATED ) {
return true ;
}
return false ;
}
2017-03-02 07:39:29 +03:00
bool ctdb_db_volatile ( struct ctdb_db_context * ctdb_db )
{
2017-03-02 08:36:55 +03:00
if ( ( ctdb_db - > db_flags & CTDB_DB_FLAGS_PERSISTENT ) | |
( ctdb_db - > db_flags & CTDB_DB_FLAGS_REPLICATED ) ) {
2017-03-02 07:53:17 +03:00
return false ;
}
return true ;
2017-03-02 07:39:29 +03:00
}
2007-04-04 15:15:56 +04:00
2017-03-02 07:44:48 +03:00
bool ctdb_db_readonly ( struct ctdb_db_context * ctdb_db )
{
2017-03-02 07:53:17 +03:00
if ( ctdb_db - > db_flags & CTDB_DB_FLAGS_READONLY ) {
return true ;
}
return false ;
2017-03-02 07:44:48 +03:00
}
void ctdb_db_set_readonly ( struct ctdb_db_context * ctdb_db )
{
2017-03-02 07:53:17 +03:00
ctdb_db - > db_flags | = CTDB_DB_FLAGS_READONLY ;
2017-03-02 07:44:48 +03:00
}
void ctdb_db_reset_readonly ( struct ctdb_db_context * ctdb_db )
{
2017-03-02 07:53:17 +03:00
ctdb_db - > db_flags & = ~ CTDB_DB_FLAGS_READONLY ;
2017-03-02 07:44:48 +03:00
}
2017-03-02 07:47:46 +03:00
bool ctdb_db_sticky ( struct ctdb_db_context * ctdb_db )
{
2017-03-02 07:53:17 +03:00
if ( ctdb_db - > db_flags & CTDB_DB_FLAGS_STICKY ) {
return true ;
}
return false ;
2017-03-02 07:47:46 +03:00
}
void ctdb_db_set_sticky ( struct ctdb_db_context * ctdb_db )
{
2017-03-02 07:53:17 +03:00
ctdb_db - > db_flags | = CTDB_DB_FLAGS_STICKY ;
2017-03-02 07:47:46 +03:00
}
2006-12-18 06:44:06 +03:00
/*
return the lmaster given a key
*/
2006-12-18 08:01:11 +03:00
uint32_t ctdb_lmaster ( struct ctdb_context * ctdb , const TDB_DATA * key )
2006-12-18 06:44:06 +03:00
{
2007-04-27 12:43:52 +04:00
uint32_t idx , lmaster ;
idx = ctdb_hash ( key ) % ctdb - > vnn_map - > size ;
lmaster = ctdb - > vnn_map - > map [ idx ] ;
return lmaster ;
2006-12-18 06:44:06 +03:00
}
2006-12-18 05:24:02 +03:00
/*
construct an initial header for a record with no ltdb header yet
*/
2007-04-03 13:41:00 +04:00
static void ltdb_initial_header ( struct ctdb_db_context * ctdb_db ,
2006-12-18 05:24:02 +03:00
TDB_DATA key ,
struct ctdb_ltdb_header * header )
{
2008-07-04 11:40:25 +04:00
ZERO_STRUCTP ( header ) ;
2006-12-18 06:05:49 +03:00
/* initial dmaster is the lmaster */
2007-04-03 13:41:00 +04:00
header - > dmaster = ctdb_lmaster ( ctdb_db - > ctdb , & key ) ;
2011-02-03 18:30:52 +03:00
header - > flags = CTDB_REC_FLAG_AUTOMATIC ;
2006-12-18 05:24:02 +03:00
}
/*
fetch a record from the ltdb , separating out the header information
and returning the body of the record . A valid ( initial ) header is
returned if the record is not present
*/
2007-04-03 13:41:00 +04:00
int ctdb_ltdb_fetch ( struct ctdb_db_context * ctdb_db ,
2007-04-07 04:45:00 +04:00
TDB_DATA key , struct ctdb_ltdb_header * header ,
TALLOC_CTX * mem_ctx , TDB_DATA * data )
2006-12-18 05:24:02 +03:00
{
TDB_DATA rec ;
2007-04-03 13:41:00 +04:00
struct ctdb_context * ctdb = ctdb_db - > ctdb ;
2006-12-18 05:24:02 +03:00
2007-04-03 13:41:00 +04:00
rec = tdb_fetch ( ctdb_db - > ltdb - > tdb , key ) ;
2006-12-18 05:24:02 +03:00
if ( rec . dsize < sizeof ( * header ) ) {
/* return an initial header */
2007-04-19 12:31:49 +04:00
if ( rec . dptr ) free ( rec . dptr ) ;
2007-06-02 07:16:11 +04:00
if ( ctdb - > vnn_map = = NULL ) {
/* called from the client */
ZERO_STRUCTP ( data ) ;
header - > dmaster = ( uint32_t ) - 1 ;
return - 1 ;
}
2007-04-03 13:41:00 +04:00
ltdb_initial_header ( ctdb_db , key , header ) ;
2007-04-04 15:15:56 +04:00
if ( data ) {
2014-07-14 10:30:18 +04:00
* data = tdb_null ;
2007-04-04 15:15:56 +04:00
}
2017-03-02 07:39:29 +03:00
if ( ctdb_db_persistent ( ctdb_db ) | |
header - > dmaster = = ctdb_db - > ctdb - > pnn ) {
2014-07-14 10:30:18 +04:00
if ( ctdb_ltdb_store ( ctdb_db , key , header , tdb_null ) ! = 0 ) {
2013-11-11 05:40:28 +04:00
DEBUG ( DEBUG_NOTICE ,
( __location__ " failed to store initial header \n " ) ) ;
}
2013-08-09 11:22:55 +04:00
}
2006-12-18 05:24:02 +03:00
return 0 ;
}
* header = * ( struct ctdb_ltdb_header * ) rec . dptr ;
2007-04-04 15:15:56 +04:00
if ( data ) {
data - > dsize = rec . dsize - sizeof ( struct ctdb_ltdb_header ) ;
2007-04-07 04:45:00 +04:00
data - > dptr = talloc_memdup ( mem_ctx ,
sizeof ( struct ctdb_ltdb_header ) + rec . dptr ,
2007-04-04 15:15:56 +04:00
data - > dsize ) ;
}
2006-12-20 02:32:31 +03:00
free ( rec . dptr ) ;
2007-04-04 15:15:56 +04:00
if ( data ) {
CTDB_NO_MEMORY ( ctdb , data - > dptr ) ;
}
2006-12-18 05:24:02 +03:00
return 0 ;
}
2011-07-20 09:31:44 +04:00
/*
fetch a record from the ltdb , separating out the header information
and returning the body of the record .
if the record does not exist , * header will be NULL
and data = { 0 , NULL }
*/
2011-09-13 12:38:20 +04:00
int ctdb_ltdb_fetch_with_header ( struct ctdb_db_context * ctdb_db ,
2011-07-20 09:31:44 +04:00
TDB_DATA key , struct ctdb_ltdb_header * header ,
TALLOC_CTX * mem_ctx , TDB_DATA * data )
{
TDB_DATA rec ;
rec = tdb_fetch ( ctdb_db - > ltdb - > tdb , key ) ;
if ( rec . dsize < sizeof ( * header ) ) {
free ( rec . dptr ) ;
data - > dsize = 0 ;
data - > dptr = NULL ;
return - 1 ;
}
* header = * ( struct ctdb_ltdb_header * ) rec . dptr ;
if ( data ) {
data - > dsize = rec . dsize - sizeof ( struct ctdb_ltdb_header ) ;
data - > dptr = talloc_memdup ( mem_ctx ,
sizeof ( struct ctdb_ltdb_header ) + rec . dptr ,
data - > dsize ) ;
}
free ( rec . dptr ) ;
return 0 ;
}
2006-12-18 05:24:02 +03:00
/*
2008-05-22 06:47:33 +04:00
write a record to a normal database
2006-12-18 05:24:02 +03:00
*/
2007-04-03 13:41:00 +04:00
int ctdb_ltdb_store ( struct ctdb_db_context * ctdb_db , TDB_DATA key ,
2006-12-18 05:24:02 +03:00
struct ctdb_ltdb_header * header , TDB_DATA data )
{
2007-04-03 13:41:00 +04:00
struct ctdb_context * ctdb = ctdb_db - > ctdb ;
2016-09-02 10:22:26 +03:00
TDB_DATA rec [ 2 ] ;
2016-09-02 10:11:17 +03:00
uint32_t hsize = sizeof ( struct ctdb_ltdb_header ) ;
2006-12-18 05:24:02 +03:00
int ret ;
2010-02-12 09:32:56 +03:00
bool seqnum_suppressed = false ;
2006-12-18 05:24:02 +03:00
2010-12-30 20:19:32 +03:00
if ( ctdb_db - > ctdb_ltdb_store_fn ) {
return ctdb_db - > ctdb_ltdb_store_fn ( ctdb_db , key , header , data ) ;
}
2007-05-11 04:33:43 +04:00
if ( ctdb - > flags & CTDB_FLAG_TORTURE ) {
2016-09-02 10:11:17 +03:00
TDB_DATA old ;
2007-05-11 04:33:43 +04:00
struct ctdb_ltdb_header * h2 ;
2016-09-02 10:11:17 +03:00
old = tdb_fetch ( ctdb_db - > ltdb - > tdb , key ) ;
h2 = ( struct ctdb_ltdb_header * ) old . dptr ;
if ( old . dptr ! = NULL & & old . dsize > = hsize & &
h2 - > rsn > header - > rsn ) {
DEBUG ( DEBUG_ERR ,
( " RSN regression! % " PRIu64 " % " PRIu64 " \n " ,
h2 - > rsn , header - > rsn ) ) ;
}
if ( old . dptr ! = NULL ) {
free ( old . dptr ) ;
2007-05-11 04:33:43 +04:00
}
}
2016-09-02 10:22:26 +03:00
rec [ 0 ] . dsize = hsize ;
rec [ 0 ] . dptr = ( uint8_t * ) header ;
2006-12-18 05:24:02 +03:00
2016-09-02 10:22:26 +03:00
rec [ 1 ] . dsize = data . dsize ;
rec [ 1 ] . dptr = data . dptr ;
2007-01-25 07:10:40 +03:00
2010-02-12 09:32:56 +03:00
/* Databases with seqnum updates enabled only get their seqnum
changes when / if we modify the data */
if ( ctdb_db - > seqnum_update ! = NULL ) {
TDB_DATA old ;
old = tdb_fetch ( ctdb_db - > ltdb - > tdb , key ) ;
2016-09-02 10:11:17 +03:00
if ( ( old . dsize = = hsize + data . dsize ) & &
memcmp ( old . dptr + hsize , data . dptr , data . dsize ) = = 0 ) {
2010-02-12 09:32:56 +03:00
tdb_remove_flags ( ctdb_db - > ltdb - > tdb , TDB_SEQNUM ) ;
seqnum_suppressed = true ;
}
2016-09-02 10:11:17 +03:00
if ( old . dptr ! = NULL ) {
free ( old . dptr ) ;
}
2010-02-12 09:32:56 +03:00
}
2016-09-02 10:22:26 +03:00
ret = tdb_storev ( ctdb_db - > ltdb - > tdb , key , rec , 2 , TDB_REPLACE ) ;
2008-05-22 06:47:33 +04:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to store dynamic data \n " ) ) ;
}
2010-02-12 09:32:56 +03:00
if ( seqnum_suppressed ) {
tdb_add_flags ( ctdb_db - > ltdb - > tdb , TDB_SEQNUM ) ;
}
2008-05-22 06:47:33 +04:00
return ret ;
}
2007-04-11 05:01:42 +04:00
/*
lock a record in the ltdb , given a key
*/
int ctdb_ltdb_lock ( struct ctdb_db_context * ctdb_db , TDB_DATA key )
{
return tdb_chainlock ( ctdb_db - > ltdb - > tdb , key ) ;
}
/*
unlock a record in the ltdb , given a key
*/
int ctdb_ltdb_unlock ( struct ctdb_db_context * ctdb_db , TDB_DATA key )
{
2007-04-22 20:19:49 +04:00
int ret = tdb_chainunlock ( ctdb_db - > ltdb - > tdb , key ) ;
if ( ret ! = 0 ) {
2010-06-09 07:54:10 +04:00
DEBUG ( DEBUG_ERR , ( " tdb_chainunlock failed on db %s [%s] \n " , ctdb_db - > db_name , tdb_errorstr ( ctdb_db - > ltdb - > tdb ) ) ) ;
2007-04-22 20:19:49 +04:00
}
return ret ;
2007-04-11 05:01:42 +04:00
}
2010-12-06 08:06:20 +03:00
/*
delete a record from a normal database
*/
int ctdb_ltdb_delete ( struct ctdb_db_context * ctdb_db , TDB_DATA key )
{
2017-03-02 07:39:29 +03:00
if ( ! ctdb_db_volatile ( ctdb_db ) ) {
DEBUG ( DEBUG_WARNING ,
( " Ignored deletion of empty record from "
" non-volatile database \n " ) ) ;
2010-12-06 08:06:20 +03:00
return 0 ;
}
if ( tdb_delete ( ctdb_db - > ltdb - > tdb , key ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to delete empty record. " ) ) ;
return - 1 ;
}
return 0 ;
}
2011-07-20 05:39:50 +04:00
int ctdb_trackingdb_add_pnn ( struct ctdb_context * ctdb , TDB_DATA * data , uint32_t pnn )
{
int byte_pos = pnn / 8 ;
int bit_mask = 1 < < ( pnn % 8 ) ;
if ( byte_pos + 1 > data - > dsize ) {
char * buf ;
buf = malloc ( byte_pos + 1 ) ;
memset ( buf , 0 , byte_pos + 1 ) ;
if ( buf = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Out of memory when allocating buffer of %d bytes for trackingdb \n " , byte_pos + 1 ) ) ;
return - 1 ;
}
if ( data - > dptr ! = NULL ) {
memcpy ( buf , data - > dptr , data - > dsize ) ;
free ( data - > dptr ) ;
}
data - > dptr = ( uint8_t * ) buf ;
data - > dsize = byte_pos + 1 ;
}
data - > dptr [ byte_pos ] | = bit_mask ;
return 0 ;
}
void ctdb_trackingdb_traverse ( struct ctdb_context * ctdb , TDB_DATA data , ctdb_trackingdb_cb cb , void * private_data )
{
int i ;
for ( i = 0 ; i < data . dsize ; i + + ) {
int j ;
for ( j = 0 ; j < 8 ; j + + ) {
int mask = 1 < < j ;
if ( data . dptr [ i ] & mask ) {
cb ( ctdb , i * 8 + j , private_data ) ;
}
}
}
}
2011-11-11 06:56:46 +04:00
/*
this is the dummy null procedure that all databases support
*/
int ctdb_null_func ( struct ctdb_call_info * call )
{
return 0 ;
}
/*
this is a plain fetch procedure that all databases support
*/
int ctdb_fetch_func ( struct ctdb_call_info * call )
{
call - > reply_data = & call - > record_data ;
return 0 ;
}
/*
this is a plain fetch procedure that all databases support
this returns the full record including the ltdb header
*/
int ctdb_fetch_with_header_func ( struct ctdb_call_info * call )
{
call - > reply_data = talloc ( call , TDB_DATA ) ;
if ( call - > reply_data = = NULL ) {
return - 1 ;
}
call - > reply_data - > dsize = sizeof ( struct ctdb_ltdb_header ) + call - > record_data . dsize ;
call - > reply_data - > dptr = talloc_size ( call - > reply_data , call - > reply_data - > dsize ) ;
if ( call - > reply_data - > dptr = = NULL ) {
return - 1 ;
}
memcpy ( call - > reply_data - > dptr , call - > header , sizeof ( struct ctdb_ltdb_header ) ) ;
memcpy ( & call - > reply_data - > dptr [ sizeof ( struct ctdb_ltdb_header ) ] , call - > record_data . dptr , call - > record_data . dsize ) ;
return 0 ;
}
2011-07-20 05:39:50 +04:00