-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Start instrumenting existing code with state machines #678
Changes from all commits
9f0f195
7afa477
62380b1
5db84c2
96f9759
05c4891
65032c8
24cb351
fde8bbe
51f4baa
ccf87e2
be2f9d3
c20e79b
cb93894
51ee710
c90a011
1ebee4b
fa3f0b4
11665b2
bc7a5ec
2c2ce8b
66a2cd1
19f455b
633f471
07ed5b9
33a4a24
85e494d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,13 +54,15 @@ void sm_init(struct sm *m, | |
|
||
PRE(conf[state].flags & SM_INITIAL); | ||
|
||
m->conf = conf; | ||
m->state = state; | ||
m->invariant = invariant; | ||
m->is_locked = is_locked; | ||
m->id = ++id; | ||
m->pid = getpid(); | ||
m->rc = 0; | ||
*m = (struct sm){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks cool as it's easier to grep out initialization with |
||
.conf = conf, | ||
.state = state, | ||
.invariant = invariant, | ||
.is_locked = is_locked, | ||
.id = ++id, | ||
.pid = getpid(), | ||
.rc = 0, | ||
}; | ||
snprintf(m->name, SM_MAX_NAME_LENGTH, "%s", name); | ||
sm_obs(m); | ||
|
||
|
@@ -98,6 +100,22 @@ void sm_fail(struct sm *m, int fail_state, int rc) | |
POST(m->invariant != NULL && m->invariant(m, prev)); | ||
} | ||
|
||
void sm_done(struct sm *m, int good_state, int bad_state, int rc) | ||
{ | ||
int prev = sm_state(m); | ||
|
||
PRE(sm_is_locked(m)); | ||
PRE(m->conf[sm_state(m)].allowed & BITS(good_state)); | ||
PRE(m->conf[sm_state(m)].allowed & BITS(bad_state)); | ||
PRE(m->conf[good_state].flags & SM_FINAL); | ||
PRE(m->conf[bad_state].flags & SM_FAILURE); | ||
|
||
m->rc = rc; | ||
m->state = rc == 0 ? good_state : bad_state; | ||
sm_obs(m); | ||
POST(m->invariant != NULL && m->invariant(m, prev)); | ||
} | ||
|
||
static __attribute__((noinline)) bool check_failed(const char *f, int n, const char *s) | ||
{ | ||
tracef("%s:%d check failed: %s", f, n, s); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,12 @@ | ||
#include "../lib/queue.h" | ||
#include "../raft.h" | ||
#include "../tracing.h" | ||
#include "assert.h" | ||
#include "configuration.h" | ||
#include "err.h" | ||
#include "lifecycle.h" | ||
#include "log.h" | ||
#include "membership.h" | ||
#include "progress.h" | ||
#include "../lib/queue.h" | ||
#include "replication.h" | ||
#include "request.h" | ||
|
||
|
@@ -17,7 +16,9 @@ | |
const unsigned n, | ||
raft_apply_cb cb) | ||
{ | ||
raft_index start; | ||
raft_index index; | ||
const struct sm *entry_sm; | ||
int rv; | ||
|
||
tracef("raft_apply n %d", n); | ||
|
@@ -34,30 +35,40 @@ | |
} | ||
|
||
/* Index of the first entry being appended. */ | ||
index = logLastIndex(r->log) + 1; | ||
tracef("%u commands starting at %lld", n, index); | ||
start = logLastIndex(r->log) + 1; | ||
tracef("%u commands starting at %lld", n, start); | ||
req->type = RAFT_COMMAND; | ||
req->index = index; | ||
req->index = start; | ||
req->cb = cb; | ||
|
||
sm_init(&req->sm, request_invariant, NULL, request_states, "apply-request", | ||
REQUEST_START); | ||
queue_insert_tail(&r->leader_state.requests, &req->queue); | ||
|
||
/* Append the new entries to the log. */ | ||
rv = logAppendCommands(r->log, r->current_term, bufs, n); | ||
if (rv != 0) { | ||
goto err; | ||
index = start; | ||
for (unsigned i = 0; i < n; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the reason of removing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's just a cleanup, yes. |
||
rv = logAppend(r->log, r->current_term, RAFT_COMMAND, bufs[i], true, NULL); | ||
if (rv != 0) { | ||
goto err_after_request_start; | ||
} | ||
entry_sm = log_get_entry_sm(r->log, r->current_term, index); | ||
assert(entry_sm != NULL); | ||
sm_relate(&req->sm, entry_sm); | ||
index++; | ||
} | ||
|
||
lifecycleRequestStart(r, (struct request *)req); | ||
|
||
rv = replicationTrigger(r, index); | ||
rv = replicationTrigger(r, start); | ||
if (rv != 0) { | ||
goto err_after_log_append; | ||
goto err_after_request_start; | ||
} | ||
|
||
return 0; | ||
|
||
err_after_log_append: | ||
err_after_request_start: | ||
logDiscard(r->log, index); | ||
queue_remove(&req->queue); | ||
sm_fail(&req->sm, REQUEST_FAILED, rv); | ||
err: | ||
assert(rv != 0); | ||
return rv; | ||
|
@@ -95,7 +106,7 @@ | |
goto err_after_buf_alloc; | ||
} | ||
|
||
lifecycleRequestStart(r, (struct request *)req); | ||
queue_insert_tail(&r->leader_state.requests, &req->queue); | ||
|
||
rv = replicationTrigger(r, index); | ||
if (rv != 0) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just wanted to leave this code here to show that it's possible to define states in a more compact way:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure. I experimented with switching the state machine definitions over to this style, and it works well for some of them, but once you have more than a few allowed transitions out of some state the lines get long enough to need breaking, and at that point you're more or less back to the beginning. I've pushed a commit that rewrites the definitions in this style, let me know what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not pushing for this style, but it's my personal preference.