2010-01-23 02:13:59 +00:00
# include "logstore.h"
2010-03-17 21:51:26 +00:00
# include "merger.h"
2010-01-23 02:13:59 +00:00
2010-02-15 23:02:01 +00:00
# include <stasis/transactional.h>
2010-04-28 19:21:25 +00:00
# include <stasis/bufferManager.h>
# include <stasis/bufferManager/bufferHash.h>
2010-05-19 23:42:06 +00:00
# include "mergeStats.h"
2010-04-28 19:21:25 +00:00
2010-03-17 21:51:26 +00:00
# undef try
# undef end
2010-02-15 23:02:01 +00:00
static inline double tv_to_double ( struct timeval tv )
{
return static_cast < double > ( tv . tv_sec ) +
( static_cast < double > ( tv . tv_usec ) / 1000000.0 ) ;
}
2010-01-23 02:13:59 +00:00
/////////////////////////////////////////////////////////////////
// LOG TABLE IMPLEMENTATION
/////////////////////////////////////////////////////////////////
2010-03-17 21:51:26 +00:00
template < class TUPLE >
logtable < TUPLE > : : logtable ( pageid_t internal_region_size , pageid_t datapage_region_size , pageid_t datapage_size )
2010-01-23 02:13:59 +00:00
{
2010-05-21 23:43:17 +00:00
r_val = MIN_R ;
2010-01-23 02:13:59 +00:00
tree_c0 = NULL ;
2010-02-18 23:31:57 +00:00
tree_c0_mergeable = NULL ;
2010-08-05 17:43:46 +00:00
c0_is_merging = false ;
tree_c1_prime = NULL ;
2010-01-23 02:13:59 +00:00
tree_c1 = NULL ;
2010-02-18 23:31:57 +00:00
tree_c1_mergeable = NULL ;
2010-01-23 02:13:59 +00:00
tree_c2 = NULL ;
2010-08-17 21:23:39 +00:00
// This bool is purely for external code.
this - > accepting_new_requests = true ;
2010-12-08 19:49:13 +00:00
this - > shutting_down_ = false ;
2010-08-21 03:09:18 +00:00
flushing = false ;
2010-05-19 23:42:06 +00:00
this - > merge_mgr = new mergeManager ( this ) ;
2010-01-23 02:13:59 +00:00
this - > mergedata = 0 ;
//tmerger = new tuplemerger(&append_merger);
tmerger = new tuplemerger ( & replace_merger ) ;
2010-05-27 01:49:27 +00:00
header_mut = rwlc_initlock ( ) ;
2010-06-21 22:59:05 +00:00
pthread_mutex_init ( & tick_mut , 0 ) ;
2010-05-27 01:49:27 +00:00
pthread_mutex_init ( & rb_mut , 0 ) ;
2010-05-19 23:42:06 +00:00
pthread_cond_init ( & c0_needed , 0 ) ;
pthread_cond_init ( & c0_ready , 0 ) ;
pthread_cond_init ( & c1_needed , 0 ) ;
pthread_cond_init ( & c1_ready , 0 ) ;
2010-02-20 01:18:39 +00:00
2010-01-23 02:13:59 +00:00
tsize = 0 ;
tree_bytes = 0 ;
2010-02-20 01:18:39 +00:00
epoch = 0 ;
2010-03-13 00:05:06 +00:00
this - > internal_region_size = internal_region_size ;
this - > datapage_region_size = datapage_region_size ;
this - > datapage_size = datapage_size ;
2010-01-23 02:13:59 +00:00
}
2010-02-10 21:49:50 +00:00
2010-03-17 21:51:26 +00:00
template < class TUPLE >
logtable < TUPLE > : : ~ logtable ( )
2010-01-23 02:13:59 +00:00
{
if ( tree_c1 ! = NULL )
delete tree_c1 ;
if ( tree_c2 ! = NULL )
delete tree_c2 ;
if ( tree_c0 ! = NULL )
{
2010-03-09 01:42:23 +00:00
memTreeComponent < datatuple > : : tearDownTree ( tree_c0 ) ;
2010-01-23 02:13:59 +00:00
}
2010-05-27 01:49:27 +00:00
pthread_mutex_destroy ( & rb_mut ) ;
2010-06-21 22:59:05 +00:00
pthread_mutex_destroy ( & tick_mut ) ;
2010-05-27 01:49:27 +00:00
rwlc_deletelock ( header_mut ) ;
2010-05-19 23:42:06 +00:00
pthread_cond_destroy ( & c0_needed ) ;
pthread_cond_destroy ( & c0_ready ) ;
pthread_cond_destroy ( & c1_needed ) ;
pthread_cond_destroy ( & c1_ready ) ;
2010-01-23 02:13:59 +00:00
delete tmerger ;
}
2010-04-28 19:21:25 +00:00
template < class TUPLE >
void logtable < TUPLE > : : init_stasis ( ) {
DataPage < datatuple > : : register_stasis_page_impl ( ) ;
2010-09-29 17:58:34 +00:00
stasis_buffer_manager_size = 768 * 1024 ; // 4GB = 2^10 pages:
2010-05-27 23:15:24 +00:00
// XXX Workaround Stasis' (still broken) default concurrent buffer manager
2010-12-08 19:49:13 +00:00
// stasis_buffer_manager_factory = stasis_buffer_manager_hash_factory;
// stasis_buffer_manager_hint_writes_are_sequential = 0;
2010-04-28 19:21:25 +00:00
Tinit ( ) ;
}
template < class TUPLE >
void logtable < TUPLE > : : deinit_stasis ( ) { Tdeinit ( ) ; }
2010-03-17 21:51:26 +00:00
template < class TUPLE >
recordid logtable < TUPLE > : : allocTable ( int xid )
2010-01-23 02:13:59 +00:00
{
table_rec = Talloc ( xid , sizeof ( tbl_header ) ) ;
2010-05-19 23:42:06 +00:00
mergeStats * stats = 0 ;
2010-01-23 02:13:59 +00:00
//create the big tree
2010-04-29 00:57:48 +00:00
tree_c2 = new diskTreeComponent ( xid , internal_region_size , datapage_region_size , datapage_size , stats ) ;
2010-01-23 02:13:59 +00:00
//create the small tree
2010-04-29 00:57:48 +00:00
tree_c1 = new diskTreeComponent ( xid , internal_region_size , datapage_region_size , datapage_size , stats ) ;
2010-02-27 00:35:13 +00:00
2010-06-21 20:03:05 +00:00
c0_stats = merge_mgr - > get_merge_stats ( 0 ) ;
merge_mgr - > new_merge ( 0 ) ;
c0_stats - > starting_merge ( ) ;
update_persistent_header ( xid , 1 ) ;
update_persistent_header ( xid , 2 ) ;
2010-02-27 00:35:13 +00:00
return table_rec ;
}
2010-03-17 21:51:26 +00:00
template < class TUPLE >
void logtable < TUPLE > : : openTable ( int xid , recordid rid ) {
2010-03-13 00:05:06 +00:00
table_rec = rid ;
Tread ( xid , table_rec , & tbl_header ) ;
2010-04-29 00:57:48 +00:00
tree_c2 = new diskTreeComponent ( xid , tbl_header . c2_root , tbl_header . c2_state , tbl_header . c2_dp_state , 0 ) ;
tree_c1 = new diskTreeComponent ( xid , tbl_header . c1_root , tbl_header . c1_state , tbl_header . c1_dp_state , 0 ) ;
2010-06-21 20:03:05 +00:00
merge_mgr - > get_merge_stats ( 1 ) - > bytes_out = tbl_header . c1_base_size ;
merge_mgr - > get_merge_stats ( 1 ) - > base_size = tbl_header . c1_base_size ;
merge_mgr - > get_merge_stats ( 1 ) - > mergeable_size = tbl_header . c1_mergeable_size ;
merge_mgr - > get_merge_stats ( 2 ) - > base_size = tbl_header . c2_base_size ;
merge_mgr - > get_merge_stats ( 2 ) - > bytes_out = tbl_header . c2_base_size ;
c0_stats = merge_mgr - > get_merge_stats ( 0 ) ;
merge_mgr - > new_merge ( 0 ) ;
c0_stats - > starting_merge ( ) ;
2010-03-01 21:26:07 +00:00
}
2010-03-17 21:51:26 +00:00
template < class TUPLE >
2010-06-21 20:03:05 +00:00
void logtable < TUPLE > : : update_persistent_header ( int xid , int merge_level ) {
2010-02-27 00:35:13 +00:00
2010-05-19 23:42:06 +00:00
tbl_header . c2_root = tree_c2 - > get_root_rid ( ) ;
2010-03-13 00:05:06 +00:00
tbl_header . c2_dp_state = tree_c2 - > get_datapage_allocator_rid ( ) ;
tbl_header . c2_state = tree_c2 - > get_internal_node_allocator_rid ( ) ;
tbl_header . c1_root = tree_c1 - > get_root_rid ( ) ;
tbl_header . c1_dp_state = tree_c1 - > get_datapage_allocator_rid ( ) ;
tbl_header . c1_state = tree_c1 - > get_internal_node_allocator_rid ( ) ;
2010-01-23 02:13:59 +00:00
2010-06-21 20:03:05 +00:00
if ( merge_level = = 1 ) {
tbl_header . c1_base_size = merge_mgr - > get_merge_stats ( 1 ) - > bytes_out ;
tbl_header . c1_mergeable_size = merge_mgr - > get_merge_stats ( 1 ) - > mergeable_size ;
} else if ( merge_level = = 2 ) {
tbl_header . c1_mergeable_size = 0 ;
tbl_header . c2_base_size = merge_mgr - > get_merge_stats ( 2 ) - > bytes_out ;
} else {
assert ( merge_level = = 1 | | merge_level = = 2 ) ;
abort ( ) ;
}
2010-01-23 02:13:59 +00:00
Tset ( xid , table_rec , & tbl_header ) ;
}
2010-03-17 21:51:26 +00:00
template < class TUPLE >
void logtable < TUPLE > : : setMergeData ( logtable_mergedata * mdata ) {
this - > mergedata = mdata ;
bump_epoch ( ) ;
}
template < class TUPLE >
void logtable < TUPLE > : : flushTable ( )
2010-01-23 02:13:59 +00:00
{
struct timeval start_tv , stop_tv ;
double start , stop ;
static double last_start ;
static bool first = 1 ;
static int merge_count = 0 ;
gettimeofday ( & start_tv , 0 ) ;
start = tv_to_double ( start_tv ) ;
2010-08-24 00:40:48 +00:00
# ifdef NO_SNOWSHOVEL
merge_mgr - > finished_merge ( 0 ) ; // XXX will deadlock..
# endif
2010-01-23 02:13:59 +00:00
2010-08-21 03:09:18 +00:00
flushing = true ;
2010-05-19 23:42:06 +00:00
bool blocked = false ;
2010-01-23 02:13:59 +00:00
2010-08-05 17:43:46 +00:00
int expmcount = merge_count ;
//this waits for the previous merger of the mem-tree
//hopefullly this wont happen
# ifdef NO_SNOWSHOVEL
2010-05-19 23:42:06 +00:00
while ( get_tree_c0_mergeable ( ) ) {
2010-08-05 17:43:46 +00:00
# else
while ( get_c0_is_merging ( ) ) {
# endif
2010-05-27 01:49:27 +00:00
rwlc_cond_wait ( & c0_needed , header_mut ) ;
2010-05-19 23:42:06 +00:00
blocked = true ;
if ( expmcount ! = merge_count ) {
return ;
}
2010-01-23 02:13:59 +00:00
}
2010-08-05 17:43:46 +00:00
set_c0_is_merging ( true ) ;
2010-01-23 02:13:59 +00:00
2010-05-26 00:58:17 +00:00
c0_stats - > handed_off_tree ( ) ;
2010-06-02 21:47:58 +00:00
merge_mgr - > new_merge ( 0 ) ;
2010-05-26 00:58:17 +00:00
2010-01-23 02:13:59 +00:00
gettimeofday ( & stop_tv , 0 ) ;
stop = tv_to_double ( stop_tv ) ;
2010-08-05 17:43:46 +00:00
# ifdef NO_SNOWSHOVEL
2010-02-18 23:31:57 +00:00
set_tree_c0_mergeable ( get_tree_c0 ( ) ) ;
2010-08-05 17:43:46 +00:00
# endif
2010-05-19 23:42:06 +00:00
pthread_cond_signal ( & c0_ready ) ;
2010-05-26 00:58:17 +00:00
DEBUG ( " Signaled c0-c1 merge thread \n " ) ;
2010-01-23 02:13:59 +00:00
merge_count + + ;
2010-08-05 17:43:46 +00:00
# ifdef NO_SNOWSHOVEL
2010-03-09 01:42:23 +00:00
set_tree_c0 ( new memTreeComponent < datatuple > : : rbtree_t ) ;
2010-08-05 17:43:46 +00:00
# endif
2010-05-19 23:42:06 +00:00
c0_stats - > starting_merge ( ) ;
2010-02-18 23:31:57 +00:00
2010-01-23 02:13:59 +00:00
tsize = 0 ;
tree_bytes = 0 ;
2010-05-19 23:42:06 +00:00
2010-06-03 00:12:31 +00:00
if ( blocked & & stop - start > 1.0 ) {
2010-05-19 23:42:06 +00:00
if ( first )
{
printf ( " \n Blocked writes for %f sec \n " , stop - start ) ;
first = 0 ;
}
else
{
printf ( " \n Blocked writes for %f sec (serviced writes for %f sec) \n " ,
stop - start , start - last_start ) ;
}
last_start = stop ;
2010-05-21 23:43:17 +00:00
} else {
DEBUG ( " signaled c0-c1 merge \n " ) ;
2010-01-23 02:13:59 +00:00
}
2010-08-21 03:09:18 +00:00
flushing = false ;
2010-01-23 02:13:59 +00:00
}
2010-03-17 21:51:26 +00:00
template < class TUPLE >
datatuple * logtable < TUPLE > : : findTuple ( int xid , const datatuple : : key_t key , size_t keySize )
2010-01-23 02:13:59 +00:00
{
//prepare a search tuple
2010-05-19 23:42:06 +00:00
datatuple * search_tuple = datatuple : : create ( key , keySize ) ;
2010-01-23 02:13:59 +00:00
2010-05-27 01:49:27 +00:00
pthread_mutex_lock ( & rb_mut ) ;
2010-01-23 02:13:59 +00:00
datatuple * ret_tuple = 0 ;
//step 1: look in tree_c0
2010-03-09 01:42:23 +00:00
memTreeComponent < datatuple > : : rbtree_t : : iterator rbitr = get_tree_c0 ( ) - > find ( search_tuple ) ;
2010-02-18 23:31:57 +00:00
if ( rbitr ! = get_tree_c0 ( ) - > end ( ) )
2010-01-23 02:13:59 +00:00
{
2010-02-18 23:31:57 +00:00
DEBUG ( " tree_c0 size %d \n " , get_tree_c0 ( ) - > size ( ) ) ;
2010-02-10 21:49:50 +00:00
ret_tuple = ( * rbitr ) - > create_copy ( ) ;
2010-01-23 02:13:59 +00:00
}
2010-05-27 01:49:27 +00:00
pthread_mutex_unlock ( & rb_mut ) ;
2010-06-21 20:03:05 +00:00
rwlc_readlock ( header_mut ) ; // XXX: FIXME with optimisitic concurrency control. Has to be before rb_mut, or we could merge the tuple with itself due to an intervening merge
2010-05-27 01:49:27 +00:00
2010-01-23 02:13:59 +00:00
bool done = false ;
//step: 2 look into first in tree if exists (a first level merge going on)
2010-02-18 23:31:57 +00:00
if ( get_tree_c0_mergeable ( ) ! = 0 )
2010-01-23 02:13:59 +00:00
{
DEBUG ( " old mem tree not null %d \n " , ( * ( mergedata - > old_c0 ) ) - > size ( ) ) ;
2010-02-18 23:31:57 +00:00
rbitr = get_tree_c0_mergeable ( ) - > find ( search_tuple ) ;
if ( rbitr ! = get_tree_c0_mergeable ( ) - > end ( ) )
2010-01-23 02:13:59 +00:00
{
2010-02-10 21:49:50 +00:00
datatuple * tuple = * rbitr ;
2010-01-23 02:13:59 +00:00
2010-02-10 21:49:50 +00:00
if ( tuple - > isDelete ( ) ) //tuple deleted
2010-01-23 02:13:59 +00:00
done = true ; //return ret_tuple
else if ( ret_tuple ! = 0 ) //merge the two
{
2010-02-10 21:49:50 +00:00
datatuple * mtuple = tmerger - > merge ( tuple , ret_tuple ) ; //merge the two
datatuple : : freetuple ( ret_tuple ) ; //free tuple from current tree
2010-01-23 02:13:59 +00:00
ret_tuple = mtuple ; //set return tuple to merge result
}
else //key first found in old mem tree
{
2010-05-19 23:42:06 +00:00
ret_tuple = tuple - > create_copy ( ) ;
2010-01-23 02:13:59 +00:00
}
//we cannot free tuple from old-tree 'cos it is not a copy
}
}
2010-08-05 17:43:46 +00:00
//step 2.5: check new c1 if exists
if ( ! done & & get_tree_c1_prime ( ) ! = 0 )
{
DEBUG ( " old c1 tree not null \n " ) ;
datatuple * tuple_oc1 = get_tree_c1_prime ( ) - > findTuple ( xid , key , keySize ) ;
if ( tuple_oc1 ! = NULL )
{
bool use_copy = false ;
if ( tuple_oc1 - > isDelete ( ) )
done = true ;
else if ( ret_tuple ! = 0 ) //merge the two
{
datatuple * mtuple = tmerger - > merge ( tuple_oc1 , ret_tuple ) ; //merge the two
datatuple : : freetuple ( ret_tuple ) ; //free tuple from before
ret_tuple = mtuple ; //set return tuple to merge result
}
else //found for the first time
{
use_copy = true ;
ret_tuple = tuple_oc1 ;
}
if ( ! use_copy )
{
datatuple : : freetuple ( tuple_oc1 ) ; //free tuple from tree old c1
}
}
}
//step 3: check c1
2010-01-23 02:13:59 +00:00
if ( ! done )
{
2010-03-13 00:05:06 +00:00
datatuple * tuple_c1 = get_tree_c1 ( ) - > findTuple ( xid , key , keySize ) ;
2010-01-23 02:13:59 +00:00
if ( tuple_c1 ! = NULL )
{
bool use_copy = false ;
if ( tuple_c1 - > isDelete ( ) ) //tuple deleted
2010-08-05 17:43:46 +00:00
done = true ;
2010-01-23 02:13:59 +00:00
else if ( ret_tuple ! = 0 ) //merge the two
{
datatuple * mtuple = tmerger - > merge ( tuple_c1 , ret_tuple ) ; //merge the two
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( ret_tuple ) ; //free tuple from before
2010-08-05 17:43:46 +00:00
ret_tuple = mtuple ; //set return tuple to merge result
}
2010-01-23 02:13:59 +00:00
else //found for the first time
{
use_copy = true ;
ret_tuple = tuple_c1 ;
}
if ( ! use_copy )
{
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( tuple_c1 ) ; //free tuple from tree c1
2010-01-23 02:13:59 +00:00
}
}
}
//step 4: check old c1 if exists
2010-02-18 23:31:57 +00:00
if ( ! done & & get_tree_c1_mergeable ( ) ! = 0 )
2010-01-23 02:13:59 +00:00
{
DEBUG ( " old c1 tree not null \n " ) ;
2010-03-13 00:05:06 +00:00
datatuple * tuple_oc1 = get_tree_c1_mergeable ( ) - > findTuple ( xid , key , keySize ) ;
2010-01-23 02:13:59 +00:00
if ( tuple_oc1 ! = NULL )
{
bool use_copy = false ;
if ( tuple_oc1 - > isDelete ( ) )
done = true ;
else if ( ret_tuple ! = 0 ) //merge the two
{
datatuple * mtuple = tmerger - > merge ( tuple_oc1 , ret_tuple ) ; //merge the two
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( ret_tuple ) ; //free tuple from before
2010-01-23 02:13:59 +00:00
ret_tuple = mtuple ; //set return tuple to merge result
}
else //found for the first time
{
use_copy = true ;
ret_tuple = tuple_oc1 ;
}
if ( ! use_copy )
{
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( tuple_oc1 ) ; //free tuple from tree old c1
2010-01-23 02:13:59 +00:00
}
}
}
//step 5: check c2
if ( ! done )
{
DEBUG ( " Not in old first disk tree \n " ) ;
2010-03-13 00:05:06 +00:00
datatuple * tuple_c2 = get_tree_c2 ( ) - > findTuple ( xid , key , keySize ) ;
2010-01-23 02:13:59 +00:00
if ( tuple_c2 ! = NULL )
{
bool use_copy = false ;
if ( tuple_c2 - > isDelete ( ) )
done = true ;
else if ( ret_tuple ! = 0 )
{
datatuple * mtuple = tmerger - > merge ( tuple_c2 , ret_tuple ) ; //merge the two
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( ret_tuple ) ; //free tuple from before
2010-01-23 02:13:59 +00:00
ret_tuple = mtuple ; //set return tuple to merge result
}
else //found for the first time
{
use_copy = true ;
ret_tuple = tuple_c2 ;
}
if ( ! use_copy )
{
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( tuple_c2 ) ; //free tuple from tree c2
2010-01-23 02:13:59 +00:00
}
}
}
2010-05-27 01:49:27 +00:00
rwlc_unlock ( header_mut ) ;
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( search_tuple ) ;
2010-01-23 02:13:59 +00:00
return ret_tuple ;
}
/*
* returns the first record found with the matching key
* ( not to be used together with diffs )
* */
2010-03-17 21:51:26 +00:00
template < class TUPLE >
datatuple * logtable < TUPLE > : : findTuple_first ( int xid , datatuple : : key_t key , size_t keySize )
2010-01-23 02:13:59 +00:00
{
//prepare a search tuple
2010-02-10 21:49:50 +00:00
datatuple * search_tuple = datatuple : : create ( key , keySize ) ;
2010-01-23 02:13:59 +00:00
datatuple * ret_tuple = 0 ;
//step 1: look in tree_c0
2010-05-27 01:49:27 +00:00
pthread_mutex_lock ( & rb_mut ) ;
2010-03-09 01:42:23 +00:00
memTreeComponent < datatuple > : : rbtree_t : : iterator rbitr = get_tree_c0 ( ) - > find ( search_tuple ) ;
2010-02-18 23:31:57 +00:00
if ( rbitr ! = get_tree_c0 ( ) - > end ( ) )
2010-01-23 02:13:59 +00:00
{
DEBUG ( " tree_c0 size %d \n " , tree_c0 - > size ( ) ) ;
2010-02-10 21:49:50 +00:00
ret_tuple = ( * rbitr ) - > create_copy ( ) ;
2010-05-27 01:49:27 +00:00
pthread_mutex_unlock ( & rb_mut ) ;
2010-01-23 02:13:59 +00:00
}
else
{
DEBUG ( " Not in mem tree %d \n " , tree_c0 - > size ( ) ) ;
2010-05-27 01:49:27 +00:00
pthread_mutex_unlock ( & rb_mut ) ;
2010-06-21 20:03:05 +00:00
rwlc_readlock ( header_mut ) ; // XXX FIXME WITH OCC!!
2010-05-27 01:49:27 +00:00
2010-01-23 02:13:59 +00:00
//step: 2 look into first in tree if exists (a first level merge going on)
2010-02-18 23:31:57 +00:00
if ( get_tree_c0_mergeable ( ) ! = NULL )
2010-01-23 02:13:59 +00:00
{
DEBUG ( " old mem tree not null %d \n " , ( * ( mergedata - > old_c0 ) ) - > size ( ) ) ;
2010-02-18 23:31:57 +00:00
rbitr = get_tree_c0_mergeable ( ) - > find ( search_tuple ) ;
if ( rbitr ! = get_tree_c0_mergeable ( ) - > end ( ) )
2010-01-23 02:13:59 +00:00
{
2010-02-10 21:49:50 +00:00
ret_tuple = ( * rbitr ) - > create_copy ( ) ;
2010-01-23 02:13:59 +00:00
}
}
2010-08-05 17:43:46 +00:00
if ( ret_tuple = = 0 )
{
DEBUG ( " Not in first disk tree \n " ) ;
//step 4: check in progress c1 if exists
if ( get_tree_c1_prime ( ) ! = 0 )
{
DEBUG ( " old c1 tree not null \n " ) ;
ret_tuple = get_tree_c1_prime ( ) - > findTuple ( xid , key , keySize ) ;
}
}
2010-01-23 02:13:59 +00:00
if ( ret_tuple = = 0 )
{
DEBUG ( " Not in old mem tree \n " ) ;
//step 3: check c1
2010-03-13 00:05:06 +00:00
ret_tuple = get_tree_c1 ( ) - > findTuple ( xid , key , keySize ) ;
2010-01-23 02:13:59 +00:00
}
if ( ret_tuple = = 0 )
{
DEBUG ( " Not in first disk tree \n " ) ;
//step 4: check old c1 if exists
2010-02-18 23:31:57 +00:00
if ( get_tree_c1_mergeable ( ) ! = 0 )
2010-01-23 02:13:59 +00:00
{
2010-03-13 00:05:06 +00:00
DEBUG ( " old c1 tree not null \n " ) ;
ret_tuple = get_tree_c1_mergeable ( ) - > findTuple ( xid , key , keySize ) ;
2010-01-23 02:13:59 +00:00
}
}
if ( ret_tuple = = 0 )
{
DEBUG ( " Not in old first disk tree \n " ) ;
//step 5: check c2
2010-03-13 00:05:06 +00:00
ret_tuple = get_tree_c2 ( ) - > findTuple ( xid , key , keySize ) ;
}
2010-06-18 00:06:46 +00:00
rwlc_unlock ( header_mut ) ;
2010-01-23 02:13:59 +00:00
}
2010-02-10 21:49:50 +00:00
datatuple : : freetuple ( search_tuple ) ;
2010-01-23 02:13:59 +00:00
return ret_tuple ;
}
2010-08-30 22:22:25 +00:00
2010-03-17 21:51:26 +00:00
template < class TUPLE >
2010-08-30 22:22:25 +00:00
datatuple * logtable < TUPLE > : : insertTupleHelper ( datatuple * tuple )
2010-01-23 02:13:59 +00:00
{
2010-08-30 22:22:25 +00:00
//find the previous tuple with same key in the memtree if exists
memTreeComponent < datatuple > : : rbtree_t : : iterator rbitr = tree_c0 - > find ( tuple ) ;
datatuple * t = 0 ;
datatuple * pre_t = 0 ;
if ( rbitr ! = tree_c0 - > end ( ) )
{
pre_t = * rbitr ;
//do the merging
datatuple * new_t = tmerger - > merge ( pre_t , tuple ) ;
c0_stats - > merged_tuples ( new_t , tuple , pre_t ) ;
t = new_t ;
tree_c0 - > erase ( pre_t ) ; //remove the previous tuple
tree_c0 - > insert ( new_t ) ; //insert the new tuple
//update the tree size (+ new_t size - pre_t size)
tree_bytes + = ( ( int64_t ) new_t - > byte_length ( ) - ( int64_t ) pre_t - > byte_length ( ) ) ;
2010-02-10 21:49:50 +00:00
2010-08-30 22:22:25 +00:00
}
else //no tuple with same key exists in mem-tree
{
2010-01-28 02:20:49 +00:00
2010-08-30 22:22:25 +00:00
t = tuple - > create_copy ( ) ;
2010-01-28 02:20:49 +00:00
2010-08-30 22:22:25 +00:00
//insert tuple into the rbtree
tree_c0 - > insert ( t ) ;
2010-05-26 00:58:17 +00:00
2010-08-30 22:22:25 +00:00
tsize + + ;
tree_bytes + = t - > byte_length ( ) ; // + RB_TREE_OVERHEAD;
2010-01-23 02:13:59 +00:00
2010-08-30 22:22:25 +00:00
}
merge_mgr - > wrote_tuple ( 0 , t ) ; // needs to be here; doesn't grab a mutex.
2010-01-23 02:13:59 +00:00
2010-08-05 17:43:46 +00:00
# ifdef NO_SNOWSHOVEL
2010-08-30 22:22:25 +00:00
//flushing logic
if ( tree_bytes > = max_c0_size )
{
DEBUG ( " tree size before merge %d tuples %lld bytes. \n " , tsize , tree_bytes ) ;
// NOTE: we hold rb_mut across the (blocking on merge) flushTable. Therefore:
// *** Blocking in flushTable is REALLY BAD ***
// Because it blocks readers and writers.
// The merge policy does its best to make sure flushTable does not block.
rwlc_writelock ( header_mut ) ;
// the test of tree size needs to be atomic with the flushTable, and flushTable needs a writelock.
if ( tree_bytes > = max_c0_size ) {
flushTable ( ) ; // this needs to hold rb_mut if snowshoveling is disabled, but can't hold rb_mut if snowshoveling is enabled.
}
rwlc_unlock ( header_mut ) ;
2010-08-05 17:43:46 +00:00
# endif
2010-08-30 22:22:25 +00:00
return pre_t ;
}
template < class TUPLE >
void logtable < TUPLE > : : insertManyTuples ( datatuple * * tuples , int tuple_count ) {
for ( int i = 0 ; i < tuple_count ; i + + ) {
merge_mgr - > read_tuple_from_small_component ( 0 , tuples [ i ] ) ;
}
pthread_mutex_lock ( & rb_mut ) ;
int num_old_tups = 0 ;
pageid_t sum_old_tup_lens = 0 ;
for ( int i = 0 ; i < tuple_count ; i + + ) {
datatuple * old_tup = insertTupleHelper ( tuples [ i ] ) ;
if ( old_tup ) {
num_old_tups + + ;
sum_old_tup_lens + = old_tup - > byte_length ( ) ;
datatuple : : freetuple ( old_tup ) ;
}
}
pthread_mutex_unlock ( & rb_mut ) ;
merge_mgr - > read_tuple_from_large_component ( 0 , num_old_tups , sum_old_tup_lens ) ;
}
template < class TUPLE >
void logtable < TUPLE > : : insertTuple ( datatuple * tuple )
{
//lock the red-black tree
merge_mgr - > read_tuple_from_small_component ( 0 , tuple ) ; // has to be before rb_mut, since it calls tick with block = true, and that releases header_mut.
datatuple * pre_t = 0 ; // this is a pointer to any data tuples that we'll be deleting below. We need to update the merge_mgr statistics with it, but have to do so outside of the rb_mut region.
pthread_mutex_lock ( & rb_mut ) ;
pre_t = insertTupleHelper ( tuple ) ;
2010-06-18 00:06:46 +00:00
pthread_mutex_unlock ( & rb_mut ) ;
2010-08-05 17:43:46 +00:00
// XXX is it OK to move this after the NO_SNOWSHOVEL block?
if ( pre_t ) {
// needs to be here; calls update_progress, which sometimes grabs mutexes..
merge_mgr - > read_tuple_from_large_component ( 0 , pre_t ) ; // was interspersed with the erase, insert above...
datatuple : : freetuple ( pre_t ) ; //free the previous tuple
}
2010-01-23 02:13:59 +00:00
DEBUG ( " tree size %d tuples %lld bytes. \n " , tsize , tree_bytes ) ;
}
2010-09-16 22:36:48 +00:00
template < class TUPLE >
bool logtable < TUPLE > : : testAndSetTuple ( datatuple * tuple , datatuple * tuple2 )
{
bool succ = false ;
static pthread_mutex_t test_and_set_mut = PTHREAD_MUTEX_INITIALIZER ;
pthread_mutex_lock ( & test_and_set_mut ) ;
datatuple * exists = findTuple_first ( - 1 , tuple2 ? tuple2 - > key ( ) : tuple - > key ( ) , tuple2 ? tuple2 - > keylen ( ) : tuple - > keylen ( ) ) ;
if ( ! tuple2 | | tuple2 - > isDelete ( ) ) {
if ( ! exists | | exists - > isDelete ( ) ) {
succ = true ;
} else {
succ = false ;
}
} else {
if ( tuple2 - > datalen ( ) = = exists - > datalen ( ) & & ! memcmp ( tuple2 - > data ( ) , exists - > data ( ) , tuple2 - > datalen ( ) ) ) {
succ = true ;
} else {
succ = false ;
}
}
if ( exists ) datatuple : : freetuple ( exists ) ;
if ( succ ) insertTuple ( tuple ) ;
pthread_mutex_unlock ( & test_and_set_mut ) ;
return succ ;
}
2010-03-17 21:51:26 +00:00
template < class TUPLE >
void logtable < TUPLE > : : registerIterator ( iterator * it ) {
2010-02-25 01:29:32 +00:00
its . push_back ( it ) ;
}
2010-03-17 21:51:26 +00:00
template < class TUPLE >
void logtable < TUPLE > : : forgetIterator ( iterator * it ) {
2010-02-25 01:29:32 +00:00
for ( unsigned int i = 0 ; i < its . size ( ) ; i + + ) {
if ( its [ i ] = = it ) {
its . erase ( its . begin ( ) + i ) ;
break ;
}
}
}
2010-03-17 21:51:26 +00:00
template < class TUPLE >
void logtable < TUPLE > : : bump_epoch ( ) {
2010-02-25 01:29:32 +00:00
epoch + + ;
for ( unsigned int i = 0 ; i < its . size ( ) ; i + + ) {
its [ i ] - > invalidate ( ) ;
}
}
2010-03-17 21:51:26 +00:00
template class logtable < datatuple > ;