@ -216,6 +216,9 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
CompactionIteratorTest ( )
: cmp_ ( BytewiseComparator ( ) ) , icmp_ ( cmp_ ) , snapshots_ ( { } ) { }
explicit CompactionIteratorTest ( const Comparator * ucmp )
: cmp_ ( ucmp ) , icmp_ ( cmp_ ) , snapshots_ ( { } ) { }
void InitIterators (
const std : : vector < std : : string > & ks , const std : : vector < std : : string > & vs ,
const std : : vector < std : : string > & range_del_ks ,
@ -224,7 +227,9 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
SequenceNumber last_committed_sequence = kMaxSequenceNumber ,
MergeOperator * merge_op = nullptr , CompactionFilter * filter = nullptr ,
bool bottommost_level = false ,
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber ) {
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber ,
bool key_not_exists_beyond_output_level = false ,
const std : : string * full_history_ts_low = nullptr ) {
std : : unique_ptr < InternalIterator > unfragmented_range_del_iter (
new test : : VectorIterator ( range_del_ks , range_del_vs ) ) ;
auto tombstone_list = std : : make_shared < FragmentedRangeTombstoneList > (
@ -236,10 +241,12 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
range_del_agg_ - > AddTombstones ( std : : move ( range_del_iter ) ) ;
std : : unique_ptr < CompactionIterator : : CompactionProxy > compaction ;
if ( filter | | bottommost_level ) {
if ( filter | | bottommost_level | | key_not_exists_beyond_output_level ) {
compaction_proxy_ = new FakeCompaction ( ) ;
compaction_proxy_ - > is_bottommost_level = bottommost_level ;
compaction_proxy_ - > is_allow_ingest_behind = AllowIngestBehind ( ) ;
compaction_proxy_ - > key_not_exists_beyond_output_level =
key_not_exists_beyond_output_level ;
compaction . reset ( compaction_proxy_ ) ;
}
bool use_snapshot_checker = UseSnapshotChecker ( ) | | GetParam ( ) ;
@ -252,6 +259,11 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
0 /*latest_snapshot*/ , snapshot_checker_ . get ( ) ,
0 /*level*/ , nullptr /*statistics*/ , & shutting_down_ ) ) ;
if ( c_iter_ ) {
// Since iter_ is still used in ~CompactionIterator(), we call
// ~CompactionIterator() first.
c_iter_ . reset ( ) ;
}
iter_ . reset ( new LoggingForwardVectorIterator ( ks , vs ) ) ;
iter_ - > SeekToFirst ( ) ;
c_iter_ . reset ( new CompactionIterator (
@ -260,7 +272,9 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
Env : : Default ( ) , false /* report_detailed_time */ , false ,
range_del_agg_ . get ( ) , nullptr /* blob_file_builder */ ,
false /*allow_data_in_errors*/ , std : : move ( compaction ) , filter ,
& shutting_down_ ) ) ;
& shutting_down_ , /*preserve_deletes_seqnum=*/ 0 ,
/*manual_compaction_paused=*/ nullptr , /*info_log=*/ nullptr ,
full_history_ts_low ) ) ;
}
void AddSnapshot ( SequenceNumber snapshot ,
@ -282,10 +296,13 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
MergeOperator * merge_operator = nullptr ,
CompactionFilter * compaction_filter = nullptr ,
bool bottommost_level = false ,
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber ) {
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber ,
bool key_not_exists_beyond_output_level = false ,
const std : : string * full_history_ts_low = nullptr ) {
InitIterators ( input_keys , input_values , { } , { } , kMaxSequenceNumber ,
last_committed_seq , merge_operator , compaction_filter ,
bottommost_level , earliest_write_conflict_snapshot ) ;
bottommost_level , earliest_write_conflict_snapshot ,
key_not_exists_beyond_output_level , full_history_ts_low ) ;
c_iter_ - > SeekToFirst ( ) ;
for ( size_t i = 0 ; i < expected_keys . size ( ) ; i + + ) {
std : : string info = " i = " + ToString ( i ) ;
@ -299,6 +316,11 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
ASSERT_FALSE ( c_iter_ - > Valid ( ) ) ;
}
void ClearSnapshots ( ) {
snapshots_ . clear ( ) ;
snapshot_map_ . clear ( ) ;
}
const Comparator * cmp_ ;
const InternalKeyComparator icmp_ ;
std : : vector < SequenceNumber > snapshots_ ;
@ -1033,6 +1055,185 @@ INSTANTIATE_TEST_CASE_P(CompactionIteratorWithAllowIngestBehindTestInstance,
CompactionIteratorWithAllowIngestBehindTest ,
testing : : Values ( true , false ) ) ;
class CompactionIteratorTsGcTest : public CompactionIteratorTest {
public :
CompactionIteratorTsGcTest ( )
: CompactionIteratorTest ( test : : ComparatorWithU64Ts ( ) ) { }
} ;
TEST_P ( CompactionIteratorTsGcTest , NoKeyEligibleForGC ) {
constexpr char user_key [ ] = " a " ;
const std : : vector < std : : string > input_keys = {
test : : KeyStr ( /*ts=*/ 103 , user_key , /*seq=*/ 4 , kTypeValue ) ,
test : : KeyStr ( /*ts=*/ 102 , user_key , /*seq=*/ 3 ,
kTypeDeletionWithTimestamp ) } ;
const std : : vector < std : : string > input_values = { " a3 " , " " } ;
std : : string full_history_ts_low ;
// All keys' timestamps are newer than or equal to 102, thus none of them
// will be eligible for GC.
PutFixed64 ( & full_history_ts_low , 102 ) ;
const std : : vector < std : : string > & expected_keys = input_keys ;
const std : : vector < std : : string > & expected_values = input_values ;
const std : : vector < std : : pair < bool , bool > > params = {
{ false , false } , { false , true } , { true , true } } ;
for ( const std : : pair < bool , bool > & param : params ) {
const bool bottommost_level = param . first ;
const bool key_not_exists_beyond_output_level = param . second ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_seq=*/ kMaxSequenceNumber ,
/*merge_operator=*/ nullptr , /*compaction_filter=*/ nullptr ,
bottommost_level ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
key_not_exists_beyond_output_level , & full_history_ts_low ) ;
}
}
TEST_P ( CompactionIteratorTsGcTest , AllKeysOlderThanThreshold ) {
constexpr char user_key [ ] = " a " ;
const std : : vector < std : : string > input_keys = {
test : : KeyStr ( /*ts=*/ 103 , user_key , /*seq=*/ 4 , kTypeDeletionWithTimestamp ) ,
test : : KeyStr ( /*ts=*/ 102 , user_key , /*seq=*/ 3 , kTypeValue ) ,
test : : KeyStr ( /*ts=*/ 101 , user_key , /*seq=*/ 2 , kTypeValue ) } ;
const std : : vector < std : : string > input_values = { " " , " a2 " , " a1 " } ;
std : : string full_history_ts_low ;
// All keys' timestamps are older than 104.
PutFixed64 ( & full_history_ts_low , 104 ) ;
{
// With a snapshot at seq 3, both the deletion marker and the key at 3 must
// be preserved.
AddSnapshot ( 3 ) ;
const std : : vector < std : : string > expected_keys = { input_keys [ 0 ] ,
input_keys [ 1 ] } ;
const std : : vector < std : : string > expected_values = { " " , " a2 " } ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_seq=*/ kMaxSequenceNumber ,
/*merge_operator=*/ nullptr , /*compaction_filter=*/ nullptr ,
/*bottommost_level=*/ false ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
/*key_not_exists_beyond_output_level=*/ false , & full_history_ts_low ) ;
ClearSnapshots ( ) ;
}
{
// No snapshot, the deletion marker should be preserved because the user
// key may appear beyond output level.
const std : : vector < std : : string > expected_keys = { input_keys [ 0 ] } ;
const std : : vector < std : : string > expected_values = { " " } ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_seq=*/ kMaxSequenceNumber ,
/*merge_operator=*/ nullptr , /*compaction_filter=*/ nullptr ,
/*bottommost_level=*/ false ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
/*key_not_exists_beyond_output_level=*/ false , & full_history_ts_low ) ;
}
{
// No snapshot, the deletion marker can be dropped because the user key
// does not appear in higher levels.
const std : : vector < std : : string > expected_keys = { } ;
const std : : vector < std : : string > expected_values = { } ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_seq=*/ kMaxSequenceNumber ,
/*merge_operator=*/ nullptr , /*compaction_filter=*/ nullptr ,
/*bottommost_level=*/ false ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
/*key_not_exists_beyond_output_level=*/ true , & full_history_ts_low ) ;
}
}
TEST_P ( CompactionIteratorTsGcTest , NewHidesOldSameSnapshot ) {
constexpr char user_key [ ] = " a " ;
const std : : vector < std : : string > input_keys = {
test : : KeyStr ( /*ts=*/ 103 , user_key , /*seq=*/ 4 , kTypeDeletionWithTimestamp ) ,
test : : KeyStr ( /*ts=*/ 102 , user_key , /*seq=*/ 3 , kTypeValue ) ,
test : : KeyStr ( /*ts=*/ 101 , user_key , /*seq=*/ 2 , kTypeValue ) ,
test : : KeyStr ( /*ts=*/ 100 , user_key , /*seq=*/ 1 , kTypeValue ) } ;
const std : : vector < std : : string > input_values = { " " , " a2 " , " a1 " , " a0 " } ;
{
std : : string full_history_ts_low ;
// Keys whose timestamps larger than or equal to 102 will be preserved.
PutFixed64 ( & full_history_ts_low , 102 ) ;
const std : : vector < std : : string > expected_keys = { input_keys [ 0 ] ,
input_keys [ 1 ] } ;
const std : : vector < std : : string > expected_values = { " " , " a2 " } ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_seq=*/ kMaxSequenceNumber ,
/*merge_operator=*/ nullptr , /*compaction_filter=*/ nullptr ,
/*bottommost_level=*/ false ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
/*key_not_exists_beyond_output_level=*/ false , & full_history_ts_low ) ;
}
}
TEST_P ( CompactionIteratorTsGcTest , DropTombstones ) {
constexpr char user_key [ ] = " a " ;
const std : : vector < std : : string > input_keys = {
test : : KeyStr ( /*ts=*/ 103 , user_key , /*seq=*/ 4 , kTypeDeletionWithTimestamp ) ,
test : : KeyStr ( /*ts=*/ 102 , user_key , /*seq=*/ 3 , kTypeValue ) ,
test : : KeyStr ( /*ts=*/ 101 , user_key , /*seq=*/ 2 , kTypeDeletionWithTimestamp ) ,
test : : KeyStr ( /*ts=*/ 100 , user_key , /*seq=*/ 1 , kTypeValue ) } ;
const std : : vector < std : : string > input_values = { " " , " a2 " , " " , " a0 " } ;
const std : : vector < std : : string > expected_keys = { input_keys [ 0 ] , input_keys [ 1 ] } ;
const std : : vector < std : : string > expected_values = { " " , " a2 " } ;
// Take a snapshot at seq 2.
AddSnapshot ( 2 ) ;
{
// Non-bottommost level, but key does not exist beyond output level.
std : : string full_history_ts_low ;
PutFixed64 ( & full_history_ts_low , 102 ) ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_sequence=*/ kMaxSequenceNumber ,
/*merge_op=*/ nullptr , /*compaction_filter=*/ nullptr ,
/*bottommost_level=*/ false ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
/*key_not_exists_beyond_output_level=*/ true , & full_history_ts_low ) ;
}
{
// Bottommost level
std : : string full_history_ts_low ;
PutFixed64 ( & full_history_ts_low , 102 ) ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_seq=*/ kMaxSequenceNumber ,
/*merge_operator=*/ nullptr , /*compaction_filter=*/ nullptr ,
/*bottommost_level=*/ true ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
/*key_not_exists_beyond_output_level=*/ false , & full_history_ts_low ) ;
}
}
TEST_P ( CompactionIteratorTsGcTest , RewriteTs ) {
constexpr char user_key [ ] = " a " ;
const std : : vector < std : : string > input_keys = {
test : : KeyStr ( /*ts=*/ 103 , user_key , /*seq=*/ 4 , kTypeDeletionWithTimestamp ) ,
test : : KeyStr ( /*ts=*/ 102 , user_key , /*seq=*/ 3 , kTypeValue ) ,
test : : KeyStr ( /*ts=*/ 101 , user_key , /*seq=*/ 2 , kTypeDeletionWithTimestamp ) ,
test : : KeyStr ( /*ts=*/ 100 , user_key , /*seq=*/ 1 , kTypeValue ) } ;
const std : : vector < std : : string > input_values = { " " , " a2 " , " " , " a0 " } ;
const std : : vector < std : : string > expected_keys = {
input_keys [ 0 ] , input_keys [ 1 ] , input_keys [ 2 ] ,
test : : KeyStr ( /*ts=*/ 0 , user_key , /*seq=*/ 0 , kTypeValue ) } ;
const std : : vector < std : : string > expected_values = { " " , " a2 " , " " , " a0 " } ;
AddSnapshot ( 1 ) ;
AddSnapshot ( 2 ) ;
{
// Bottommost level and need to rewrite both ts and seq.
std : : string full_history_ts_low ;
PutFixed64 ( & full_history_ts_low , 102 ) ;
RunTest ( input_keys , input_values , expected_keys , expected_values ,
/*last_committed_seq=*/ kMaxSequenceNumber ,
/*merge_operator=*/ nullptr , /*compaction_filter=*/ nullptr ,
/*bottommost_level=*/ true ,
/*earliest_write_conflict_snapshot=*/ kMaxSequenceNumber ,
/*key_not_exists_beyond_output_level=*/ true , & full_history_ts_low ) ;
}
}
INSTANTIATE_TEST_CASE_P ( CompactionIteratorTsGcTestInstance ,
CompactionIteratorTsGcTest ,
testing : : Values ( true , false ) ) ;
} // namespace ROCKSDB_NAMESPACE
int main ( int argc , char * * argv ) {