diff --git a/syndicate/dataspace.rkt b/syndicate/dataspace.rkt index 6e56b5f..8f1cd8b 100644 --- a/syndicate/dataspace.rkt +++ b/syndicate/dataspace.rkt @@ -269,7 +269,13 @@ (define a (current-actor)) ((current-actor-crash-logger) a e) (abandon-queued-work! a) - (terminate-actor! a))]) ;; TODO: tracing + ;; v Supply #f for `emit-patches?` here + ;; because we are in an uncertain limbo after + ;; discarding previously-queued actions. + ;; Instead of emitting patches to orderly + ;; tear down assertions from endpoints, we + ;; rely on the recorded `cleanup-changes`. + (terminate-actor! a #f))]) ;; TODO: tracing (call-with-syndicate-prompt (lambda () body ...)) @@ -437,12 +443,12 @@ (define v (actor-pending-scripts ac)) (vector-set! v priority (enqueue (vector-ref v priority) thunk-with-context))) -(define (retract-facet-assertions-and-subscriptions! f) +(define (retract-facet-assertions-and-subscriptions! f emit-patches?) (define ac (facet-actor f)) (define ds (actor-dataspace ac)) (push-script! ac (lambda () (for [((eid ep) (in-hash (facet-endpoints f)))] - (destroy-endpoint! ds ac f ep)) + (destroy-endpoint! ds ac f ep emit-patches?)) (hash-clear! (facet-endpoints f))))) (define (abandon-queued-work! ac) @@ -452,15 +458,16 @@ (vector-set! scripts i (make-queue))))) ;; Abruptly terminates an entire actor, without running stop-scripts etc. -(define (terminate-actor! the-actor) - (push-script! the-actor (lambda () (for [(a (in-bag (actor-adhoc-assertions the-actor)))] - (retract! the-actor a)))) +(define (terminate-actor! the-actor emit-patches?) + (when emit-patches? + (push-script! the-actor (lambda () (for [(a (in-bag (actor-adhoc-assertions the-actor)))] + (retract! the-actor a))))) (let ((f (actor-root-facet the-actor))) (when f (let abort-facet! ((f f)) (set-facet-live?! f #f) (for [(child (in-set (facet-children f)))] (abort-facet! child)) - (retract-facet-assertions-and-subscriptions! f)))) + (retract-facet-assertions-and-subscriptions! f emit-patches?)))) (push-script! the-actor (lambda () (enqueue-action! the-actor (quit))))) ;; Cleanly terminates a facet and its children, running stop-scripts etc. @@ -483,13 +490,13 @@ (for [(script (in-list (reverse (facet-stop-scripts f))))] (script))))) - (retract-facet-assertions-and-subscriptions! f) + (retract-facet-assertions-and-subscriptions! f #t) (push-script! #:priority *gc-priority* ac (lambda () (if parent (when (facet-inert? parent) (terminate-facet! parent)) - (terminate-actor! ac)))))) + (terminate-actor! ac #t)))))) (define (stop-facet! f stop-script) (define ac (facet-actor f)) @@ -523,13 +530,13 @@ (when ep (define ac (facet-actor f)) (define ds (actor-dataspace ac)) - (destroy-endpoint! ds ac f ep) + (destroy-endpoint! ds ac f ep #t) (hash-remove! eps eid))) -(define (destroy-endpoint! ds ac f ep) +(define (destroy-endpoint! ds ac f ep emit-patches?) (match-define (endpoint eid assertion handler _update-fn) ep) (dataflow-forget-subject! (dataspace-dataflow ds) (list f eid)) - (retract! ac assertion) + (when emit-patches? (retract! ac assertion)) (when handler (dataspace-unsubscribe! ds handler))) (define (enqueue-action! ac action) diff --git a/syndicate/test/core/death-during-turn.rkt b/syndicate/test/core/death-during-turn.rkt new file mode 100644 index 0000000..03316f1 --- /dev/null +++ b/syndicate/test/core/death-during-turn.rkt @@ -0,0 +1,20 @@ +#lang imperative-syndicate/test-implementation +;; An error signalled mid-turn must cause previous actions to be +;; discarded; discarded actions must not be observed by peers. + +(test-case + [(message-struct set-box (new-value)) + (assertion-struct box-state (value)) + + (spawn (field [current-value 0]) + (assert (box-state (current-value))) + (on (message (set-box $new-value)) (current-value new-value)) + (begin/dataflow (when (= (current-value) 3) + (error 'box "aiee")))) + + (spawn (on (asserted (box-state $v)) ;; must not see 3 here. + (printf "~v\n" v) + (send! (set-box (+ v 1)))))] + (expected-output (list "0" + "1" + "2")))