void replica::replay_prepare_list() { decree start = last_committed_decree() + 1; decree end = _prepare_list->max_decree(); ddebug( "%s: replay prepare list from %lld to %lld, ballot = %lld", name(), start, end, get_ballot() ); for (decree decree = start; decree <= end; decree++) { mutation_ptr old = _prepare_list->get_mutation_by_decree(decree); mutation_ptr mu = new_mutation(decree); if (old != nullptr) { mu->copy_from(old); } else { mu->rpc_code = RPC_REPLICATION_WRITE_EMPTY; ddebug( "%s: emit empty mutation %lld when replay prepare list", name(), decree ); } init_prepare(mu); } }
void prepare_grammar () { warning ("preparing rules for codegeneration..."); init_prepare (); prepare_rules (); warning ("preparing meta rules for codegeneration..."); prepare_meta_rules (); };
void replica::on_client_write(int code, dsn_message_t request) { check_hashed_access(); if (PS_PRIMARY != status()) { response_client_message(request, ERR_INVALID_STATE); return; } mutation_ptr mu = new_mutation(_prepare_list->max_decree() + 1); mu->set_client_request(code, request); init_prepare(mu); }
void replica::on_client_write(int code, dsn_message_t request) { check_hashed_access(); if (PS_PRIMARY != status()) { response_client_message(request, ERR_INVALID_STATE); return; } auto mu = _primary_states.write_queue.add_work(code, request, this); if (mu) { init_prepare(mu); } }
void replica::on_client_write(task_code code, dsn_message_t request) { check_hashed_access(); if (PS_PRIMARY != status()) { response_client_message(request, ERR_INVALID_STATE); return; } if (static_cast<int>(_primary_states.membership.secondaries.size()) + 1 < _options->mutation_2pc_min_replica_count) { response_client_message(request, ERR_NOT_ENOUGH_MEMBER); return; } auto mu = _primary_states.write_queue.add_work(code, request, this); if (mu) { init_prepare(mu); } }
void replica::broadcast_group_check() { dassert (nullptr != _primary_states.group_check_task, ""); ddebug("%s: start to broadcast group check", name()); if (_primary_states.group_check_pending_replies.size() > 0) { dwarn( "%s: %u group check replies are still pending when doing next round check, cancel first", name(), static_cast<int>(_primary_states.group_check_pending_replies.size()) ); for (auto it = _primary_states.group_check_pending_replies.begin(); it != _primary_states.group_check_pending_replies.end(); ++it) { it->second->cancel(true); } _primary_states.group_check_pending_replies.clear(); } for (auto it = _primary_states.statuses.begin(); it != _primary_states.statuses.end(); ++it) { if (it->first == _stub->_primary_address) continue; ::dsn::rpc_address addr = it->first; std::shared_ptr<group_check_request> request(new group_check_request); request->app = _app_info; request->node = addr; _primary_states.get_replica_config(it->second, request->config); request->last_committed_decree = last_committed_decree(); if (request->config.status == partition_status::PS_POTENTIAL_SECONDARY) { auto it = _primary_states.learners.find(addr); dassert(it != _primary_states.learners.end(), "learner %s is missing", addr.to_string()); request->config.learner_signature = it->second.signature; } ddebug( "%s: send group check to %s with state %s", name(), addr.to_string(), enum_to_string(it->second) ); dsn::task_ptr callback_task = rpc::call( addr, RPC_GROUP_CHECK, *request, this, [=](error_code err, group_check_response&& resp) { auto alloc = std::make_shared<group_check_response>(std::move(resp)); on_group_check_reply(err, request, alloc); }, std::chrono::milliseconds(0), gpid_to_thread_hash(get_gpid()) ); _primary_states.group_check_pending_replies[addr] = callback_task; } // send empty prepare when necessary if (!_options->empty_write_disabled && dsn_now_ms() >= _primary_states.last_prepare_ts_ms + _options->group_check_interval_ms) { mutation_ptr mu = new_mutation(invalid_decree); mu->add_client_request(RPC_REPLICATION_WRITE_EMPTY, nullptr); init_prepare(mu); } }
void replica::execute_mutation(mutation_ptr& mu) { dinfo("%s: execute mutation %s: request_count = %u", name(), mu->name(), static_cast<int>(mu->client_requests.size()) ); error_code err = ERR_OK; decree d = mu->data.header.decree; switch (status()) { case partition_status::PS_INACTIVE: if (_app->last_committed_decree() + 1 == d) { err = _app->write_internal(mu); } else { ddebug( "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64, name(), mu->name(), enum_to_string(status()), _app->last_committed_decree() ); } break; case partition_status::PS_PRIMARY: { check_state_completeness(); dassert(_app->last_committed_decree() + 1 == d, ""); err = _app->write_internal(mu); } break; case partition_status::PS_SECONDARY: if (!_secondary_states.checkpoint_is_running) { check_state_completeness(); dassert (_app->last_committed_decree() + 1 == d, ""); err = _app->write_internal(mu); } else { ddebug( "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64, name(), mu->name(), enum_to_string(status()), _app->last_committed_decree() ); // make sure private log saves the state // catch-up will be done later after checkpoint task is fininished dassert(_private_log != nullptr, ""); } break; case partition_status::PS_POTENTIAL_SECONDARY: if (_potential_secondary_states.learning_status == learner_status::LearningSucceeded || _potential_secondary_states.learning_status == learner_status::LearningWithPrepareTransient) { dassert(_app->last_committed_decree() + 1 == d, ""); err = _app->write_internal(mu); } else { // prepare also happens with learner_status::LearningWithPrepare, in this case // make sure private log saves the state, // catch-up will be done later after the checkpoint task is finished ddebug( "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64, name(), mu->name(), enum_to_string(status()), _app->last_committed_decree() ); } break; case partition_status::PS_ERROR: break; } ddebug("TwoPhaseCommit, %s: mutation %s committed, err = %s", name(), mu->name(), err.to_string()); _counter_commit_latency.set(dsn_now_ns() - mu->create_ts_ns()); if (err != ERR_OK) { handle_local_failure(err); } if (status() == partition_status::PS_PRIMARY) { mutation_ptr next = _primary_states.write_queue.check_possible_work( static_cast<int>(_prepare_list->max_decree() - d) ); if (next) { init_prepare(next); } } }