@ -90,6 +90,28 @@ std::map<std::tuple<BackgroundErrorReason, Status::Code, Status::SubCode, bool>,
Status : : Code : : kIOError , Status : : SubCode : : kIOFenced ,
false ) ,
Status : : Severity : : kFatalError } ,
// Errors during BG flush with WAL disabled
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kIOError , Status : : SubCode : : kNoSpace ,
true ) ,
Status : : Severity : : kHardError } ,
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kIOError , Status : : SubCode : : kNoSpace ,
false ) ,
Status : : Severity : : kNoError } ,
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kIOError , Status : : SubCode : : kSpaceLimit ,
true ) ,
Status : : Severity : : kHardError } ,
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kIOError , Status : : SubCode : : kIOFenced ,
true ) ,
Status : : Severity : : kFatalError } ,
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kIOError , Status : : SubCode : : kIOFenced ,
false ) ,
Status : : Severity : : kFatalError } ,
} ;
std : : map < std : : tuple < BackgroundErrorReason , Status : : Code , bool > ,
@ -140,6 +162,19 @@ std::map<std::tuple<BackgroundErrorReason, Status::Code, bool>,
{ std : : make_tuple ( BackgroundErrorReason : : kManifestWrite ,
Status : : Code : : kIOError , false ) ,
Status : : Severity : : kFatalError } ,
// Errors during BG flush with WAL disabled
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kCorruption , true ) ,
Status : : Severity : : kUnrecoverableError } ,
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kCorruption , false ) ,
Status : : Severity : : kNoError } ,
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kIOError , true ) ,
Status : : Severity : : kFatalError } ,
{ std : : make_tuple ( BackgroundErrorReason : : kFlushNoWAL ,
Status : : Code : : kIOError , false ) ,
Status : : Severity : : kNoError } ,
} ;
std : : map < std : : tuple < BackgroundErrorReason , bool > , Status : : Severity >
@ -218,6 +253,7 @@ Status ErrorHandler::SetBGError(const Status& bg_err, BackgroundErrorReason reas
bool paranoid = db_options_ . paranoid_checks ;
Status : : Severity sev = Status : : Severity : : kFatalError ;
Status new_bg_err ;
DBRecoverContext context ;
bool found = false ;
{
@ -276,6 +312,7 @@ Status ErrorHandler::SetBGError(const Status& bg_err, BackgroundErrorReason reas
}
}
recover_context_ = context ;
if ( auto_recovery ) {
recovery_in_prog_ = true ;
@ -303,8 +340,10 @@ Status ErrorHandler::SetBGError(const IOStatus& bg_io_err,
// Always returns ok
db_ - > DisableFileDeletionsWithLock ( ) ;
}
Status new_bg_io_err = bg_io_err ;
Status s ;
DBRecoverContext context ;
if ( bg_io_err . GetDataLoss ( ) ) {
// FIrst, data loss is treated as unrecoverable error. So it can directly
// overwrite any existing bg_error_.
@ -316,6 +355,7 @@ Status ErrorHandler::SetBGError(const IOStatus& bg_io_err,
}
EventHelpers : : NotifyOnBackgroundError ( db_options_ . listeners , reason , & s ,
db_mutex_ , & auto_recovery ) ;
recover_context_ = context ;
return bg_error_ ;
} else if ( bg_io_err . GetRetryable ( ) ) {
// Second, check if the error is a retryable IO error or not. if it is
@ -332,7 +372,27 @@ Status ErrorHandler::SetBGError(const IOStatus& bg_io_err,
if ( bg_err . severity ( ) > bg_error_ . severity ( ) ) {
bg_error_ = bg_err ;
}
recover_context_ = context ;
return bg_error_ ;
} else if ( BackgroundErrorReason : : kFlushNoWAL = = reason ) {
// When the BG Retryable IO error reason is flush without WAL,
// We map it to a soft error. At the same time, all the background work
// should be stopped except the BG work from recovery. Therefore, we
// set the soft_error_no_bg_work_ to true. At the same time, since DB
// continues to receive writes when BG error is soft error, to avoid
// to many small memtable being generated during auto resume, the flush
// reason is set to kErrorRecoveryRetryFlush.
Status bg_err ( new_bg_io_err , Status : : Severity : : kSoftError ) ;
if ( recovery_in_prog_ & & recovery_error_ . ok ( ) ) {
recovery_error_ = bg_err ;
}
if ( bg_err . severity ( ) > bg_error_ . severity ( ) ) {
bg_error_ = bg_err ;
}
soft_error_no_bg_work_ = true ;
context . flush_reason = FlushReason : : kErrorRecoveryRetryFlush ;
recover_context_ = context ;
return StartRecoverFromRetryableBGIOError ( bg_io_err ) ;
} else {
Status bg_err ( new_bg_io_err , Status : : Severity : : kHardError ) ;
if ( recovery_in_prog_ & & recovery_error_ . ok ( ) ) {
@ -341,6 +401,7 @@ Status ErrorHandler::SetBGError(const IOStatus& bg_io_err,
if ( bg_err . severity ( ) > bg_error_ . severity ( ) ) {
bg_error_ = bg_err ;
}
recover_context_ = context ;
return StartRecoverFromRetryableBGIOError ( bg_io_err ) ;
}
} else {
@ -407,6 +468,7 @@ Status ErrorHandler::ClearBGError() {
Status old_bg_error = bg_error_ ;
bg_error_ = Status : : OK ( ) ;
recovery_in_prog_ = false ;
soft_error_no_bg_work_ = false ;
EventHelpers : : NotifyOnErrorRecoveryCompleted ( db_options_ . listeners ,
old_bg_error , db_mutex_ ) ;
}
@ -419,6 +481,7 @@ Status ErrorHandler::ClearBGError() {
Status ErrorHandler : : RecoverFromBGError ( bool is_manual ) {
# ifndef ROCKSDB_LITE
InstrumentedMutexLock l ( db_mutex_ ) ;
bool no_bg_work_original_flag = soft_error_no_bg_work_ ;
if ( is_manual ) {
// If its a manual recovery and there's a background recovery in progress
// return busy status
@ -426,9 +489,24 @@ Status ErrorHandler::RecoverFromBGError(bool is_manual) {
return Status : : Busy ( ) ;
}
recovery_in_prog_ = true ;
// In manual resume, we allow the bg work to run. If it is a auto resume,
// the bg work should follow this tag.
soft_error_no_bg_work_ = false ;
// In manual resume, if the bg error is a soft error and also requires
// no bg work, the error must be recovered by call the flush with
// flush reason: kErrorRecoveryRetryFlush. In other case, the flush
// reason is set to kErrorRecovery.
if ( no_bg_work_original_flag ) {
recover_context_ . flush_reason = FlushReason : : kErrorRecoveryRetryFlush ;
} else {
recover_context_ . flush_reason = FlushReason : : kErrorRecovery ;
}
}
if ( bg_error_ . severity ( ) = = Status : : Severity : : kSoftError ) {
if ( bg_error_ . severity ( ) = = Status : : Severity : : kSoftError & &
recover_context_ . flush_reason = = FlushReason : : kErrorRecovery ) {
// Simply clear the background error and return
recovery_error_ = Status : : OK ( ) ;
return ClearBGError ( ) ;
@ -438,7 +516,13 @@ Status ErrorHandler::RecoverFromBGError(bool is_manual) {
// during the recovery process. While recovering, the only operations that
// can generate background errors should be the flush operations
recovery_error_ = Status : : OK ( ) ;
Status s = db_ - > ResumeImpl ( ) ;
Status s = db_ - > ResumeImpl ( recover_context_ ) ;
if ( s . ok ( ) ) {
soft_error_no_bg_work_ = false ;
} else {
soft_error_no_bg_work_ = no_bg_work_original_flag ;
}
// For manual recover, shutdown, and fatal error cases, set
// recovery_in_prog_ to false. For automatic background recovery, leave it
// as is regardless of success or failure as it will be retried
@ -491,6 +575,7 @@ void ErrorHandler::RecoverFromRetryableBGIOError() {
if ( end_recovery_ ) {
return ;
}
DBRecoverContext context = recover_context_ ;
int resume_count = db_options_ . max_bgerror_resume_count ;
uint64_t wait_interval = db_options_ . bgerror_resume_retry_interval ;
// Recover from the retryable error. Create a separate thread to do it.
@ -502,7 +587,7 @@ void ErrorHandler::RecoverFromRetryableBGIOError() {
TEST_SYNC_POINT ( " RecoverFromRetryableBGIOError:BeforeResume1 " ) ;
recovery_io_error_ = IOStatus : : OK ( ) ;
recovery_error_ = Status : : OK ( ) ;
Status s = db_ - > ResumeImpl ( ) ;
Status s = db_ - > ResumeImpl ( context ) ;
TEST_SYNC_POINT ( " RecoverFromRetryableBGIOError:AfterResume0 " ) ;
TEST_SYNC_POINT ( " RecoverFromRetryableBGIOError:AfterResume1 " ) ;
if ( s . IsShutdownInProgress ( ) | |
@ -537,6 +622,9 @@ void ErrorHandler::RecoverFromRetryableBGIOError() {
EventHelpers : : NotifyOnErrorRecoveryCompleted ( db_options_ . listeners ,
old_bg_error , db_mutex_ ) ;
recovery_in_prog_ = false ;
if ( soft_error_no_bg_work_ ) {
soft_error_no_bg_work_ = false ;
}
return ;
} else {
TEST_SYNC_POINT ( " RecoverFromRetryableBGIOError:RecoverFail1 " ) ;