Ejemplo n.º 1
0
void replica::check_state_completeness()
{
    /* prepare commit durable */
    dassert(max_prepared_decree() >= last_committed_decree(), "");
    dassert(last_committed_decree() >= last_durable_decree(), "");

    auto mind = _stub->_log->max_gced_decree(get_gpid(), _app->init_info().init_offset_in_shared_log);
    dassert(mind <= last_durable_decree(), "");
    _stub->_log->check_valid_start_offset(get_gpid(), _app->init_info().init_offset_in_shared_log);

    if (_private_log != nullptr)
    {   
        auto mind = _private_log->max_gced_decree(get_gpid(), _app->init_info().init_offset_in_private_log);
        dassert(mind <= last_durable_decree(), "");
        _private_log->check_valid_start_offset(get_gpid(), _app->init_info().init_offset_in_private_log);
    }
}
Ejemplo n.º 2
0
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;
}