|
76 | 76 | ;;;
|
77 | 77 |
|
78 | 78 | (defn- async-send
|
| 79 | + "Returns an AsyncPut with the result of calling a non-blocking .put() on a sink. |
| 80 | + If it times out, returns the sink itself as the timeout value." |
79 | 81 | [^Downstream dwn msg dsts]
|
80 | 82 | (let [^IEventSink sink (.sink dwn)]
|
81 | 83 | (let [x (if (== (.timeout dwn) -1)
|
|
101 | 103 | (when (and (identical? ::timeout x) (.downstream? dwn))
|
102 | 104 | (s/close! sink))))
|
103 | 105 |
|
104 |
| -(defn- handle-async-put [^AsyncPut x val source] |
| 106 | +(defn- handle-async-put |
| 107 | + "Handle a successful async put" |
| 108 | + [^AsyncPut x val source] |
105 | 109 | (let [d (.deferred x)
|
106 |
| - val (if (instance? IEventSink val) |
| 110 | + val (if (instance? IEventSink val) ; it timed out, in which case the val is set to the sink |
107 | 111 | (do
|
108 | 112 | (s/close! val)
|
109 | 113 | false)
|
110 | 114 | val)]
|
| 115 | + ;; if sink failed or timed out, remove and maybe close source |
111 | 116 | (when (false? val)
|
112 | 117 | (let [^CopyOnWriteArrayList l (.dsts x)]
|
113 | 118 | (.remove l (.dst x))
|
|
125 | 130 | (.remove handle->downstreams (s/weak-handle source)))))
|
126 | 131 |
|
127 | 132 | (defn- async-connect
|
| 133 | + "Connects downstreams to an async source. |
| 134 | +
|
| 135 | + Puts to sync sinks are delayed until all async sinks have been successfully put to" |
128 | 136 | [^IEventSource source
|
129 | 137 | ^CopyOnWriteArrayList dsts]
|
130 | 138 | (let [sync-sinks (LinkedList.)
|
131 |
| - deferreds (LinkedList.) |
| 139 | + put-deferreds (LinkedList.) |
132 | 140 |
|
| 141 | + ;; asynchronously .put to all synchronous sinks, using callbacks and trampolines as needed |
133 | 142 | sync-propagate (fn this [recur-point msg]
|
134 | 143 | (loop []
|
135 | 144 | (let [^Downstream dwn (.poll sync-sinks)]
|
|
140 | 149 | val (d/success-value d ::none)]
|
141 | 150 | (if (identical? val ::none)
|
142 | 151 | (d/on-realized d
|
143 |
| - (fn [v] |
144 |
| - (handle-async-put x v source) |
| 152 | + (fn [val] |
| 153 | + (handle-async-put x val source) |
145 | 154 | (trampoline #(this recur-point msg)))
|
146 | 155 | (fn [e]
|
147 | 156 | (handle-async-error x e source)
|
|
150 | 159 | (handle-async-put x val source)
|
151 | 160 | (recur))))))))
|
152 | 161 |
|
| 162 | + ;; handle all the async puts, using callbacks and trampolines as needed |
| 163 | + ;; then handle all sync puts once asyncs are done |
153 | 164 | async-propagate (fn this [recur-point msg]
|
154 | 165 | (loop []
|
155 |
| - (let [^AsyncPut x (.poll deferreds)] |
| 166 | + (let [^AsyncPut x (.poll put-deferreds)] |
156 | 167 | (if (nil? x)
|
157 | 168 |
|
158 |
| - ;; iterator over sync-sinks |
| 169 | + ;; iterator over sync-sinks when deferreds list is empty |
159 | 170 | (if (.isEmpty sync-sinks)
|
160 | 171 | recur-point
|
161 | 172 | #(sync-propagate recur-point msg))
|
|
226 | 237 | :else
|
227 | 238 | (let [i (.iterator dsts)]
|
228 | 239 | (if (not (.hasNext i))
|
229 |
| - |
| 240 | + ;; close source if no downstreams |
230 | 241 | (do
|
231 | 242 | (s/close! source)
|
232 | 243 | (.remove handle->downstreams (s/weak-handle source)))
|
233 | 244 |
|
| 245 | + ;; otherwise: |
| 246 | + ;; 1. add all sync downstreams into a list |
| 247 | + ;; 2. attempt to .put() all async downstreams and collect AsyncPuts in a list |
| 248 | + ;; 3. call async-propagate |
234 | 249 | (do
|
235 | 250 | (loop []
|
236 | 251 | (when (.hasNext i)
|
237 | 252 | (let [^Downstream dwn (.next i)]
|
238 | 253 | (if (s/synchronous? (.sink dwn))
|
239 | 254 | (.add sync-sinks dwn)
|
240 |
| - (.add deferreds (async-send dwn msg dsts))) |
| 255 | + (.add put-deferreds (async-send dwn msg dsts))) |
241 | 256 | (recur))))
|
242 | 257 |
|
243 | 258 | (async-propagate this msg))))))))))
|
244 | 259 |
|
245 | 260 | (defn- sync-connect
|
| 261 | + "Connects downstreams to a sync source" |
246 | 262 | [^IEventSource source
|
247 | 263 | ^CopyOnWriteArrayList dsts]
|
248 | 264 | (utils/future-with (ex/wait-pool)
|
|
0 commit comments