1use crate::runtime::{
2 config::streaming::StreamingLogLevel,
3 logging::ServerLogger,
4 memory_management::ManagedMemoryId,
5 server::{Binding, ServerError},
6 stream::{StreamFactory, StreamPool},
7};
8use core::any::Any;
9use ruda_core::{backtrace::BackTrace, stream_id::StreamId};
10use hashbrown::HashMap;
11use std::{
12 boxed::Box,
13 format,
14 sync::{Arc, mpsc::SyncSender},
15 vec::Vec,
16};
17
18pub trait EventStreamBackend: 'static {
23 type Stream: core::fmt::Debug;
25 type Event: Send + 'static;
27
28 fn create_stream(&self) -> Self::Stream;
30 fn handle_cursor(stream: &Self::Stream, handle: &Binding) -> u64;
32 fn is_healthy(stream: &Self::Stream) -> bool;
34
35 fn flush(stream: &mut Self::Stream) -> Self::Event;
38 fn wait_event(stream: &mut Self::Stream, event: Self::Event);
40 fn wait_event_sync(event: Self::Event) -> Result<(), ServerError>;
42}
43
44#[derive(Debug)]
49pub struct MultiStream<B: EventStreamBackend> {
50 streams: StreamPool<EventStreamBackendWrapper<B>>,
52 pub logger: Arc<ServerLogger>,
54 max_streams: usize,
55 gc: GcThread<B>,
56 shared_bindings_pool: Vec<(ManagedMemoryId, StreamId, u64)>,
57}
58
59pub(crate) struct StreamWrapper<B: EventStreamBackend> {
64 stream: B::Stream,
66 cursor: u64,
68 last_synced: HashMap<usize, u64>,
70}
71
72pub struct ResolvedStreams<'a, B: EventStreamBackend> {
74 pub cursor: u64,
78 streams: &'a mut StreamPool<EventStreamBackendWrapper<B>>,
79 analysis: SharedBindingAnalysis,
80 gc: &'a GcThread<B>,
81 pub current: StreamId,
83}
84
85#[derive(Debug)]
86pub struct GcTask<B: EventStreamBackend> {
88 to_drop: Box<dyn Any + Send + 'static>,
89 event: B::Event,
91}
92
93impl<B: EventStreamBackend> GcTask<B> {
94 pub fn new<T: Send + 'static>(to_drop: T, event: B::Event) -> Self {
96 Self {
97 to_drop: Box::new(to_drop),
98 event,
99 }
100 }
101}
102
103#[derive(Debug)]
104struct EventStreamBackendWrapper<B: EventStreamBackend> {
105 backend: B,
106}
107
108impl<B: EventStreamBackend> StreamFactory for EventStreamBackendWrapper<B> {
109 type Stream = StreamWrapper<B>;
110
111 fn create(&mut self) -> Self::Stream {
112 StreamWrapper {
113 stream: self.backend.create_stream(),
114 cursor: 0,
115 last_synced: Default::default(),
116 }
117 }
118}
119
120#[derive(Debug)]
121struct GcThread<B: EventStreamBackend> {
122 sender: SyncSender<GcTask<B>>,
123}
124
125impl<B: EventStreamBackend> GcThread<B> {
126 fn new() -> GcThread<B> {
127 let (sender, recv) = std::sync::mpsc::sync_channel::<GcTask<B>>(8);
128
129 std::thread::spawn(move || {
130 while let Ok(event) = recv.recv() {
131 B::wait_event_sync(event.event).unwrap();
132 core::mem::drop(event.to_drop);
133 }
134 });
135
136 GcThread { sender }
137 }
138 fn register(&self, task: GcTask<B>) {
139 self.sender.send(task).unwrap()
140 }
141}
142
143fn stream_index(stream_id: &StreamId, max_streams: usize) -> usize {
144 stream_id.value as usize % max_streams
145}
146
147impl<'a, B: EventStreamBackend> ResolvedStreams<'a, B> {
148 pub fn get(&mut self, stream_id: &StreamId) -> &mut B::Stream {
150 let stream = self.streams.get_mut(stream_id);
151 &mut stream.stream
152 }
153
154 pub fn current(&mut self) -> &mut B::Stream {
156 let stream = self.streams.get_mut(&self.current);
157 &mut stream.stream
158 }
159
160 pub fn gc(&mut self, gc: GcTask<B>) {
162 self.gc.sender.send(gc).unwrap();
163 }
164}
165
166impl<'a, B: EventStreamBackend> Drop for ResolvedStreams<'a, B> {
167 fn drop(&mut self) {
168 if self.analysis.slices.is_empty() {
169 return;
170 }
171
172 let stream = self.streams.get_mut(&self.current);
173 let event_origin = B::flush(&mut stream.stream);
174
175 let stream_gc = &mut unsafe { self.streams.get_special(0) }.stream;
176 B::wait_event(stream_gc, event_origin);
177 let event = B::flush(stream_gc);
178
179 let mut ids = Vec::new();
180 self.analysis
181 .slices
182 .drain()
183 .for_each(|item| ids.extend(item.1));
184
185 self.gc.register(GcTask::new(ids, event));
186 }
187}
188
189impl<B: EventStreamBackend> MultiStream<B> {
190 pub fn try_initialize_with<E>(
193 &mut self, stream_id: &StreamId,
194 initialize: impl FnOnce(&B) -> Result<B::Stream, E>,
195 ) -> Result<bool, E> {
196 self.streams.try_initialize_with(stream_id, |factory| {
197 Ok(StreamWrapper { stream: initialize(&factory.backend)?,
198 cursor: 0, last_synced: Default::default() })
199 })
200 }
201
202 pub fn new(logger: Arc<ServerLogger>, backend: B, max_streams: u8) -> Self {
204 let wrapper = EventStreamBackendWrapper { backend };
205 Self {
206 streams: StreamPool::new(wrapper, max_streams, 1),
207 logger,
208 max_streams: max_streams as usize,
209 gc: GcThread::new(),
210 shared_bindings_pool: Vec::new(),
211 }
212 }
213
214 pub fn gc(&mut self, gc: GcTask<B>) {
216 self.gc.sender.send(gc).unwrap();
217 }
218
219 pub fn resolve<'a>(
225 &mut self,
226 stream_id: StreamId,
227 handles: impl Iterator<Item = &'a Binding>,
228 enforce_healthy: bool,
229 ) -> Result<ResolvedStreams<'_, B>, ServerError> {
230 let analysis = self.align_streams(stream_id, handles);
231
232 let stream = self.streams.get_mut(&stream_id);
233 stream.cursor += 1;
234
235 if enforce_healthy && !B::is_healthy(&stream.stream) {
236 return Err(ServerError::Generic {
237 reason: "Can't resolve the stream since it is currently in an error state".into(),
238 backtrace: BackTrace::capture(),
239 });
240 }
241
242 Ok(ResolvedStreams {
243 cursor: stream.cursor,
244 streams: &mut self.streams,
245 current: stream_id,
246 analysis,
247 gc: &self.gc,
248 })
249 }
250
251 fn align_streams<'a>(
256 &mut self,
257 stream_id: StreamId,
258 handles: impl Iterator<Item = &'a Binding>,
259 ) -> SharedBindingAnalysis {
260 let analysis = self.update_shared_bindings(stream_id, handles);
261
262 self.apply_analysis(stream_id, analysis)
263 }
264
265 pub(crate) fn update_shared_bindings<'a>(
270 &mut self,
271 stream_id: StreamId,
272 handles: impl Iterator<Item = &'a Binding>,
273 ) -> SharedBindingAnalysis {
274 self.shared_bindings_pool.clear();
276
277 for handle in handles {
278 let index = stream_index(&handle.stream, self.max_streams);
279 let stream = unsafe { self.streams.get_mut_index(index) };
280 let cursor_handle = B::handle_cursor(&stream.stream, handle);
281
282 if handle.stream != stream_id {
285 self.shared_bindings_pool.push((
286 handle.memory.descriptor().id,
287 handle.stream,
288 cursor_handle,
289 ));
290 }
291 }
292
293 let mut analysis = SharedBindingAnalysis::default();
294 let current = self.streams.get_mut(&stream_id);
295
296 for (handle_id, stream, cursor) in self.shared_bindings_pool.iter() {
297 let index = stream_index(stream, self.max_streams);
298
299 if let Some(last_synced) = current.last_synced.get(&index) {
300 if last_synced < cursor {
301 self.logger.log_streaming(
302 |level| matches!(level, StreamingLogLevel::Full),
303 || {
304 format!(
305 "Binding on {} is shared on {} since it's not sync {} < {}",
306 stream, stream_id, last_synced, cursor
307 )
308 },
309 );
310 analysis.shared(*handle_id, index);
311 }
312 } else {
313 self.logger.log_streaming(
314 |level| matches!(level, StreamingLogLevel::Full),
315 || {
316 format!(
317 "Binding on {} is shared on {} since it was never synced.",
318 stream, stream_id,
319 )
320 },
321 );
322 analysis.shared(*handle_id, index);
323 }
324 }
325
326 analysis
327 }
328
329 pub(crate) fn apply_analysis(
330 &mut self,
331 stream_id: StreamId,
332 analysis: SharedBindingAnalysis,
333 ) -> SharedBindingAnalysis {
334 if analysis.slices.is_empty() {
335 return analysis;
336 }
337
338 let mut events = Vec::with_capacity(analysis.slices.len());
339
340 unsafe {
341 for origin in analysis.slices.keys() {
342 let stream = self.streams.get_mut_index(*origin);
343 let event = B::flush(&mut stream.stream);
344
345 events.push(((origin, stream.cursor), event));
346 }
347 }
348
349 let stream = self.streams.get_mut(&stream_id);
350
351 for ((stream_origin, cursor_origin), event) in events {
352 stream.last_synced.insert(*stream_origin, cursor_origin);
353
354 self.logger.log_streaming(
355 |level| !matches!(level, StreamingLogLevel::Disabled),
356 || format!("Waiting on {stream_origin} from {stream_id}",),
357 );
358
359 B::wait_event(&mut stream.stream, event);
360 }
361
362 analysis
363 }
364}
365
366impl<B: EventStreamBackend> core::fmt::Debug for StreamWrapper<B> {
367 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
368 f.debug_struct("StreamWrapper")
369 .field("stream", &self.stream)
370 .field("cursor", &self.cursor)
371 .field("last_synced", &self.last_synced)
372 .finish()
373 }
374}
375
376#[derive(Default, Debug, PartialEq, Eq)]
377pub(crate) struct SharedBindingAnalysis {
378 slices: HashMap<usize, Vec<ManagedMemoryId>>,
379}
380
381impl SharedBindingAnalysis {
382 fn shared(&mut self, id: ManagedMemoryId, index: usize) {
383 match self.slices.get_mut(&index) {
384 Some(bindings) => bindings.push(id),
385 None => {
386 self.slices.insert(index, alloc::vec![id]);
387 }
388 }
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 use crate::runtime::server::Handle;
395
396 use super::*;
397
398 const MAX_STREAMS: u8 = 4;
399
400 #[test_log::test]
401 fn test_analysis_shared_bindings_1() {
402 let logger = Arc::new(ServerLogger::default());
403 let stream_1 = StreamId { value: 1 };
404 let stream_2 = StreamId { value: 2 };
405
406 let binding_1 = handle(stream_1);
407 let binding_2 = handle(stream_2);
408
409 let mut ms = MultiStream::new(logger, TestBackend, MAX_STREAMS);
410 ms.resolve(stream_1, [].into_iter(), false).unwrap();
411 ms.resolve(stream_2, [].into_iter(), false).unwrap();
412
413 let analysis = ms.update_shared_bindings(stream_1, [&binding_1, &binding_2].into_iter());
414
415 let mut expected = SharedBindingAnalysis::default();
416 expected.shared(
417 binding_2.memory.descriptor().id,
418 ms.streams.stream_index(&binding_2.stream),
419 );
420
421 assert_eq!(analysis, expected);
422 }
423
424 #[test_log::test]
425 fn test_analysis_shared_bindings_2() {
426 let logger = Arc::new(ServerLogger::default());
427 let stream_1 = StreamId { value: 1 };
428 let stream_2 = StreamId { value: 2 };
429
430 let binding_1 = handle(stream_1);
431 let binding_2 = handle(stream_2);
432 let binding_3 = handle(stream_1);
433
434 let mut ms = MultiStream::new(logger, TestBackend, 4);
435 ms.resolve(stream_1, [].into_iter(), false).unwrap();
436 ms.resolve(stream_2, [].into_iter(), false).unwrap();
437
438 let analysis =
439 ms.update_shared_bindings(stream_1, [&binding_1, &binding_2, &binding_3].into_iter());
440
441 let mut expected = SharedBindingAnalysis::default();
442 expected.shared(
443 binding_2.memory.descriptor().id,
444 ms.streams.stream_index(&binding_2.stream),
445 );
446
447 assert_eq!(analysis, expected);
448 }
449
450 #[test_log::test]
451 fn test_analysis_no_shared() {
452 let logger = Arc::new(ServerLogger::default());
453 let stream_1 = StreamId { value: 1 };
454 let stream_2 = StreamId { value: 2 };
455
456 let binding_1 = handle(stream_1);
457 let binding_2 = handle(stream_1);
458 let binding_3 = handle(stream_1);
459
460 let mut ms = MultiStream::new(logger, TestBackend, MAX_STREAMS);
461 ms.resolve(stream_1, [].into_iter(), false).unwrap();
462 ms.resolve(stream_2, [].into_iter(), false).unwrap();
463
464 let analysis =
465 ms.update_shared_bindings(stream_1, [&binding_1, &binding_2, &binding_3].into_iter());
466
467 let expected = SharedBindingAnalysis::default();
468
469 assert_eq!(analysis, expected);
470 }
471
472 #[test_log::test]
473 fn test_state() {
474 let logger = Arc::new(ServerLogger::default());
475 let stream_1 = StreamId { value: 1 };
476 let stream_2 = StreamId { value: 2 };
477
478 let binding_1 = handle(stream_1);
479 let binding_2 = handle(stream_2);
480 let binding_3 = handle(stream_1);
481
482 let mut ms = MultiStream::new(logger, TestBackend, MAX_STREAMS);
483 ms.resolve(stream_1, [].into_iter(), false).unwrap();
484 ms.resolve(stream_2, [].into_iter(), false).unwrap();
485
486 ms.resolve(
487 stream_1,
488 [&binding_1, &binding_2, &binding_3].into_iter(),
489 false,
490 )
491 .unwrap();
492
493 let stream1 = ms.streams.get_mut(&stream_1);
494 let index_2 = stream_index(&stream_2, MAX_STREAMS as usize);
495 assert_eq!(stream1.last_synced.get(&index_2), Some(&1));
496 assert_eq!(stream1.cursor, 2);
497
498 let stream2 = ms.streams.get_mut(&stream_2);
499 assert!(stream2.last_synced.is_empty());
500 assert_eq!(stream2.cursor, 1);
501 }
502
503 fn handle(stream: StreamId) -> Binding {
504 Handle::new(stream, 10).binding()
505 }
506
507 struct TestBackend;
508
509 #[derive(Debug)]
510 struct TestStream {}
511
512 #[derive(Debug)]
513 struct TestEvent {}
514
515 impl EventStreamBackend for TestBackend {
516 type Stream = TestStream;
517 type Event = TestEvent;
518
519 fn create_stream(&self) -> Self::Stream {
520 TestStream {}
521 }
522
523 fn flush(_stream: &mut Self::Stream) -> Self::Event {
524 TestEvent {}
525 }
526
527 fn wait_event(_stream: &mut Self::Stream, _event: Self::Event) {}
528
529 fn wait_event_sync(_event: Self::Event) -> Result<(), ServerError> {
530 Ok(())
531 }
532
533 fn handle_cursor(_stream: &Self::Stream, _handle: &Binding) -> u64 {
534 0
535 }
536
537 fn is_healthy(_stream: &Self::Stream) -> bool {
538 true
539 }
540 }
541}