Skip to content

Commit 6a510c5

Browse files
committed
allow to specify custom mbox type per dispatcher and via actor-of.
additional test for if mbox class is not known. allow specifying custom mbox-type via `actor-of`. sbcl fix docstring changes
1 parent c149c0c commit 6a510c5

File tree

5 files changed

+116
-26
lines changed

5 files changed

+116
-26
lines changed

src/actor-context-api.lisp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
(:documentation "Interface for creating an actor.
2424
2525
**!!! Attention:** this factory function wraps the `act:make-actor` functionality to something more simple to use.
26-
Using this function there is no need to use both `act:make-actor`.
26+
Using this function there is no need to use `act:make-actor`.
2727
2828
`context` is either an `asys:actor-system`, an `ac:actor-context`, or an `act:actor` (any type of actor).
2929
The new actor is created in the given context.
@@ -43,6 +43,8 @@ This function allows to unsubsribe from event-stream or such.
4343
Additional options:
4444
4545
- `:queue-size` limits the message-box's size. By default, it is unbounded.
46+
- `:mbox-type` specify a custom message-box type similar as can be done is dispatcher config.
47+
It must be a subtype of `mesgb:message-box/dp`.
4648
"))
4749

4850
(defgeneric find-actors (context path &key test key)

src/actor-context.lisp

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ The `actor-system` and the `actor` itself are composed of an `actor-context`."))
2727
(defun %get-shared-dispatcher (system identifier)
2828
(getf (asys:dispatchers system) identifier))
2929

30+
(defun %get-dispatcher-config (config dispatcher-id)
31+
(let* ((disp-config (config:retrieve-section config :dispatchers))
32+
(dispatcher-keys (config:retrieve-keys disp-config)))
33+
(when (find dispatcher-id dispatcher-keys)
34+
(config:retrieve-section disp-config dispatcher-id))))
35+
3036
(defun %add-actor (context actor)
3137
(let ((atomic-actors (slot-value context 'actors)))
3238
(atomic:atomic-swap atomic-actors (lambda (old-actors)
@@ -43,16 +49,23 @@ The `actor-system` and the `actor` itself are composed of an `actor-context`."))
4349
(act-cell:name actor))))
4450
old-actors)))))
4551

46-
(defun %message-box-for-dispatcher-id (context dispatcher-id queue-size)
52+
(defun %message-box-for-dispatcher-id (context dispatcher-id queue-size mbox-type)
4753
(case dispatcher-id
4854
(:pinned (make-instance 'mesgb:message-box/bt
4955
:max-queue-size queue-size))
50-
(otherwise (let ((dispatcher (%get-shared-dispatcher (system context) dispatcher-id)))
56+
(otherwise (let* ((asys (system context))
57+
(sys-config (asys:config asys))
58+
(disp-config (%get-dispatcher-config sys-config dispatcher-id))
59+
(dispatcher (%get-shared-dispatcher asys dispatcher-id)))
5160
(unless dispatcher
5261
(error (format nil "No such dispatcher identifier '~a' exists!" dispatcher-id)))
53-
(make-instance 'mesgb:message-box/dp
54-
:dispatcher dispatcher
55-
:max-queue-size queue-size)))))
62+
;; if dispatcher exists, the config does, too.
63+
(let ((eff-mbox-type (if mbox-type
64+
mbox-type
65+
(getf disp-config :mbox-type 'mesgb:message-box/dp))))
66+
(make-instance eff-mbox-type
67+
:dispatcher dispatcher
68+
:max-queue-size queue-size))))))
5669

5770
(defun %find-actor-by-name (context name)
5871
(find-if (lambda (a)
@@ -75,19 +88,19 @@ The `actor-system` and the `actor` itself are composed of an `actor-context`."))
7588
(log:error "Actor with name '~a' already exists!" actor-name)
7689
(error (make-condition 'actor-name-exists :name actor-name)))))
7790

78-
(defun %create-actor (context create-fun dispatcher-id queue-size)
91+
(defun %create-actor (context create-fun dispatcher-id queue-size mbox-type)
7992
(let ((actor (funcall create-fun)))
8093
(when actor
8194
(%verify-actor context actor)
8295
(act::finalize-initialization actor
83-
(%message-box-for-dispatcher-id context dispatcher-id queue-size)
96+
(%message-box-for-dispatcher-id context dispatcher-id queue-size mbox-type)
8497
(make-actor-context (system context)
8598
(miscutils:mkstr (id context) "/" (act-cell:name actor)))))
8699
actor))
87100

88-
(defun %actor-of (context create-fun &key (dispatcher :shared) (queue-size 0))
101+
(defun %actor-of (context create-fun &key (dispatcher :shared) (queue-size 0) mbox-type)
89102
"See `ac:actor-of`"
90-
(let ((created (%create-actor context create-fun dispatcher queue-size)))
103+
(let ((created (%create-actor context create-fun dispatcher queue-size mbox-type)))
91104
(when created
92105
(act:watch created context)
93106
(%add-actor context created))))
@@ -122,19 +135,22 @@ An `act:actor` contains an `actor-context`."
122135
"See `ac:actor-of`."
123136
(check-type receive function "a function!")
124137

125-
(alexandria:remove-from-plistf rest
126-
:queue-size
127-
:dispatcher)
128-
(%actor-of context
129-
(lambda () (apply #'act:make-actor receive
130-
:init init
131-
:destroy destroy
132-
:state state
133-
:type type
134-
:name name
135-
rest))
136-
:dispatcher dispatcher
137-
:queue-size queue-size))
138+
(let ((mbox-type (getf rest :mbox-type)))
139+
(alexandria:remove-from-plistf rest
140+
:queue-size
141+
:dispatcher
142+
:mbox-type)
143+
(%actor-of context
144+
(lambda () (apply #'act:make-actor receive
145+
:init init
146+
:destroy destroy
147+
:state state
148+
:type type
149+
:name name
150+
rest))
151+
:dispatcher dispatcher
152+
:queue-size queue-size
153+
:mbox-type mbox-type)))
138154

139155

140156
;; test 2-arity function with 'path' and 'act-cell-name' (default)

src/actor-system-api.lisp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#:dispatchers
77
#:evstream
88
#:scheduler
9+
#:config
910
#:register-dispatcher
1011
#:register-new-dispatcher
1112
#:*default-config*))
@@ -14,12 +15,39 @@
1415

1516
(defparameter *default-config*
1617
'(:dispatchers
17-
(:shared (:workers 4 :strategy :random))
18+
(:shared (:workers 4 :strategy :random :mbox-type mesgb:message-box/dp))
1819
:timeout-timer
1920
(:resolution 100 :max-size 500)
2021
:eventstream
2122
(:dispatcher-id :shared)
2223
:scheduler
2324
(:enabled :true :resolution 100 :max-size 500))
2425
"The default config used when creating an `asys:actor-system`.
25-
The actor-system constructor allows to provide custom config options that override the default.")
26+
The actor-system constructor allows to provide custom config options that override the defaults.
27+
28+
The constructor provided configuration does not need to specify all parts of the config,
29+
rather, what is provided is merged with `*default-config*`.
30+
That means e.g. specifying an additional dispatcher, one just has to provide this to the constructor:
31+
32+
```
33+
'(:dispatchers
34+
(:my-disp (:workers 4)))
35+
```
36+
37+
For all other parameters the defaults will be used, even `:workers` does not need to be there.
38+
The defaults, when omitted, are:
39+
- workers = 2
40+
- strategy = :random
41+
- mbox-type = 'mesgb:message-box/dp'
42+
43+
If you want to just modify parts of the config, i.e. the strategy, then one can do:
44+
45+
```
46+
'(:dispatchers
47+
(:shared (:strategy :round-robin)))
48+
```
49+
50+
This will just change the strategy to `:round-robin`.
51+
52+
Note that `mbox-type` must be a subtype of `mesgb:message-box/dp`.
53+
")

tests/actor-context-test.lisp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@
6767
(is (not (eq cut (act:context actor))))
6868
(is (not (null (ac:system (act:context actor))))))))
6969

70+
(defclass my-mbox-type (mesgb:message-box/dp) ())
71+
(test actor-of--shared--custom-mbox-type
72+
(with-fixture test-system ()
73+
(let* ((cut (make-actor-context system))
74+
(actor (actor-of cut :receive (lambda ())
75+
:mbox-type 'sento.actor-context-test::my-mbox-type)))
76+
(is (typep (act-cell:msgbox actor) 'my-mbox-type)))))
77+
7078
(test actor-of--pinned
7179
"Tests creating a new actor in the context with pinned dispatcher"
7280
(with-fixture test-system ()
@@ -95,6 +103,42 @@
95103
))
96104
(ac:shutdown system))))
97105

106+
(test actor-of--custom-dispatcher-with-custom-mbox-type
107+
"Tests creating an actor with a custom shared dispatcher."
108+
(let ((system))
109+
(unwind-protect
110+
(progn
111+
(setf system (asys:make-actor-system '(:dispatchers
112+
(:foo
113+
(:workers 0
114+
:mbox-type sento.actor-context-test::my-mbox-type)))))
115+
(let* ((cut (make-actor-context system))
116+
(actor (actor-of cut :receive (lambda ()) :dispatcher :foo)))
117+
(is (not (null actor)))
118+
(is (typep (act-cell:msgbox actor) 'my-mbox-type))
119+
(is (eq :foo (slot-value (mesgb::dispatcher (act-cell:msgbox actor)) 'disp::identifier)))
120+
))
121+
(ac:shutdown system))))
122+
123+
(test actor-of--err-custom-dispatcher--unknown-mbox-type
124+
"Tests creating an actor with a custom shared dispatcher."
125+
(let ((system))
126+
(unwind-protect
127+
(progn
128+
(setf system (asys:make-actor-system '(:dispatchers
129+
(:foo
130+
(:mbox-type foombox)))))
131+
(let ((cut (make-actor-context system)))
132+
(handler-case
133+
(progn
134+
(actor-of cut :receive (lambda ()) :dispatcher :foo)
135+
(fail()))
136+
(error (c)
137+
(format t "cond: ~a" c)
138+
(is (str:containsp "FOOMBOX"
139+
(format nil "~a" c)))))))
140+
(ac:shutdown system))))
141+
98142
(test actor-of--err-unknown-dispatcher
99143
"Tests creating a new actor on an unknown dispatcher."
100144
(with-fixture test-system ()

tests/actor-system-test.lisp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
(unwind-protect
8080
(progn
8181
(is (equal (asys::%get-dispatcher-config (asys::config system))
82-
'(:shared (:workers 4 :strategy :random))))
82+
'(:shared (:workers 4 :strategy :random :mbox-type mesgb:message-box/dp))))
8383
(is (equal (asys::%get-timeout-timer-config (asys::config system))
8484
'(:resolution 100
8585
:max-size 500)))

0 commit comments

Comments
 (0)