just might work. close() mapped out.

Starting to draw a distinction between clean-close and abrupt-halt. At least,
if we're in the connected state, wormhole.close() should take its time and
free up server-side resources (nameplate/mailbox) right away, rather than
relying on GC/timeouts to release them.

It might be useful to make separate "clean" wormhole.close() and "abrupt"
wormhole.halt() API calls, except that really when would you ever call halt?
To be realistic, only one of two things will happen:

* connection happens normally, app finishes, calls "clean" close()
* app terminates suddenly, via exception or SIGINT

The problem with defining .close() is that I have to make it work sensibly
from any state, not just the one plausible "connected" state. Providing
.halt() requires defining its behavior from everywhere else.
This commit is contained in:
Brian Warner 2016-12-27 01:32:01 -05:00
parent 2cfc990d5e
commit 86f246dbdb
2 changed files with 53 additions and 26 deletions

View File

@ -201,18 +201,22 @@ digraph {
C_start [label="Connection\nMachine" style="dotted"]
C_start -> C_S_connecting [label="C_start()"]
C_S_connecting [label="connecting"]
C_S_connecting -> C_S_connected [label="connected"]
C_S_connecting -> C_P_connected [label="onConnect"]
C_P_connected [shape="box" label="M_connected()"]
C_P_connected -> C_S_connected
C_S_connecting -> C_P_stop_connecting [label="C_stop()"]
C_P_stop_connecting [shape="box" label="cancel\nconnection\nattempt"]
C_P_stop_connecting -> C_S_stopped
C_S_connected [label="connected" color="green"]
C_S_connected -> C_S_waiting [label="lost"]
C_S_connected -> C_P_lost [label="onClose"]
C_P_lost [shape="box" label="M_lost()\nstart timer"]
C_P_lost -> C_S_waiting
C_S_waiting [label="waiting"]
C_S_waiting -> C_S_connecting [label="expire"]
C_S_waiting -> C_S_stopped [label="C_stop()"]
C_S_connected -> C_S_stopping [label="C_stop()"]
C_S_stopping [label="stopping"]
C_S_stopping -> C_S_stopped [label="stopped"]
C_S_stopping -> C_S_stopped [label="onClose"]
C_S_stopped [label="stopped"]
}

View File

