void replica::close() { if (status() != PS_INACTIVE && status() != PS_ERROR) { update_local_configuration_with_no_ballot_change(PS_INACTIVE); } cleanup_preparing_mutations(true); _primary_states.cleanup(); _potential_secondary_states.cleanup(true); if (_app != nullptr) { _app->close(false); } }
void replica::close() { dassert( status() == partition_status::PS_ERROR || status() == partition_status::PS_INACTIVE, "%s: invalid state %s when calling replica::close", name(), enum_to_string(status()) ); if (nullptr != _checkpoint_timer) { _checkpoint_timer->cancel(true); _checkpoint_timer = nullptr; } cleanup_preparing_mutations(true); dassert(_primary_states.is_cleaned(), "primary context is not cleared"); if (partition_status::PS_INACTIVE == status()) { dassert(_secondary_states.is_cleaned(), "secondary context is not cleared"); dassert(_potential_secondary_states.is_cleaned(), "potential secondary context is not cleared"); } // for partition_status::PS_ERROR, context cleanup is done here as they may block else { bool r = _secondary_states.cleanup(true); dassert(r, "secondary context is not cleared"); r = _potential_secondary_states.cleanup(true); dassert(r, "potential secondary context is not cleared"); } if (_private_log != nullptr) { _private_log->close(); _private_log = nullptr; } if (_app != nullptr) { _app->close(false); } }
bool replica::update_local_configuration(const replica_configuration& config, bool same_ballot/* = false*/) { dassert(config.ballot > get_ballot() || (same_ballot && config.ballot == get_ballot()), ""); dassert (config.gpid == get_gpid(), ""); partition_status old_status = status(); ballot old_ballot = get_ballot(); // skip unncessary configuration change if (old_status == config.status && old_ballot == config.ballot) return true; // skip invalid change switch (old_status) { case PS_ERROR: { ddebug( "%s: status change from %s @ %lld to %s @ %lld is not allowed", name(), enum_to_string(old_status), old_ballot, enum_to_string(config.status), config.ballot ); return false; } break; case PS_INACTIVE: if ((config.status == PS_PRIMARY || config.status == PS_SECONDARY) && !_inactive_is_transient) { ddebug( "%s: status change from %s @ %lld to %s @ %lld is not allowed when inactive state is not transient", name(), enum_to_string(old_status), old_ballot, enum_to_string(config.status), config.ballot ); return false; } break; case PS_POTENTIAL_SECONDARY: if (config.status == PS_ERROR || config.status == PS_INACTIVE) { if (!_potential_secondary_states.cleanup(false)) { dwarn( "%s: status change from %s @ %lld to %s @ %lld is not allowed coz learning remote state is still running", name(), enum_to_string(old_status), old_ballot, enum_to_string(config.status), config.ballot ); return false; } } break; case PS_SECONDARY: if (config.status != PS_SECONDARY && _secondary_states.checkpoint_task != nullptr) { dwarn( "%s: status change from %s @ %lld to %s @ %lld is not allowed coz checkpointing is still running", name(), enum_to_string(old_status), old_ballot, enum_to_string(config.status), config.ballot ); return false; } break; } uint64_t oldTs = _last_config_change_time_ms; _config = config; _last_config_change_time_ms =now_ms(); dassert (max_prepared_decree() >= last_committed_decree(), ""); switch (old_status) { case PS_PRIMARY: cleanup_preparing_mutations(true); switch (config.status) { case PS_PRIMARY: replay_prepare_list(); break; case PS_INACTIVE: _primary_states.cleanup(old_ballot != config.ballot); break; case PS_SECONDARY: case PS_ERROR: _primary_states.cleanup(); break; case PS_POTENTIAL_SECONDARY: dassert (false, "invalid execution path"); break; default: dassert (false, "invalid execution path"); } break; case PS_SECONDARY: cleanup_preparing_mutations(true); switch (config.status) { case PS_PRIMARY: init_group_check(); replay_prepare_list(); break; case PS_SECONDARY: break; case PS_POTENTIAL_SECONDARY: // InActive in config break; case PS_INACTIVE: break; case PS_ERROR: break; default: dassert (false, "invalid execution path"); } break; case PS_POTENTIAL_SECONDARY: switch (config.status) { case PS_PRIMARY: dassert (false, "invalid execution path"); break; case PS_SECONDARY: _prepare_list->truncate(_app->last_committed_decree()); _potential_secondary_states.cleanup(true); check_state_completeness(); break; case PS_POTENTIAL_SECONDARY: break; case PS_INACTIVE: _potential_secondary_states.cleanup(true); break; case PS_ERROR: _prepare_list->reset(_app->last_committed_decree()); _potential_secondary_states.cleanup(true); break; default: dassert (false, "invalid execution path"); } break; case PS_INACTIVE: switch (config.status) { case PS_PRIMARY: _inactive_is_transient = false; init_group_check(); replay_prepare_list(); break; case PS_SECONDARY: _inactive_is_transient = false; break; case PS_POTENTIAL_SECONDARY: _inactive_is_transient = false; break; case PS_INACTIVE: break; case PS_ERROR: _inactive_is_transient = false; break; default: dassert (false, "invalid execution path"); } break; case PS_ERROR: switch (config.status) { case PS_PRIMARY: dassert (false, "invalid execution path"); break; case PS_SECONDARY: dassert (false, "invalid execution path"); break; case PS_POTENTIAL_SECONDARY: dassert(false, "invalid execution path"); break; case PS_INACTIVE: dassert (false, "invalid execution path"); break; case PS_ERROR: break; default: dassert (false, "invalid execution path"); } break; default: dassert (false, "invalid execution path"); } dwarn( "%s: status change %s @ %lld => %s @ %lld, pre(%llu, %llu), app(%llu, %llu), duration=%llu ms", name(), enum_to_string(old_status), old_ballot, enum_to_string(status()), get_ballot(), _prepare_list->max_decree(), _prepare_list->last_committed_decree(), _app->last_committed_decree(), _app->last_durable_decree(), _last_config_change_time_ms - oldTs ); if (status() != old_status) { bool isClosing = (status() == PS_ERROR || (status() == PS_INACTIVE && get_ballot() > old_ballot)); _stub->notify_replica_state_update(config, isClosing); if (isClosing) { ddebug("%s: being close ...", name()); _stub->begin_close_replica(this); return false; } } else { _stub->notify_replica_state_update(config, false); } return true; }