@ -43,17 +43,16 @@ int MemTableList::size() {
// Returns true if there is at least one memtable on which flush has
// not yet started.
bool MemTableList : : IsFlushPending ( ) {
if ( num_flush_not_started_ > 0 ) {
bool MemTableList : : IsFlushPending ( int min_write_buffer_number_to_merge ) {
if ( num_flush_not_started_ > = min_write_buffer_number_to_merge ) {
assert ( imm_flush_needed . NoBarrier_Load ( ) ! = nullptr ) ;
return true ;
}
return false ;
}
// Returns the earliest memtable that needs to be flushed.
// Returns null, if no such memtable exist.
MemTable * MemTableList : : PickMemtableToFlush ( ) {
// Returns the memtables that need to be flushed.
void MemTableList : : PickMemtablesToFlush ( std : : vector < MemTable * > * ret ) {
for ( list < MemTable * > : : reverse_iterator it = memlist_ . rbegin ( ) ;
it ! = memlist_ . rend ( ) ; it + + ) {
MemTable * m = * it ;
@ -64,37 +63,48 @@ MemTable* MemTableList::PickMemtableToFlush() {
imm_flush_needed . Release_Store ( nullptr ) ;
}
m - > flush_in_progress_ = true ; // flushing will start very soon
return m ;
ret - > push_back ( m ) ;
}
}
return nullptr ;
}
// Record a successful flush in the manifest file
Status MemTableList : : InstallMemtableFlushResults ( MemTable * m ,
Status MemTableList : : InstallMemtableFlushResults (
const std : : vector < MemTable * > & mems ,
VersionSet * vset , Status flushStatus ,
port : : Mutex * mu , Logger * info_log ,
uint64_t file_number ,
std : : set < uint64_t > & pending_outputs ) {
mu - > AssertHeld ( ) ;
assert ( m - > flush_in_progress_ ) ;
assert ( m - > file_number_ = = 0 ) ;
// If the flush was not successful, then just reset state.
// Maybe a suceeding attempt to flush will be successful.
if ( ! flushStatus . ok ( ) ) {
m - > flush_in_progress_ = false ;
m - > flush_completed_ = false ;
m - > edit_ . Clear ( ) ;
num_flush_not_started_ + + ;
imm_flush_needed . Release_Store ( ( void * ) 1 ) ;
pending_outputs . erase ( file_number ) ;
for ( MemTable * m : mems ) {
assert ( m - > flush_in_progress_ ) ;
assert ( m - > file_number_ = = 0 ) ;
m - > flush_in_progress_ = false ;
m - > flush_completed_ = false ;
m - > edit_ . Clear ( ) ;
num_flush_not_started_ + + ;
imm_flush_needed . Release_Store ( ( void * ) 1 ) ;
pending_outputs . erase ( file_number ) ;
}
return flushStatus ;
}
// flush was sucessful
m - > flush_completed_ = true ;
m - > file_number_ = file_number ;
bool first = true ;
for ( MemTable * m : mems ) {
// All the edits are associated with the first memtable of this batch.
assert ( first | | m - > GetEdits ( ) - > NumEntries ( ) = = 0 ) ;
first = false ;
m - > flush_completed_ = true ;
m - > file_number_ = file_number ;
}
// if some other thread is already commiting, then return
Status s ;
@ -106,12 +116,15 @@ Status MemTableList::InstallMemtableFlushResults(MemTable* m,
commit_in_progress_ = true ;
// scan all memtables from the earliest, and commit those
// (in that order) that have finished flushing.
while ( ! memlist_ . empty ( ) ) {
m = memlist_ . back ( ) ; // get the last element
// (in that order) that have finished flushing. Memetables
// are always committed in the order that they were created.
while ( ! memlist_ . empty ( ) & & s . ok ( ) ) {
MemTable * m = memlist_ . back ( ) ; // get the last element
if ( ! m - > flush_completed_ ) {
break ;
}
first = true ;
Log ( info_log ,
" Level-0 commit table #%llu: started " ,
( unsigned long long ) m - > file_number_ ) ;
@ -119,33 +132,39 @@ Status MemTableList::InstallMemtableFlushResults(MemTable* m,
// this can release and reacquire the mutex.
s = vset - > LogAndApply ( & m - > edit_ , mu ) ;
if ( s . ok ( ) ) { // commit new state
Log ( info_log , " Level-0 commit table #%llu: done " ,
( unsigned long long ) m - > file_number_ ) ;
memlist_ . remove ( m ) ;
assert ( m - > file_number_ > 0 ) ;
// pending_outputs can be cleared only after the newly created file
// has been written to a committed version so that other concurrently
// executing compaction threads do not mistakenly assume that this
// file is not live.
pending_outputs . erase ( m - > file_number_ ) ;
m - > Unref ( ) ;
size_ - - ;
} else {
//commit failed. setup state so that we can flush again.
Log ( info_log , " Level-0 commit table #%llu: failed " ,
( unsigned long long ) m - > file_number_ ) ;
m - > flush_completed_ = false ;
m - > flush_in_progress_ = false ;
m - > edit_ . Clear ( ) ;
num_flush_not_started_ + + ;
pending_outputs . erase ( m - > file_number_ ) ;
m - > file_number_ = 0 ;
imm_flush_needed . Release_Store ( ( void * ) 1 ) ;
s = Status : : IOError ( " Unable to commit flushed memtable " ) ;
break ;
}
// All the later memtables that have the same filenum
// are part of the same batch. They can be committed now.
do {
if ( s . ok ( ) ) { // commit new state
Log ( info_log , " Level-0 commit table #%llu: done %s " ,
( unsigned long long ) m - > file_number_ ,
first ? " " : " bulk " ) ;
memlist_ . remove ( m ) ;
assert ( m - > file_number_ > 0 ) ;
// pending_outputs can be cleared only after the newly created file
// has been written to a committed version so that other concurrently
// executing compaction threads do not mistakenly assume that this
// file is not live.
pending_outputs . erase ( m - > file_number_ ) ;
m - > Unref ( ) ;
size_ - - ;
} else {
//commit failed. setup state so that we can flush again.
Log ( info_log , " Level-0 commit table #%llu: failed " ,
( unsigned long long ) m - > file_number_ ) ;
m - > flush_completed_ = false ;
m - > flush_in_progress_ = false ;
m - > edit_ . Clear ( ) ;
num_flush_not_started_ + + ;
pending_outputs . erase ( m - > file_number_ ) ;
m - > file_number_ = 0 ;
imm_flush_needed . Release_Store ( ( void * ) 1 ) ;
s = Status : : IOError ( " Unable to commit flushed memtable " ) ;
}
first = false ;
} while ( ! memlist_ . empty ( ) & & ( m = memlist_ . back ( ) ) & &
m - > file_number_ = = file_number ) ;
}
commit_in_progress_ = false ;
return s ;