@ -14,8 +14,8 @@ digraph {
{rank=same; M_S1 M_S1B}
M_S1 [label="1: know nothing"]
M_S1B [label="1: know nothing\n(bound)"]
M_S1 -> M_S1B [label="connect()"]
M_S1B -> M_S1 [label="lose()"]
M_S1 -> M_S1B [label="M_connected()"]
M_S1B -> M_S1 [label="M_lost()"]
M_S1 -> M_S2 [label="M_set_nameplate()"]
M_S1B -> M_P_claim1 [label="M_set_nameplate()"]
@ -25,8 +25,8 @@ digraph {
{rank=same; M_S2 M_S2B M_P_claim2}
M_S2 [label="2: know nameplate\nwant claim\nunknown mailbox\nwant open"]
M_S2B [label="2: know nameplate\nwant claim\nunknown mailbox\nwant open\n(bound)"]
M_S2 -> M_P_claim2 [label="connect()"]
M_S2B -> M_S2 [label="lose()"]
M_S2 -> M_P_claim2 [label="M_connected()"]
M_S2B -> M_S2 [label="M_lost()"]
M_P_claim2 [shape="box" label="tx claim()"]
M_P_claim2 -> M_S2B
M_S2 -> M_P2_queue [label="M_send(msg)" style="dotted"]
@ -44,9 +44,9 @@ digraph {
{rank=same; M_S3 M_S3B M_P3_open M_P3_send}
M_S3 [label="3: claimed\nknown mailbox\nwant open"]
M_S3B [label="3: claimed\nknown mailbox\nwant open\n(bound)"]
M_S3 -> M_P3_open [label="connect()"]
M_S3B -> M_S3 [label="lose()"]
/*M_S3B -> M_S2 [label="lose()"]*/ /* not worth it */
M_S3 -> M_P3_open [label="M_connected()"]
M_S3B -> M_S3 [label="M_lost()"]
/*M_S3B -> M_S2 [label="M_lost()"]*/ /* not worth it */
M_P3_open [shape="box" label="tx open()\ntx add(queued)"]
M_P3_open -> M_S3B
M_S3B -> M_S3B [label="rx_claimed()"]
@ -63,8 +63,15 @@ digraph {
M_P3_process_ours -> M_S3B
M_S3B -> M_P3_process_theirs [label="rx_message(side!=me)"]
M_P3_process_theirs [shape="box" label="tx release()\nprocess message"]
/* pay attention to the race here: this process_message() will
deliver msg_pake to the WormholeMachine, which will compute_key() and
M_send(version), and we're inbetween M_S2 (where M_send gets queued)
and M_S3 (where M_send gets sent and queued), and we're no longer
passing through the M_P3_open phase (which drains the queue). So
there's a real possibility of the outbound msg_version getting
dropped on the floor, or put in a queue but never delivered. */
M_P3_process_theirs -> M_S4B
M_S3B -> M_P3_close [label="M_close()"]
M_S3B -> M_P3_close [label="M_close(mood)"]
M_P3_close [shape="box" label="tx release()\n"]
M_P3_close -> M_P_close
@ -72,12 +79,12 @@ digraph {
M_S4 [label="4: released\nunwant nameplate\nwant mailbox\nopen\n"]
M_S4B [label="4: released\nunwant nameplate\nwant mailbox\nopen\n(bound)"]
M_S4 -> M_P4_release [label="connect()"]
M_S4 -> M_P4_release [label="M_connected()"]
/* it is currently an error to release a nameplate you aren't
currently claiming, so release() is not idempotent. #118 fixes that */
M_P4_release [shape="box" label="tx open()\ntx add(queued)\ntx release()"]
/*M_S4B -> M_S4B [label="rx_claimed() *#118"]*/
M_S4B -> M_P_close [label="M_close()"]
M_S4B -> M_P_close [label="M_close(mood)"]
M_S4B -> M_P4_send [label="M_send(msg)"]
M_P4_send [shape="box" label="queue\ntx add(msg)"]
M_P4_send -> M_S4B
@ -86,8 +93,8 @@ digraph {
M_P4_queue -> M_S4 [style="dotted"]
M_P4_release -> M_S4B
M_S4B -> M_S4 [label="lose()"]
/*M_S4B -> M_S2 [label="lose()"]*/
M_S4B -> M_S4 [label="M_lost()"]
/*M_S4B -> M_S2 [label="M_lost()"]*/
M_S4B -> M_P4_process [label="rx_message()"]
M_P4_process [shape="box" label="process message"]
M_P4_process -> M_S4B
@ -96,14 +103,16 @@ digraph {
M_S4B -> M_S5B [label="rx_released()"]
seed [label="from Seed?"]
M_S3 -> seed [style="invis"]
M_S4 -> seed [style="invis"]
seed -> M_S5
{rank=same; seed M_S5 M_S5B M_P5_open M_P5_process}
M_S5 [label="5: released\nunwant nameplate\nwant mailbox\nopen\n"]
M_S5B [label="5: released\nunwant nameplate\nwant mailbox\nopen\n(bound)" color="green"]
M_S5 -> M_P5_open [label="connect()"]
M_S5 -> M_P5_open [label="M_connected()"]
M_P5_open [shape="box" label="tx open()\ntx add(queued)"]
M_P5_open -> M_S5B
M_S5B -> M_S5 [label="lose()"]
M_S5B -> M_S5 [label="M_lost()"]
M_S5B -> M_P5_process [label="rx_message()"]
M_P5_process [shape="box" label="process message"]
M_P5_process -> M_S5B
@ -114,26 +123,40 @@ digraph {
M_P5_queue [shape="box" label="queue" style="dotted"]
M_P5_queue -> M_S5 [style="dotted"]
M_S5 -> M_S6 [label="M_close()"]
/*M_S5 -> M_P7_drop [label="M_close()"]*/
M_S5B -> M_P_close [label="M_close()"]
M_P_close [shape="box" label="tx close()"]
M_S5 -> M_S6 [style="invis"]
M_S5B -> M_P_close [label="M_close(mood)"]
M_P_close [shape="box" label="tx close(mood)"]
M_P_close -> M_S6B
{rank=same; M_S6 M_P6_close M_S6B}
M_S6 [label="6: closing\nunwant mailbox\nopen\n"]
M_S6B [label="6: closing\nunwant mailbox\nopen\n(bound)"]
M_S6 -> M_P6_close [label="connect()"]
M_S6 -> M_P6_close [label="M_connected()"]
M_P6_close [shape="box" label="tx close()"]
M_P6_close -> M_S6B
M_S6B -> M_S6 [label="lose()"]
M_S6B -> M_S6 [label="M_lost()"]
M_S6B -> M_S6B [label="rx_released()"]
M_S6B -> M_S6B [label="M_close()"]
M_S6B -> M_S6B [label="M_send()"]
M_S6 -> M_S6 [label="M_send()"]
M_S6 -> M_S7 [label="(none)" style="invis"]
/*M_S6 -> M_P7_drop [label="M_close()"]*/
{rank=same; M_other_closes M_P7_drop}
M_other_closes [label="all\nother\nunbound\nstates" style="dotted"]
M_other_closes -> M_P7_stop [label="M_close()" style="dotted"]
M_P7_stop [shape="box" label="C_stop()"]
M_P7_stop -> M_S7
/*M_S1 -> M_other_closes [label="M_close()"]
M_S2 -> M_other_closes [label="M_close()"]
M_S3 -> M_other_closes [label="M_close()"]
M_S4 -> M_other_closes [label="M_close()"]*/
M_S5 -> M_other_closes [style="dotted"]
/*M_S6 -> M_P7_stop [label="M_close()"]*/
M_S6 -> M_other_closes [style="dotted"]
M_S1B -> M_P7_drop [label="M_close()"]
M_S2B -> M_P2_drop [label="M_close()"]
M_P2_drop [shape="box" label="tx release()"]
M_P2_drop -> M_P7_drop
M_S6B -> M_P7_drop [label="rx_closed()"]
M_P7_drop [shape="box" label="C_stop()"]
M_P7_drop -> M_S7B
@ -141,8 +164,8 @@ digraph {
{rank=same; M_S7 M_S7B}
M_S7 [label="7: closed\n"]
M_S7B [label="7: closed\n(bound)"]
M_S7 -> M_S7B [label="connect()" style="invis"]
M_S7B -> M_S7 [label="lose()"]
M_S7 -> M_S7B [style="invis"]
M_S7B -> M_S7 [label="M_lost()"]
M_S7B -> M_S7B [label="M_close()"]
M_S7B -> M_S7B [label="M_send()"]