void finish(int r) override {
assert(r >= 0);
Mutex::Locker l(paxos->mon->lock);
+ if (paxos->is_shutdown()) {
+ paxos->abort_commit();
+ return;
+ }
paxos->commit_finish();
}
};
+void Paxos::abort_commit()
+{
+ assert(commits_started > 0);
+ --commits_started;
+ if (commits_started == 0)
+ shutdown_cond.Signal();
+}
+
void Paxos::commit_start()
{
dout(10) << __func__ << " " << (last_committed+1) << dendl;
state = STATE_WRITING;
else
ceph_abort();
+ ++commits_started;
if (mon->get_quorum().size() > 1) {
// cancel timeout event
// it doesn't need to flush the store queue
assert(is_writing() || is_writing_previous());
state = STATE_REFRESH;
+ assert(commits_started > 0);
+ --commits_started;
if (do_refresh()) {
commit_proposal();
{
dout(10) << __func__ << " cancel all contexts" << dendl;
+ state = STATE_SHUTDOWN;
+
// discard pending transaction
pending_proposal.reset();
+ // Let store finish commits in progress
+ // XXX: I assume I can't use finish_contexts() because the store
+ // is going to trigger
+ while(commits_started > 0)
+ shutdown_cond.Wait(mon->lock);
+
finish_contexts(g_ceph_context, waiting_for_writeable, -ECANCELED);
finish_contexts(g_ceph_context, waiting_for_commit, -ECANCELED);
finish_contexts(g_ceph_context, waiting_for_readable, -ECANCELED);
STATE_WRITING_PREVIOUS,
// leader: refresh following a commit
STATE_REFRESH,
+ // Shutdown after WRITING or WRITING_PREVIOUS
+ STATE_SHUTDOWN
};
/**
return "writing-previous";
case STATE_REFRESH:
return "refresh";
+ case STATE_SHUTDOWN:
+ return "shutdown";
default:
return "UNKNOWN";
}
/**
* @}
*/
+ int commits_started = 0;
+
+ Cond shutdown_cond;
public:
/**
/// @return 'true' if we are refreshing an update just committed
bool is_refresh() const { return state == STATE_REFRESH; }
+ /// @return 'true' if we are in the process of shutting down
+ bool is_shutdown() const { return state == STATE_SHUTDOWN; }
+
private:
/**
* @defgroup Paxos_h_recovery_vars Common recovery-related member variables
*/
void commit_start();
void commit_finish(); ///< finish a commit after txn becomes durable
+ void abort_commit(); ///< Handle commit finish after shutdown started
/**
* Commit the new value to stable storage as being the latest available
* version.