diff --git a/syndicate/dataspace.rkt b/syndicate/dataspace.rkt index 3332ec2..2863807 100644 --- a/syndicate/dataspace.rkt +++ b/syndicate/dataspace.rkt @@ -14,17 +14,7 @@ (require "bag.rkt") ;; An `ActorID` uniquely identifies an actor in a `Dataspace`. -;; -;; A `FID` is a Facet ID, uniquely identifying both a facet and its -;; ancestry in a `Dataspace`. -;; -;; FID = (facet-id ActorID (Listof Nat)) -;; -(struct facet-id (actor path) #:prefab) -;; -;; The first `Nat` in `path` is the unique identifier for this facet; -;; the `cdr` of the list is the `path` its parent facet. No two `FID`s -;; in a `Dataspace` have the same first `Nat` in their `path`. +;; A `FID` is a Facet ID, uniquely identifying a facet in a `Dataspace`. ;; A `Dataspace` is a ... TODO @@ -36,34 +26,50 @@ (struct dataspace ([next-id #:mutable] ;; Nat routing-table ;; Skeleton - facets ;; (MutableHash FID Facet) - actors ;; (MutableHash ActorID Any) ;; maps ActorID to actor name + actors ;; (MutableHash ActorID Actor) assertions ;; (Bagof Assertion) dataflow ;; DataflowGraph pending-scripts ;; (MutableVectorof (Queueof (-> Any))) [pending-actions #:mutable] ;; (Queueof Action) - ) - #:transparent) + )) -(struct facet (fid ;; FID +(struct actor (id ;; ActorID + name ;; Any + [root-facet #:mutable] ;; (Option Facet) + ) + #:methods gen:custom-write + [(define (write-proc a p mode) + (fprintf p "#" (actor-id a) (actor-name a)))]) + +(struct facet (id ;; FID + [live? #:mutable] ;; Boolean + actor ;; Actor + parent ;; (Option Facet) endpoints ;; (MutableHash EID Endpoint) [stop-scripts #:mutable] ;; (Listof Script) -- IN REVERSE ORDER - [children #:mutable] ;; (Setof FID) + [children #:mutable] ;; (Seteqof Facet) ) - #:transparent) + #:methods gen:custom-write + [(define (write-proc f p mode) + (fprintf p "#" + (actor-id (facet-actor f)) + (actor-name (facet-actor f)) + (facet-id f)))]) (struct endpoint (id ;; EID [assertion #:mutable] ;; Assertion assertion-fn ;; (-> Assertion) handler ;; (Option SkInterest) ) - #:transparent) + #:methods gen:custom-write + [(define (write-proc e p mode) + (fprintf p "#" (endpoint-id e)))]) ;; TODO: field ownership: record actor (root facet) ID in field, check ;; it on access. (struct field-handle (name ;; Symbol id ;; Nat - owner ;; ActorID + owner ;; Actor [value #:mutable] ;; Any ) #:methods gen:custom-write @@ -81,8 +87,11 @@ ;; Parameterof Dataspace (define current-dataspace (make-parameter #f)) -;; Parameterof FID -(define current-facet-id (make-parameter #f)) +;; Parameterof Actor +(define current-actor (make-parameter #f)) + +;; Parameterof Facet +(define current-facet (make-parameter #f)) ;; Parameterof Boolean (define in-script? (make-parameter #t)) @@ -126,7 +135,6 @@ (define ds (dataspace 0 (make-empty-skeleton) (make-hash) - (make-hash) (make-bag) (make-dataflow-graph) (make-vector priority-count (make-queue)) @@ -139,58 +147,42 @@ (set-dataspace-next-id! ds (+ id 1)) id)) -;; TODO: remove?? -(define (fid-parent fid) - (match-define (facet-id actor (cons _ path)) fid) - (facet-id actor path)) - -(define (generate-fid! ds parent-fid) - (match-define (facet-id actor path) parent-fid) - (facet-id actor (cons (generate-id! ds) path))) - -(define (fid-ancestor? fid maybe-ancestor) - (and (equal? (facet-id-actor fid) (facet-id-actor maybe-ancestor)) - (let ((b-path (facet-id-path maybe-ancestor))) - (let walk ((a-path (facet-id-path fid))) - (and (pair? a-path) ;; empty fid lists obviously no ancestors at all! - (or (equal? a-path b-path) - (walk (cdr a-path)))))))) - -(define (has-parent? fid) - (pair? (cdr (facet-id-path fid)))) - (define (add-actor! ds name boot-proc initial-assertions) - (define actor-id (generate-id! ds)) - (define root-fid (facet-id actor-id (list actor-id))) ;; TODO: bad convention. Use a fresh Nat, don't reuse actor-id in the path - (hash-set! (dataspace-actors ds) actor-id name) + (define the-actor-id (generate-id! ds)) + (define the-actor (actor the-actor-id name #f)) + (hash-set! (dataspace-actors ds) the-actor-id the-actor) (for [(a initial-assertions)] (match (bag-change! (dataspace-assertions ds) a 1) ['absent->present (add-assertion! (dataspace-routing-table ds) a)] ;; 'absent->absent and 'present->absent absurd ['present->present (void)])) ;; i.e. no visible change - (add-facet! ds #f root-fid (lambda () - (boot-proc) - (for [(a initial-assertions)] (dataspace-retract! ds a))))) + (add-facet! ds + #f + the-actor + #f + (lambda () + (boot-proc) + (for [(a initial-assertions)] (dataspace-retract! ds a))))) -(define (lookup-facet ds fid) - (hash-ref (dataspace-facets ds) fid #f)) - -(define-syntax-rule (with-current-facet [ds0 fid0 script?] body ...) +(define-syntax-rule (with-current-facet [ds0 a0 f0 script?] body ...) (let ((ds ds0) - (fid fid0)) + (a a0) + (f f0)) (parameterize ((current-dataspace ds) - (current-facet-id fid) + (current-actor a) + (current-facet f) (in-script? script?)) (with-handlers ([(lambda (e) (not (exn:break? e))) - (lambda (e) (terminate-actor! ds (facet-id-actor fid)))]) ;; TODO: tracing + (lambda (e) (terminate-actor! ds a))]) ;; TODO: tracing body ... (void))))) (define (capture-facet-context proc) (let ((ds (current-dataspace)) - (fid (current-facet-id))) + (a (current-actor)) + (f (current-facet))) (lambda args - (with-current-facet [ds fid #t] + (with-current-facet [ds a f #t] (apply proc args))))) (define (pop-next-script! ds) @@ -210,10 +202,9 @@ (begin (script) (dataflow-repair-damage! (dataspace-dataflow ds) (lambda (subject-id) - (match-define (list fid eid) subject-id) - (define f (lookup-facet ds fid)) - (when f - (with-current-facet [ds fid #f] + (match-define (list f eid) subject-id) + (when (facet-live? f) ;; TODO: necessary test, or tautological? + (with-current-facet [ds (facet-actor f) f #f] (define ep (hash-ref (facet-endpoints f) eid)) (define old-assertion (endpoint-assertion ep)) (define new-assertion ((endpoint-assertion-fn ep))) @@ -253,36 +244,31 @@ ;; being held elsewhere! (or ran-a-script performed-an-action)) -(define (add-facet! ds where fid boot-proc) +(define (add-facet! ds where actor parent boot-proc) (when (and (not (in-script?)) where) (error 'add-facet! "~a: Cannot add facet outside script; are you missing an (on ...)?" where)) - (define parent-fid (fid-parent fid)) - (define f (facet fid + (define f (facet (generate-id! ds) + #t + actor + parent (make-hash) '() - (set))) - (hash-set! (dataspace-facets ds) fid f) - (when (has-parent? fid) - (define pf (lookup-facet ds parent-fid)) - (when pf (set-facet-children! pf (set-add (facet-children pf) fid)))) - (with-current-facet [ds fid #f] + (seteq))) + (if parent + (set-facet-children! parent (set-add (facet-children parent) f)) + (set-actor-root-facet! actor f)) + (with-current-facet [ds actor f #f] (boot-proc)) (schedule-script!* ds (lambda () - (when (and (facet-live? ds fid) - (or (and (has-parent? fid) - (not (facet-live? ds parent-fid))) - (facet-live-but-inert? ds fid))) - (terminate-facet! ds fid))))) + (when (and (facet-live? f) + (or (and parent (not (facet-live? parent))) + (facet-inert? ds f))) + (terminate-facet! ds f))))) -(define (facet-live? ds fid) - (hash-has-key? (dataspace-facets ds) fid)) - -(define (facet-live-but-inert? ds fid) - (define f (lookup-facet ds fid)) - (and f - (hash-empty? (facet-endpoints f)) +(define (facet-inert? ds f) + (and (hash-empty? (facet-endpoints f)) (set-empty? (facet-children f)))) (define (schedule-script! #:priority [priority *normal-priority*] ds thunk) @@ -292,82 +278,78 @@ (define v (dataspace-pending-scripts ds)) (vector-set! v priority (enqueue (vector-ref v priority) thunk))) -;; Precondition: `f` is the `facet` struct that is/was associated with `fid` in `ds` -(define (retract-facet-assertions-and-subscriptions! ds fid f) +(define (retract-facet-assertions-and-subscriptions! ds f) (schedule-script!* ds (lambda () (for [((eid ep) (in-hash (facet-endpoints f)))] - (dataflow-forget-subject! (dataspace-dataflow ds) (list fid eid)) + (dataflow-forget-subject! (dataspace-dataflow ds) (list f eid)) (dataspace-retract! ds (endpoint-assertion ep)) (define h (endpoint-handler ep)) (when h (dataspace-unsubscribe! ds h)))))) ;; Abruptly terminates an entire actor, without running stop-scripts etc. -(define (terminate-actor! ds actor-id) - (hash-remove! (dataspace-actors ds) actor-id) - (let abort-facet! ((fid (facet-id actor-id (list actor-id)))) ;; TODO: ugh - (define f (lookup-facet ds fid)) +(define (terminate-actor! ds the-actor) + (hash-remove! (dataspace-actors ds) (actor-id the-actor)) + (let ((f (actor-root-facet the-actor))) (when f - (hash-remove! (dataspace-facets ds) fid) - (for [(child-fid (in-set (facet-children f)))] (abort-facet! child-fid)) - (retract-facet-assertions-and-subscriptions! ds fid 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! ds f))))) ;; Cleanly terminates a facet and its children, running stop-scripts etc. -(define (terminate-facet! ds fid) - (define f (lookup-facet ds fid)) - (when f - (define parent-fid (fid-parent fid)) +(define (terminate-facet! ds f) + (when (facet-live? f) + (define parent (facet-parent f)) + (if parent + (set-facet-children! parent (set-remove (facet-children parent) f)) + (set-actor-root-facet! (facet-actor f) #f)) - (when (has-parent? fid) - (define pf (lookup-facet ds parent-fid)) - (when pf (set-facet-children! pf (set-remove (facet-children pf) fid)))) + (set-facet-live?! f #f) - (hash-remove! (dataspace-facets ds) fid) - - (for [(child-fid (in-set (facet-children f)))] - (terminate-facet! ds child-fid)) + (for [(child (in-set (facet-children f)))] (terminate-facet! ds child)) ;; Run stop-scripts after terminating children. This means that ;; children's stop-scripts run before ours. (for [(script (reverse (facet-stop-scripts f)))] (schedule-script! ds (lambda () - (with-current-facet [ds fid #t] + (with-current-facet [ds (facet-actor f) f #t] (script))))) - (retract-facet-assertions-and-subscriptions! ds fid f) + (retract-facet-assertions-and-subscriptions! ds f) (schedule-script!* #:priority *gc-priority* ds (lambda () - (if (has-parent? fid) - (when (facet-live-but-inert? ds parent-fid) (terminate-facet! ds parent-fid)) - (terminate-actor! ds fid)))))) + (if parent + (when (facet-inert? ds parent) (terminate-facet! ds parent)) + (terminate-actor! ds (facet-actor f))))))) -(define (stop-facet! ds fid stop-script) - (with-current-facet [ds (fid-parent fid) #t] ;; run in parent context wrt terminating facet +(define (stop-facet! ds f stop-script) + (with-current-facet [ds (facet-actor f) f #t] ;; run in parent context wrt terminating facet (schedule-script! ds (lambda () - (terminate-facet! ds fid) + (terminate-facet! ds f) (schedule-script! ds stop-script))))) (define (add-stop-script! ds script-proc) - (define f (lookup-facet ds (current-facet-id))) - (when f (set-facet-stop-scripts! f (cons script-proc (facet-stop-scripts f))))) + (define f (current-facet)) + (set-facet-stop-scripts! f (cons script-proc (facet-stop-scripts f)))) (define (add-endpoint! ds where assertion-fn handler) (when (in-script?) (error 'add-endpoint! "~a: Cannot add endpoint in script; are you missing a (react ...)?" where)) - (define fid (current-facet-id)) + (define f (current-facet)) (define eid (generate-id! ds)) (define assertion - (parameterize ((current-dataflow-subject-id (list fid eid))) + (parameterize ((current-dataflow-subject-id (list f eid))) (assertion-fn))) (define ep (endpoint eid assertion assertion-fn handler)) (dataspace-assert! ds assertion) (when handler (dataspace-subscribe! ds handler)) - (hash-set! (facet-endpoints (lookup-facet ds fid)) eid ep)) + (hash-set! (facet-endpoints f) eid ep)) (define (enqueue-action! ds action) (set-dataspace-pending-actions! ds (enqueue (dataspace-pending-actions ds) action))) @@ -420,14 +402,14 @@ (lambda () (define current-value (field-handle 'current-value (generate-id! (current-dataspace)) - (facet-id-actor (current-facet-id)) + (facet-actor (current-facet)) 0)) (add-endpoint! (current-dataspace) 'stop-when-ten (lambda () (when (= (current-value) 10) (stop-facet! (current-dataspace) - (current-facet-id) + (current-facet) (lambda () (log-info "box: terminating")))) (void)) @@ -468,7 +450,7 @@ (when (eq? '- op) (stop-facet! (current-dataspace) - (current-facet-id) + (current-facet) (lambda () (log-info "client: box has gone")))))))) (add-endpoint! (current-dataspace) diff --git a/syndicate/syntax.rkt b/syndicate/syntax.rkt index 45198cc..d2c42db 100644 --- a/syndicate/syntax.rkt +++ b/syndicate/syntax.rkt @@ -134,7 +134,8 @@ (define ds (current-dataspace)) (add-facet! ds where - (generate-fid! ds (current-facet-id)) + (current-actor) + (current-facet) boot-proc)) (define-syntax (react stx)