@ -11,6 +11,7 @@
# include "db/db_impl/db_impl.h"
# include "rocksdb/env.h"
# include "rocksdb/iterator.h"
# include "rocksdb/options.h"
# include "rocksdb/slice.h"
# include "rocksdb/system_clock.h"
@ -18,7 +19,6 @@
# include "rocksdb/write_batch.h"
# include "util/coding.h"
# include "util/string_util.h"
# include "util/threadpool_imp.h"
namespace ROCKSDB_NAMESPACE {
@ -104,6 +104,20 @@ Status TracerHelper::DecodeTrace(const std::string& encoded_trace,
return Status : : OK ( ) ;
}
Status TracerHelper : : DecodeHeader ( const std : : string & encoded_trace ,
Trace * header ) {
Status s = TracerHelper : : DecodeTrace ( encoded_trace , header ) ;
if ( header - > type ! = kTraceBegin ) {
return Status : : Corruption ( " Corrupted trace file. Incorrect header. " ) ;
}
if ( header - > payload . substr ( 0 , kTraceMagic . length ( ) ) ! = kTraceMagic ) {
return Status : : Corruption ( " Corrupted trace file. Incorrect magic. " ) ;
}
return s ;
}
bool TracerHelper : : SetPayloadMap ( uint64_t & payload_map ,
const TracePayloadType payload_type ) {
uint64_t old_state = payload_map ;
@ -112,82 +126,153 @@ bool TracerHelper::SetPayloadMap(uint64_t& payload_map,
return old_state ! = payload_map ;
}
void TracerHelper : : DecodeWritePayload ( Trace * trace ,
WritePayload * write_payload ) {
assert ( write_payload ! = nullptr ) ;
Slice buf ( trace - > payload ) ;
GetFixed64 ( & buf , & trace - > payload_map ) ;
int64_t payload_map = static_cast < int64_t > ( trace - > payload_map ) ;
while ( payload_map ) {
// Find the rightmost set bit.
uint32_t set_pos = static_cast < uint32_t > ( log2 ( payload_map & - payload_map ) ) ;
switch ( set_pos ) {
case TracePayloadType : : kWriteBatchData :
GetLengthPrefixedSlice ( & buf , & ( write_payload - > write_batch_data ) ) ;
break ;
default :
assert ( false ) ;
Status TracerHelper : : DecodeWriteRecord ( Trace * trace , int trace_file_version ,
std : : unique_ptr < TraceRecord > * record ) {
assert ( trace ! = nullptr ) ;
assert ( trace - > type = = kTraceWrite ) ;
PinnableSlice rep ;
if ( trace_file_version < 2 ) {
rep . PinSelf ( trace - > payload ) ;
} else {
Slice buf ( trace - > payload ) ;
GetFixed64 ( & buf , & trace - > payload_map ) ;
int64_t payload_map = static_cast < int64_t > ( trace - > payload_map ) ;
Slice write_batch_data ;
while ( payload_map ) {
// Find the rightmost set bit.
uint32_t set_pos =
static_cast < uint32_t > ( log2 ( payload_map & - payload_map ) ) ;
switch ( set_pos ) {
case TracePayloadType : : kWriteBatchData :
GetLengthPrefixedSlice ( & buf , & write_batch_data ) ;
break ;
default :
assert ( false ) ;
}
// unset the rightmost bit.
payload_map & = ( payload_map - 1 ) ;
}
// unset the rightmost bit.
payload_map & = ( payload_map - 1 ) ;
rep . PinSelf ( write_batch_data ) ;
}
if ( record ! = nullptr ) {
record - > reset ( new WriteQueryTraceRecord ( std : : move ( rep ) , trace - > ts ) ) ;
}
return Status : : OK ( ) ;
}
void TracerHelper : : DecodeGetPayload ( Trace * trace , GetPayload * get_payload ) {
assert ( get_payload ! = nullptr ) ;
Slice buf ( trace - > payload ) ;
GetFixed64 ( & buf , & trace - > payload_map ) ;
int64_t payload_map = static_cast < int64_t > ( trace - > payload_map ) ;
while ( payload_map ) {
// Find the rightmost set bit.
uint32_t set_pos = static_cast < uint32_t > ( log2 ( payload_map & - payload_map ) ) ;
switch ( set_pos ) {
case TracePayloadType : : kGetCFID :
GetFixed32 ( & buf , & ( get_payload - > cf_id ) ) ;
break ;
case TracePayloadType : : kGetKey :
GetLengthPrefixedSlice ( & buf , & ( get_payload - > get_key ) ) ;
break ;
default :
assert ( false ) ;
Status TracerHelper : : DecodeGetRecord ( Trace * trace , int trace_file_version ,
std : : unique_ptr < TraceRecord > * record ) {
assert ( trace ! = nullptr ) ;
assert ( trace - > type = = kTraceGet ) ;
uint32_t cf_id = 0 ;
Slice get_key ;
if ( trace_file_version < 2 ) {
DecodeCFAndKey ( trace - > payload , & cf_id , & get_key ) ;
} else {
Slice buf ( trace - > payload ) ;
GetFixed64 ( & buf , & trace - > payload_map ) ;
int64_t payload_map = static_cast < int64_t > ( trace - > payload_map ) ;
while ( payload_map ) {
// Find the rightmost set bit.
uint32_t set_pos =
static_cast < uint32_t > ( log2 ( payload_map & - payload_map ) ) ;
switch ( set_pos ) {
case TracePayloadType : : kGetCFID :
GetFixed32 ( & buf , & cf_id ) ;
break ;
case TracePayloadType : : kGetKey :
GetLengthPrefixedSlice ( & buf , & get_key ) ;
break ;
default :
assert ( false ) ;
}
// unset the rightmost bit.
payload_map & = ( payload_map - 1 ) ;
}
// unset the rightmost bit.
payload_map & = ( payload_map - 1 ) ;
}
if ( record ! = nullptr ) {
PinnableSlice ps ;
ps . PinSelf ( get_key ) ;
record - > reset ( new GetQueryTraceRecord ( cf_id , std : : move ( ps ) , trace - > ts ) ) ;
}
return Status : : OK ( ) ;
}
void TracerHelper : : DecodeIterPayload ( Trace * trace , IterPayload * iter_payload ) {
assert ( iter_payload ! = nullptr ) ;
Slice buf ( trace - > payload ) ;
GetFixed64 ( & buf , & trace - > payload_map ) ;
int64_t payload_map = static_cast < int64_t > ( trace - > payload_map ) ;
while ( payload_map ) {
// Find the rightmost set bit.
uint32_t set_pos = static_cast < uint32_t > ( log2 ( payload_map & - payload_map ) ) ;
switch ( set_pos ) {
case TracePayloadType : : kIterCFID :
GetFixed32 ( & buf , & ( iter_payload - > cf_id ) ) ;
break ;
case TracePayloadType : : kIterKey :
GetLengthPrefixedSlice ( & buf , & ( iter_payload - > iter_key ) ) ;
break ;
case TracePayloadType : : kIterLowerBound :
GetLengthPrefixedSlice ( & buf , & ( iter_payload - > lower_bound ) ) ;
break ;
case TracePayloadType : : kIterUpperBound :
GetLengthPrefixedSlice ( & buf , & ( iter_payload - > upper_bound ) ) ;
break ;
default :
assert ( false ) ;
Status TracerHelper : : DecodeIterRecord ( Trace * trace , int trace_file_version ,
std : : unique_ptr < TraceRecord > * record ) {
assert ( trace ! = nullptr ) ;
assert ( trace - > type = = kTraceIteratorSeek | |
trace - > type = = kTraceIteratorSeekForPrev ) ;
uint32_t cf_id = 0 ;
Slice iter_key ;
if ( trace_file_version < 2 ) {
DecodeCFAndKey ( trace - > payload , & cf_id , & iter_key ) ;
} else {
// Are these two used anywhere?
Slice lower_bound ;
Slice upper_bound ;
Slice buf ( trace - > payload ) ;
GetFixed64 ( & buf , & trace - > payload_map ) ;
int64_t payload_map = static_cast < int64_t > ( trace - > payload_map ) ;
while ( payload_map ) {
// Find the rightmost set bit.
uint32_t set_pos =
static_cast < uint32_t > ( log2 ( payload_map & - payload_map ) ) ;
switch ( set_pos ) {
case TracePayloadType : : kIterCFID :
GetFixed32 ( & buf , & cf_id ) ;
break ;
case TracePayloadType : : kIterKey :
GetLengthPrefixedSlice ( & buf , & iter_key ) ;
break ;
case TracePayloadType : : kIterLowerBound :
GetLengthPrefixedSlice ( & buf , & lower_bound ) ;
break ;
case TracePayloadType : : kIterUpperBound :
GetLengthPrefixedSlice ( & buf , & upper_bound ) ;
break ;
default :
assert ( false ) ;
}
// unset the rightmost bit.
payload_map & = ( payload_map - 1 ) ;
}
// unset the rightmost bit.
payload_map & = ( payload_map - 1 ) ;
}
if ( record ! = nullptr ) {
PinnableSlice ps_key ;
ps_key . PinSelf ( iter_key ) ;
record - > reset ( new IteratorSeekQueryTraceRecord (
static_cast < IteratorSeekQueryTraceRecord : : SeekType > ( trace - > type ) , cf_id ,
std : : move ( ps_key ) , trace - > ts ) ) ;
}
return Status : : OK ( ) ;
}
void TracerHelper : : DecodeMultiGetPayload ( Trace * trace ,
MultiGetPayload * multiget_payload ) {
assert ( multiget_payload ! = nullptr ) ;
Status TracerHelper : : DecodeMultiGetRecord (
Trace * trace , int trace_file_version ,
std : : unique_ptr < TraceRecord > * record ) {
assert ( trace ! = nullptr ) ;
assert ( trace - > type = = kTraceMultiGet ) ;
if ( trace_file_version < 2 ) {
return Status : : Corruption ( " MultiGet is not supported. " ) ;
}
uint32_t multiget_size = 0 ;
std : : vector < uint32_t > cf_ids ;
std : : vector < PinnableSlice > multiget_keys ;
Slice cfids_payload ;
Slice keys_payload ;
Slice buf ( trace - > payload ) ;
@ -198,7 +283,7 @@ void TracerHelper::DecodeMultiGetPayload(Trace* trace,
uint32_t set_pos = static_cast < uint32_t > ( log2 ( payload_map & - payload_map ) ) ;
switch ( set_pos ) {
case TracePayloadType : : kMultiGetSize :
GetFixed32 ( & buf , & ( multiget_payload - > multiget_size ) ) ;
GetFixed32 ( & buf , & multiget_size ) ;
break ;
case TracePayloadType : : kMultiGetCFIDs :
GetLengthPrefixedSlice ( & buf , & cfids_payload ) ;
@ -212,18 +297,31 @@ void TracerHelper::DecodeMultiGetPayload(Trace* trace,
// unset the rightmost bit.
payload_map & = ( payload_map - 1 ) ;
}
if ( multiget_size = = 0 ) {
return Status : : InvalidArgument ( " Empty MultiGet cf_ids or keys. " ) ;
}
// Decode the cfids_payload and keys_payload
multiget_payload - > cf_ids . reserve ( multiget_payload - > multiget_size ) ;
multiget_payload - > multiget_ keys . reserve ( multiget_payload - > multiget_size ) ;
for ( uint32_t i = 0 ; i < multiget_payload - > multiget_ size ; i + + ) {
cf_ids . reserve ( multiget_size ) ;
multiget_keys . reserve ( multiget_size ) ;
for ( uint32_t i = 0 ; i < multiget_size ; i + + ) {
uint32_t tmp_cfid ;
Slice tmp_key ;
GetFixed32 ( & cfids_payload , & tmp_cfid ) ;
GetLengthPrefixedSlice ( & keys_payload , & tmp_key ) ;
multiget_payload - > cf_ids . push_back ( tmp_cfid ) ;
multiget_payload - > multiget_keys . push_back ( tmp_key . ToString ( ) ) ;
cf_ids . push_back ( tmp_cfid ) ;
Slice s ( tmp_key ) ;
PinnableSlice ps ;
ps . PinSelf ( s ) ;
multiget_keys . push_back ( std : : move ( ps ) ) ;
}
if ( record ! = nullptr ) {
record - > reset ( new MultiGetQueryTraceRecord (
std : : move ( cf_ids ) , std : : move ( multiget_keys ) , trace - > ts ) ) ;
}
return Status : : OK ( ) ;
}
Tracer : : Tracer ( SystemClock * clock , const TraceOptions & trace_options ,
@ -418,10 +516,9 @@ bool Tracer::ShouldSkipTrace(const TraceType& trace_type) {
if ( IsTraceFileOverMax ( ) ) {
return true ;
}
if ( ( trace_options_ . filter & kTraceFilterGet
& & trace_type = = kTraceGet )
| | ( trace_options_ . filter & kTraceFilterWrite
& & trace_type = = kTraceWrite ) ) {
if ( ( trace_options_ . filter & kTraceFilterGet & & trace_type = = kTraceGet ) | |
( trace_options_ . filter & kTraceFilterWrite & &
trace_type = = kTraceWrite ) ) {
return true ;
}
+ + trace_request_count_ ;
@ -471,445 +568,4 @@ Status Tracer::WriteTrace(const Trace& trace) {
Status Tracer : : Close ( ) { return WriteFooter ( ) ; }
Replayer : : Replayer ( DB * db , const std : : vector < ColumnFamilyHandle * > & handles ,
std : : unique_ptr < TraceReader > & & reader )
: trace_reader_ ( std : : move ( reader ) ) {
assert ( db ! = nullptr ) ;
db_ = static_cast < DBImpl * > ( db - > GetRootDB ( ) ) ;
env_ = Env : : Default ( ) ;
for ( ColumnFamilyHandle * cfh : handles ) {
cf_map_ [ cfh - > GetID ( ) ] = cfh ;
}
fast_forward_ = 1 ;
}
Replayer : : ~ Replayer ( ) { trace_reader_ . reset ( ) ; }
Status Replayer : : SetFastForward ( uint32_t fast_forward ) {
Status s ;
if ( fast_forward < 1 ) {
s = Status : : InvalidArgument ( " Wrong fast forward speed! " ) ;
} else {
fast_forward_ = fast_forward ;
s = Status : : OK ( ) ;
}
return s ;
}
Status Replayer : : Replay ( ) {
Status s ;
Trace header ;
int db_version ;
s = ReadHeader ( & header ) ;
if ( ! s . ok ( ) ) {
return s ;
}
s = TracerHelper : : ParseTraceHeader ( header , & trace_file_version_ , & db_version ) ;
if ( ! s . ok ( ) ) {
return s ;
}
std : : chrono : : system_clock : : time_point replay_epoch =
std : : chrono : : system_clock : : now ( ) ;
WriteOptions woptions ;
ReadOptions roptions ;
Trace trace ;
uint64_t ops = 0 ;
Iterator * single_iter = nullptr ;
while ( s . ok ( ) ) {
trace . reset ( ) ;
s = ReadTrace ( & trace ) ;
if ( ! s . ok ( ) ) {
break ;
}
std : : this_thread : : sleep_until (
replay_epoch +
std : : chrono : : microseconds ( ( trace . ts - header . ts ) / fast_forward_ ) ) ;
if ( trace . type = = kTraceWrite ) {
if ( trace_file_version_ < 2 ) {
WriteBatch batch ( trace . payload ) ;
db_ - > Write ( woptions , & batch ) ;
} else {
WritePayload w_payload ;
TracerHelper : : DecodeWritePayload ( & trace , & w_payload ) ;
WriteBatch batch ( w_payload . write_batch_data . ToString ( ) ) ;
db_ - > Write ( woptions , & batch ) ;
}
ops + + ;
} else if ( trace . type = = kTraceGet ) {
GetPayload get_payload ;
get_payload . cf_id = 0 ;
get_payload . get_key = 0 ;
if ( trace_file_version_ < 2 ) {
DecodeCFAndKey ( trace . payload , & get_payload . cf_id , & get_payload . get_key ) ;
} else {
TracerHelper : : DecodeGetPayload ( & trace , & get_payload ) ;
}
if ( get_payload . cf_id > 0 & &
cf_map_ . find ( get_payload . cf_id ) = = cf_map_ . end ( ) ) {
return Status : : Corruption ( " Invalid Column Family ID. " ) ;
}
std : : string value ;
if ( get_payload . cf_id = = 0 ) {
db_ - > Get ( roptions , get_payload . get_key , & value ) ;
} else {
db_ - > Get ( roptions , cf_map_ [ get_payload . cf_id ] , get_payload . get_key ,
& value ) ;
}
ops + + ;
} else if ( trace . type = = kTraceIteratorSeek ) {
// Currently, we only support to call Seek. The Next() and Prev() is not
// supported.
IterPayload iter_payload ;
iter_payload . cf_id = 0 ;
if ( trace_file_version_ < 2 ) {
DecodeCFAndKey ( trace . payload , & iter_payload . cf_id ,
& iter_payload . iter_key ) ;
} else {
TracerHelper : : DecodeIterPayload ( & trace , & iter_payload ) ;
}
if ( iter_payload . cf_id > 0 & &
cf_map_ . find ( iter_payload . cf_id ) = = cf_map_ . end ( ) ) {
return Status : : Corruption ( " Invalid Column Family ID. " ) ;
}
if ( iter_payload . cf_id = = 0 ) {
single_iter = db_ - > NewIterator ( roptions ) ;
} else {
single_iter = db_ - > NewIterator ( roptions , cf_map_ [ iter_payload . cf_id ] ) ;
}
single_iter - > Seek ( iter_payload . iter_key ) ;
ops + + ;
delete single_iter ;
} else if ( trace . type = = kTraceIteratorSeekForPrev ) {
// Currently, we only support to call SeekForPrev. The Next() and Prev()
// is not supported.
IterPayload iter_payload ;
iter_payload . cf_id = 0 ;
if ( trace_file_version_ < 2 ) {
DecodeCFAndKey ( trace . payload , & iter_payload . cf_id ,
& iter_payload . iter_key ) ;
} else {
TracerHelper : : DecodeIterPayload ( & trace , & iter_payload ) ;
}
if ( iter_payload . cf_id > 0 & &
cf_map_ . find ( iter_payload . cf_id ) = = cf_map_ . end ( ) ) {
return Status : : Corruption ( " Invalid Column Family ID. " ) ;
}
if ( iter_payload . cf_id = = 0 ) {
single_iter = db_ - > NewIterator ( roptions ) ;
} else {
single_iter = db_ - > NewIterator ( roptions , cf_map_ [ iter_payload . cf_id ] ) ;
}
single_iter - > SeekForPrev ( iter_payload . iter_key ) ;
ops + + ;
delete single_iter ;
} else if ( trace . type = = kTraceMultiGet ) {
MultiGetPayload multiget_payload ;
assert ( trace_file_version_ > = 2 ) ;
TracerHelper : : DecodeMultiGetPayload ( & trace , & multiget_payload ) ;
std : : vector < ColumnFamilyHandle * > v_cfd ;
std : : vector < Slice > keys ;
assert ( multiget_payload . cf_ids . size ( ) = =
multiget_payload . multiget_keys . size ( ) ) ;
for ( size_t i = 0 ; i < multiget_payload . cf_ids . size ( ) ; i + + ) {
assert ( i < multiget_payload . cf_ids . size ( ) & &
i < multiget_payload . multiget_keys . size ( ) ) ;
if ( cf_map_ . find ( multiget_payload . cf_ids [ i ] ) = = cf_map_ . end ( ) ) {
return Status : : Corruption ( " Invalid Column Family ID. " ) ;
}
v_cfd . push_back ( cf_map_ [ multiget_payload . cf_ids [ i ] ] ) ;
keys . push_back ( Slice ( multiget_payload . multiget_keys [ i ] ) ) ;
}
std : : vector < std : : string > values ;
std : : vector < Status > ss = db_ - > MultiGet ( roptions , v_cfd , keys , & values ) ;
} else if ( trace . type = = kTraceEnd ) {
// Do nothing for now.
// TODO: Add some validations later.
break ;
}
}
if ( s . IsIncomplete ( ) ) {
// Reaching eof returns Incomplete status at the moment.
// Could happen when killing a process without calling EndTrace() API.
// TODO: Add better error handling.
return Status : : OK ( ) ;
}
return s ;
}
// The trace can be replayed with multithread by configurnge the number of
// threads in the thread pool. Trace records are read from the trace file
// sequentially and the corresponding queries are scheduled in the task
// queue based on the timestamp. Currently, we support Write_batch (Put,
// Delete, SingleDelete, DeleteRange), Get, Iterator (Seek and SeekForPrev).
Status Replayer : : MultiThreadReplay ( uint32_t threads_num ) {
Status s ;
Trace header ;
int db_version ;
s = ReadHeader ( & header ) ;
if ( ! s . ok ( ) ) {
return s ;
}
s = TracerHelper : : ParseTraceHeader ( header , & trace_file_version_ , & db_version ) ;
if ( ! s . ok ( ) ) {
return s ;
}
ThreadPoolImpl thread_pool ;
thread_pool . SetHostEnv ( env_ ) ;
if ( threads_num > 1 ) {
thread_pool . SetBackgroundThreads ( static_cast < int > ( threads_num ) ) ;
} else {
thread_pool . SetBackgroundThreads ( 1 ) ;
}
std : : chrono : : system_clock : : time_point replay_epoch =
std : : chrono : : system_clock : : now ( ) ;
WriteOptions woptions ;
ReadOptions roptions ;
uint64_t ops = 0 ;
while ( s . ok ( ) ) {
std : : unique_ptr < ReplayerWorkerArg > ra ( new ReplayerWorkerArg ) ;
ra - > db = db_ ;
s = ReadTrace ( & ( ra - > trace_entry ) ) ;
if ( ! s . ok ( ) ) {
break ;
}
ra - > cf_map = & cf_map_ ;
ra - > woptions = woptions ;
ra - > roptions = roptions ;
ra - > trace_file_version = trace_file_version_ ;
std : : this_thread : : sleep_until (
replay_epoch + std : : chrono : : microseconds (
( ra - > trace_entry . ts - header . ts ) / fast_forward_ ) ) ;
if ( ra - > trace_entry . type = = kTraceWrite ) {
thread_pool . Schedule ( & Replayer : : BGWorkWriteBatch , ra . release ( ) , nullptr ,
nullptr ) ;
ops + + ;
} else if ( ra - > trace_entry . type = = kTraceGet ) {
thread_pool . Schedule ( & Replayer : : BGWorkGet , ra . release ( ) , nullptr ,
nullptr ) ;
ops + + ;
} else if ( ra - > trace_entry . type = = kTraceIteratorSeek ) {
thread_pool . Schedule ( & Replayer : : BGWorkIterSeek , ra . release ( ) , nullptr ,
nullptr ) ;
ops + + ;
} else if ( ra - > trace_entry . type = = kTraceIteratorSeekForPrev ) {
thread_pool . Schedule ( & Replayer : : BGWorkIterSeekForPrev , ra . release ( ) ,
nullptr , nullptr ) ;
ops + + ;
} else if ( ra - > trace_entry . type = = kTraceMultiGet ) {
thread_pool . Schedule ( & Replayer : : BGWorkMultiGet , ra . release ( ) , nullptr ,
nullptr ) ;
ops + + ;
} else if ( ra - > trace_entry . type = = kTraceEnd ) {
// Do nothing for now.
// TODO: Add some validations later.
break ;
} else {
// Other trace entry types that are not implemented for replay.
// To finish the replay, we continue the process.
continue ;
}
}
if ( s . IsIncomplete ( ) ) {
// Reaching eof returns Incomplete status at the moment.
// Could happen when killing a process without calling EndTrace() API.
// TODO: Add better error handling.
s = Status : : OK ( ) ;
}
thread_pool . JoinAllThreads ( ) ;
return s ;
}
Status Replayer : : ReadHeader ( Trace * header ) {
assert ( header ! = nullptr ) ;
std : : string encoded_trace ;
// Read the trace head
Status s = trace_reader_ - > Read ( & encoded_trace ) ;
if ( ! s . ok ( ) ) {
return s ;
}
s = TracerHelper : : DecodeTrace ( encoded_trace , header ) ;
if ( header - > type ! = kTraceBegin ) {
return Status : : Corruption ( " Corrupted trace file. Incorrect header. " ) ;
}
if ( header - > payload . substr ( 0 , kTraceMagic . length ( ) ) ! = kTraceMagic ) {
return Status : : Corruption ( " Corrupted trace file. Incorrect magic. " ) ;
}
return s ;
}
Status Replayer : : ReadFooter ( Trace * footer ) {
assert ( footer ! = nullptr ) ;
Status s = ReadTrace ( footer ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( footer - > type ! = kTraceEnd ) {
return Status : : Corruption ( " Corrupted trace file. Incorrect footer. " ) ;
}
// TODO: Add more validations later
return s ;
}
Status Replayer : : ReadTrace ( Trace * trace ) {
assert ( trace ! = nullptr ) ;
std : : string encoded_trace ;
Status s = trace_reader_ - > Read ( & encoded_trace ) ;
if ( ! s . ok ( ) ) {
return s ;
}
return TracerHelper : : DecodeTrace ( encoded_trace , trace ) ;
}
void Replayer : : BGWorkGet ( void * arg ) {
std : : unique_ptr < ReplayerWorkerArg > ra (
reinterpret_cast < ReplayerWorkerArg * > ( arg ) ) ;
assert ( ra ! = nullptr ) ;
auto cf_map = static_cast < std : : unordered_map < uint32_t , ColumnFamilyHandle * > * > (
ra - > cf_map ) ;
GetPayload get_payload ;
get_payload . cf_id = 0 ;
if ( ra - > trace_file_version < 2 ) {
DecodeCFAndKey ( ra - > trace_entry . payload , & get_payload . cf_id ,
& get_payload . get_key ) ;
} else {
TracerHelper : : DecodeGetPayload ( & ( ra - > trace_entry ) , & get_payload ) ;
}
if ( get_payload . cf_id > 0 & &
cf_map - > find ( get_payload . cf_id ) = = cf_map - > end ( ) ) {
return ;
}
std : : string value ;
if ( get_payload . cf_id = = 0 ) {
ra - > db - > Get ( ra - > roptions , get_payload . get_key , & value ) ;
} else {
ra - > db - > Get ( ra - > roptions , ( * cf_map ) [ get_payload . cf_id ] , get_payload . get_key ,
& value ) ;
}
return ;
}
void Replayer : : BGWorkWriteBatch ( void * arg ) {
std : : unique_ptr < ReplayerWorkerArg > ra (
reinterpret_cast < ReplayerWorkerArg * > ( arg ) ) ;
assert ( ra ! = nullptr ) ;
if ( ra - > trace_file_version < 2 ) {
WriteBatch batch ( ra - > trace_entry . payload ) ;
ra - > db - > Write ( ra - > woptions , & batch ) ;
} else {
WritePayload w_payload ;
TracerHelper : : DecodeWritePayload ( & ( ra - > trace_entry ) , & w_payload ) ;
WriteBatch batch ( w_payload . write_batch_data . ToString ( ) ) ;
ra - > db - > Write ( ra - > woptions , & batch ) ;
}
return ;
}
void Replayer : : BGWorkIterSeek ( void * arg ) {
std : : unique_ptr < ReplayerWorkerArg > ra (
reinterpret_cast < ReplayerWorkerArg * > ( arg ) ) ;
assert ( ra ! = nullptr ) ;
auto cf_map = static_cast < std : : unordered_map < uint32_t , ColumnFamilyHandle * > * > (
ra - > cf_map ) ;
IterPayload iter_payload ;
iter_payload . cf_id = 0 ;
if ( ra - > trace_file_version < 2 ) {
DecodeCFAndKey ( ra - > trace_entry . payload , & iter_payload . cf_id ,
& iter_payload . iter_key ) ;
} else {
TracerHelper : : DecodeIterPayload ( & ( ra - > trace_entry ) , & iter_payload ) ;
}
if ( iter_payload . cf_id > 0 & &
cf_map - > find ( iter_payload . cf_id ) = = cf_map - > end ( ) ) {
return ;
}
Iterator * single_iter = nullptr ;
if ( iter_payload . cf_id = = 0 ) {
single_iter = ra - > db - > NewIterator ( ra - > roptions ) ;
} else {
single_iter =
ra - > db - > NewIterator ( ra - > roptions , ( * cf_map ) [ iter_payload . cf_id ] ) ;
}
single_iter - > Seek ( iter_payload . iter_key ) ;
delete single_iter ;
return ;
}
void Replayer : : BGWorkIterSeekForPrev ( void * arg ) {
std : : unique_ptr < ReplayerWorkerArg > ra (
reinterpret_cast < ReplayerWorkerArg * > ( arg ) ) ;
assert ( ra ! = nullptr ) ;
auto cf_map = static_cast < std : : unordered_map < uint32_t , ColumnFamilyHandle * > * > (
ra - > cf_map ) ;
IterPayload iter_payload ;
iter_payload . cf_id = 0 ;
if ( ra - > trace_file_version < 2 ) {
DecodeCFAndKey ( ra - > trace_entry . payload , & iter_payload . cf_id ,
& iter_payload . iter_key ) ;
} else {
TracerHelper : : DecodeIterPayload ( & ( ra - > trace_entry ) , & iter_payload ) ;
}
if ( iter_payload . cf_id > 0 & &
cf_map - > find ( iter_payload . cf_id ) = = cf_map - > end ( ) ) {
return ;
}
Iterator * single_iter = nullptr ;
if ( iter_payload . cf_id = = 0 ) {
single_iter = ra - > db - > NewIterator ( ra - > roptions ) ;
} else {
single_iter =
ra - > db - > NewIterator ( ra - > roptions , ( * cf_map ) [ iter_payload . cf_id ] ) ;
}
single_iter - > SeekForPrev ( iter_payload . iter_key ) ;
delete single_iter ;
return ;
}
void Replayer : : BGWorkMultiGet ( void * arg ) {
std : : unique_ptr < ReplayerWorkerArg > ra (
reinterpret_cast < ReplayerWorkerArg * > ( arg ) ) ;
assert ( ra ! = nullptr ) ;
auto cf_map = static_cast < std : : unordered_map < uint32_t , ColumnFamilyHandle * > * > (
ra - > cf_map ) ;
MultiGetPayload multiget_payload ;
if ( ra - > trace_file_version < 2 ) {
return ;
}
TracerHelper : : DecodeMultiGetPayload ( & ( ra - > trace_entry ) , & multiget_payload ) ;
std : : vector < ColumnFamilyHandle * > v_cfd ;
std : : vector < Slice > keys ;
if ( multiget_payload . cf_ids . size ( ) ! = multiget_payload . multiget_keys . size ( ) ) {
return ;
}
for ( size_t i = 0 ; i < multiget_payload . cf_ids . size ( ) ; i + + ) {
if ( cf_map - > find ( multiget_payload . cf_ids [ i ] ) = = cf_map - > end ( ) ) {
return ;
}
v_cfd . push_back ( ( * cf_map ) [ multiget_payload . cf_ids [ i ] ] ) ;
keys . push_back ( Slice ( multiget_payload . multiget_keys [ i ] ) ) ;
}
std : : vector < std : : string > values ;
std : : vector < Status > ss = ra - > db - > MultiGet ( ra - > roptions , v_cfd , keys , & values ) ;
return ;
}
} // namespace ROCKSDB_NAMESPACE