1use std::any::Any;
16use std::collections::{HashMap, HashSet};
17use std::fmt::Debug;
18use std::sync::Arc;
19use std::time::Duration;
20
21use api::v1::value::ValueData;
22use api::v1::{ColumnSchema, Row, RowInsertRequest, RowInsertRequests, Rows};
23use async_trait::async_trait;
24use backon::{BackoffBuilder, ExponentialBuilder};
25use common_telemetry::{debug, error, info, warn};
26use common_time::timestamp::{TimeUnit, Timestamp};
27use humantime::format_duration;
28use itertools::Itertools;
29use serde::{Deserialize, Serialize};
30use store_api::mito_engine_options::{APPEND_MODE_KEY, TTL_KEY};
31use tokio::sync::mpsc::{Receiver, Sender, channel};
32use tokio::task::JoinHandle;
33use tokio::time::sleep;
34use tokio_util::sync::CancellationToken;
35
36use crate::error::{MismatchedSchemaSnafu, Result};
37use crate::event_table::{
38 PAYLOAD_COLUMN, TIMESTAMP_COLUMN, TYPE_COLUMN, base_column_schemas, jsonb_value,
39};
40
41pub const DEFAULT_EVENTS_TABLE_NAME: &str = "events";
43
44pub const EVENTS_TABLE_TYPE_COLUMN_NAME: &str = TYPE_COLUMN.name();
46pub const EVENTS_TABLE_PAYLOAD_COLUMN_NAME: &str = PAYLOAD_COLUMN.name();
48pub const EVENTS_TABLE_TIMESTAMP_COLUMN_NAME: &str = TIMESTAMP_COLUMN.name();
50
51pub type EventRecorderRef = Arc<dyn EventRecorder>;
53
54pub type EventTypeFilterRef = Arc<EventTypeFilter>;
56
57#[derive(Debug, Clone, PartialEq, Eq, Default)]
59pub enum EventTypeFilter {
60 #[default]
62 All,
63 Only(HashSet<String>),
65}
66
67impl EventTypeFilter {
68 pub fn allows(&self, event_type: &str) -> bool {
70 match self {
71 Self::All => true,
72 Self::Only(event_types) => event_types.contains(event_type),
73 }
74 }
75}
76
77fn deserialize_event_types<'de, D>(
78 deserializer: D,
79) -> std::result::Result<EventTypeFilterRef, D::Error>
80where
81 D: serde::Deserializer<'de>,
82{
83 HashSet::<String>::deserialize(deserializer)
84 .map(|event_types| Arc::new(EventTypeFilter::Only(event_types)))
85}
86
87fn serialize_event_types<S>(
88 event_types: &EventTypeFilterRef,
89 serializer: S,
90) -> std::result::Result<S::Ok, S::Error>
91where
92 S: serde::Serializer,
93{
94 match event_types.as_ref() {
95 EventTypeFilter::All => serializer.serialize_none(),
96 EventTypeFilter::Only(event_types) => {
97 let mut event_types = event_types.iter().collect::<Vec<_>>();
98 event_types.sort_unstable();
99 event_types.serialize(serializer)
100 }
101 }
102}
103
104fn event_type_filter_is_all(event_types: &EventTypeFilterRef) -> bool {
105 matches!(event_types.as_ref(), EventTypeFilter::All)
106}
107
108pub const DEFAULT_FLUSH_INTERVAL_SECONDS: Duration = Duration::from_secs(5);
110const DEFAULT_EVENTS_TABLE_TTL: Duration = Duration::from_secs(90 * 86400);
112pub const DEFAULT_COMPACTION_TIME_WINDOW: Duration = Duration::from_secs(86400);
114const DEFAULT_CHANNEL_SIZE: usize = 2048;
116const DEFAULT_BUFFER_SIZE: usize = 100;
118const DEFAULT_MAX_RETRY_TIMES: u64 = 3;
120
121pub trait Event: Send + Sync + Debug {
130 fn table_name(&self) -> &str {
132 DEFAULT_EVENTS_TABLE_NAME
133 }
134
135 fn event_type(&self) -> &str;
137
138 fn timestamp(&self) -> Timestamp {
140 Timestamp::current_time(TimeUnit::Nanosecond)
141 }
142
143 fn json_payload(&self) -> Result<serde_json::Value> {
145 Ok(serde_json::Value::Null)
146 }
147
148 fn extra_schema(&self) -> Vec<ColumnSchema> {
150 vec![]
151 }
152
153 fn extra_rows(&self) -> Result<Vec<Row>> {
155 Ok(vec![Row { values: vec![] }])
156 }
157
158 fn as_any(&self) -> &dyn Any;
160}
161
162pub trait Eventable: Send + Sync + Debug {
164 fn to_event(&self) -> Option<Box<dyn Event>> {
166 None
167 }
168}
169
170#[allow(clippy::borrowed_box)]
172pub fn group_events_by_type(events: &[Box<dyn Event>]) -> HashMap<&str, Vec<&Box<dyn Event>>> {
173 events
174 .iter()
175 .into_grouping_map_by(|event| event.event_type())
176 .collect()
177}
178
179#[allow(clippy::borrowed_box)]
181pub fn build_row_inserts_request(events: &[&Box<dyn Event>]) -> Result<RowInsertRequests> {
182 validate_events(events)?;
184
185 let event = &events[0];
187 let extra_schema = event.extra_schema();
188 let mut schema: Vec<ColumnSchema> = Vec::with_capacity(3 + extra_schema.len());
189 schema.extend(base_column_schemas());
190 schema.extend(extra_schema);
191
192 let mut rows: Vec<Row> = Vec::with_capacity(events.len());
193 for event in events {
194 let extra_rows = event.extra_rows()?;
195 for extra_row in extra_rows {
196 let mut values = Vec::with_capacity(3 + extra_row.values.len());
197 values.extend([
198 ValueData::StringValue(event.event_type().to_string()).into(),
199 jsonb_value(&event.json_payload()?),
200 ValueData::TimestampNanosecondValue(event.timestamp().value()).into(),
201 ]);
202 values.extend(extra_row.values);
203 rows.push(Row { values });
204 }
205 }
206
207 Ok(RowInsertRequests {
208 inserts: vec![RowInsertRequest {
209 table_name: event.table_name().to_string(),
210 rows: Some(Rows { schema, rows }),
211 }],
212 })
213}
214
215#[allow(clippy::borrowed_box)]
217fn validate_events(events: &[&Box<dyn Event>]) -> Result<()> {
218 let extra_schema = events[0].extra_schema();
220 for event in events {
221 if event.extra_schema() != extra_schema {
222 MismatchedSchemaSnafu {
223 expected: extra_schema.clone(),
224 actual: event.extra_schema(),
225 }
226 .fail()?;
227 }
228 }
229 Ok(())
230}
231
232pub trait EventRecorder: Send + Sync + Debug + 'static {
234 fn record(&self, event: Box<dyn Event>);
236
237 fn event_type_filter(&self) -> EventTypeFilterRef;
239
240 fn close(&self);
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
246pub struct EventHandlerOptions {
247 pub ttl: Duration,
249 pub append_mode: bool,
251}
252
253impl Default for EventHandlerOptions {
254 fn default() -> Self {
255 Self {
256 ttl: DEFAULT_EVENTS_TABLE_TTL,
257 append_mode: true,
258 }
259 }
260}
261
262impl EventHandlerOptions {
263 pub fn to_hints(&self) -> Vec<(&str, String)> {
265 vec![
266 (TTL_KEY, format_duration(self.ttl).to_string()),
267 (APPEND_MODE_KEY, self.append_mode.to_string()),
268 ]
269 }
270}
271
272#[async_trait]
274pub trait EventHandler: Send + Sync + 'static {
275 async fn handle(&self, events: &[Box<dyn Event>]) -> Result<()>;
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
282pub struct EventRecorderOptions {
283 #[serde(default = "default_events_table_ttl", with = "humantime_serde")]
285 pub ttl: Duration,
286 #[serde(
288 default,
289 deserialize_with = "deserialize_event_types",
290 serialize_with = "serialize_event_types",
291 skip_serializing_if = "event_type_filter_is_all"
292 )]
293 pub event_types: EventTypeFilterRef,
294 #[serde(skip, default = "default_flush_interval")]
300 pub flush_interval: Duration,
301}
302
303fn default_events_table_ttl() -> Duration {
304 DEFAULT_EVENTS_TABLE_TTL
305}
306
307fn default_flush_interval() -> Duration {
308 DEFAULT_FLUSH_INTERVAL_SECONDS
309}
310
311impl Default for EventRecorderOptions {
312 fn default() -> Self {
313 Self {
314 ttl: DEFAULT_EVENTS_TABLE_TTL,
315 event_types: Arc::new(EventTypeFilter::All),
316 flush_interval: DEFAULT_FLUSH_INTERVAL_SECONDS,
317 }
318 }
319}
320
321#[derive(Debug)]
323pub struct EventRecorderImpl {
324 tx: Sender<Box<dyn Event>>,
326 event_types: EventTypeFilterRef,
328 cancel_token: CancellationToken,
330 handle: Option<JoinHandle<()>>,
332}
333
334impl EventRecorderImpl {
335 pub fn new(event_handler: Box<dyn EventHandler>) -> Self {
336 Self::with_event_type_filter(
337 event_handler,
338 Arc::new(EventTypeFilter::All),
339 DEFAULT_FLUSH_INTERVAL_SECONDS,
340 )
341 }
342
343 pub fn with_event_type_filter(
345 event_handler: Box<dyn EventHandler>,
346 event_types: EventTypeFilterRef,
347 flush_interval: Duration,
348 ) -> Self {
349 let (tx, rx) = channel(DEFAULT_CHANNEL_SIZE);
350 let cancel_token = CancellationToken::new();
351
352 let mut recorder = Self {
353 tx,
354 event_types,
355 handle: None,
356 cancel_token: cancel_token.clone(),
357 };
358
359 let processor =
360 EventProcessor::new(rx, event_handler, flush_interval, DEFAULT_MAX_RETRY_TIMES)
361 .with_cancel_token(cancel_token);
362
363 let handle = tokio::spawn(async move {
365 processor.process(DEFAULT_BUFFER_SIZE).await;
366 });
367
368 recorder.handle = Some(handle);
369
370 recorder
371 }
372}
373
374impl EventRecorder for EventRecorderImpl {
375 fn record(&self, event: Box<dyn Event>) {
377 if !self.event_types.allows(event.event_type()) {
378 return;
379 }
380
381 if let Err(e) = self.tx.try_send(event) {
382 error!("Failed to send event to the background processor: {}", e);
383 }
384 }
385
386 fn event_type_filter(&self) -> EventTypeFilterRef {
387 self.event_types.clone()
388 }
389
390 fn close(&self) {
392 self.cancel_token.cancel();
393 }
394}
395
396impl Drop for EventRecorderImpl {
397 fn drop(&mut self) {
398 if let Some(handle) = self.handle.take() {
399 handle.abort();
400 info!("Aborted the background processor in event recorder");
401 }
402 }
403}
404
405struct EventProcessor {
406 rx: Receiver<Box<dyn Event>>,
407 event_handler: Box<dyn EventHandler>,
408 max_retry_times: u64,
409 process_interval: Duration,
410 cancel_token: CancellationToken,
411}
412
413impl EventProcessor {
414 fn new(
415 rx: Receiver<Box<dyn Event>>,
416 event_handler: Box<dyn EventHandler>,
417 process_interval: Duration,
418 max_retry_times: u64,
419 ) -> Self {
420 Self {
421 rx,
422 event_handler,
423 max_retry_times,
424 process_interval,
425 cancel_token: CancellationToken::new(),
426 }
427 }
428
429 fn with_cancel_token(mut self, cancel_token: CancellationToken) -> Self {
430 self.cancel_token = cancel_token;
431 self
432 }
433
434 async fn process(mut self, buffer_size: usize) {
435 info!("Start the background processor in event recorder to handle the received events.");
436
437 let mut buffer = Vec::with_capacity(buffer_size);
438 let mut interval = tokio::time::interval(self.process_interval);
439
440 loop {
441 tokio::select! {
442 maybe_event = self.rx.recv() => {
443 if let Some(maybe_event) = maybe_event {
444 debug!("Received event: {:?}", maybe_event);
445
446 if buffer.len() >= buffer_size {
447 debug!(
448 "Flushing events to the event handler because the buffer is full with {} events",
449 buffer.len()
450 );
451 self.flush_events_to_handler(&mut buffer).await;
452 }
453
454 buffer.push(maybe_event);
456 } else {
457 self.flush_events_to_handler(&mut buffer).await;
459 break;
460 }
461 }
462 _ = self.cancel_token.cancelled() => {
464 warn!("Received a cancel signal, flushing the buffer and exiting the loop");
465 self.flush_events_to_handler(&mut buffer).await;
466 break;
467 }
468 _ = interval.tick() => {
470 self.flush_events_to_handler(&mut buffer).await;
471 }
472 }
473 }
474 }
475
476 async fn flush_events_to_handler(&self, buffer: &mut Vec<Box<dyn Event>>) {
478 if !buffer.is_empty() {
479 debug!("Flushing {} events to the event handler", buffer.len());
480
481 let mut backoff = ExponentialBuilder::default()
482 .with_min_delay(Duration::from_millis(
483 DEFAULT_FLUSH_INTERVAL_SECONDS.as_millis() as u64 / self.max_retry_times.max(1),
484 ))
485 .with_max_delay(Duration::from_millis(
486 DEFAULT_FLUSH_INTERVAL_SECONDS.as_millis() as u64,
487 ))
488 .with_max_times(self.max_retry_times as usize)
489 .build();
490
491 loop {
492 match self.event_handler.handle(buffer).await {
493 Ok(()) => {
494 debug!("Successfully handled {} events", buffer.len());
495 break;
496 }
497 Err(e) => {
498 if let Some(d) = backoff.next() {
499 warn!(e; "Failed to handle events, retrying...");
500 sleep(d).await;
501 continue;
502 } else {
503 warn!(
504 e; "Failed to handle events after {} retries",
505 self.max_retry_times
506 );
507 break;
508 }
509 }
510 }
511 }
512 }
513
514 buffer.clear();
516 }
517}
518
519#[cfg(test)]
520mod tests {
521 use std::collections::HashSet;
522 use std::sync::atomic::{AtomicUsize, Ordering};
523
524 use serde_json::json;
525
526 use super::*;
527
528 #[derive(Debug)]
529 struct TestEvent {}
530
531 impl Event for TestEvent {
532 fn event_type(&self) -> &str {
533 "test_event"
534 }
535
536 fn json_payload(&self) -> Result<serde_json::Value> {
537 Ok(json!({"procedure_id": "1234567890"}))
538 }
539
540 fn as_any(&self) -> &dyn Any {
541 self
542 }
543 }
544
545 struct TestEventHandlerImpl {}
546
547 #[async_trait]
548 impl EventHandler for TestEventHandlerImpl {
549 async fn handle(&self, events: &[Box<dyn Event>]) -> Result<()> {
550 let event = events
551 .first()
552 .unwrap()
553 .as_any()
554 .downcast_ref::<TestEvent>()
555 .unwrap();
556 assert_eq!(
557 event.json_payload().unwrap(),
558 json!({"procedure_id": "1234567890"}),
559 );
560 assert_eq!(event.event_type(), "test_event");
561 Ok(())
562 }
563 }
564
565 #[test]
566 fn test_event_type_filter_defaults_to_all() {
567 let options = toml::from_str::<EventRecorderOptions>("ttl = '90d'").unwrap();
568
569 assert!(options.event_types.allows("slow_query"));
570 assert!(options.event_types.allows("future_event"));
571 }
572
573 #[test]
574 fn test_event_type_filter_deserializes_explicit_empty_array() {
575 let options =
576 toml::from_str::<EventRecorderOptions>("ttl = '90d'\nevent_types = []").unwrap();
577
578 assert_eq!(
579 options.event_types.as_ref(),
580 &EventTypeFilter::Only(HashSet::new())
581 );
582 }
583
584 #[test]
585 fn test_event_recorder_options_default_ttl_for_partial_table() {
586 let options = toml::from_str::<EventRecorderOptions>("event_types = []").unwrap();
587
588 assert_eq!(DEFAULT_EVENTS_TABLE_TTL, options.ttl);
589 assert_eq!(
590 options.event_types.as_ref(),
591 &EventTypeFilter::Only(HashSet::new())
592 );
593 }
594
595 #[test]
596 fn test_event_type_filter_deserializes_selected_types() {
597 let options = toml::from_str::<EventRecorderOptions>(
598 "ttl = '90d'\nevent_types = ['create_database']",
599 )
600 .unwrap();
601
602 assert!(options.event_types.allows("create_database"));
603 assert!(!options.event_types.allows("drop_database"));
604 }
605
606 struct CountingEventHandler {
607 count: Arc<AtomicUsize>,
608 }
609
610 #[async_trait]
611 impl EventHandler for CountingEventHandler {
612 async fn handle(&self, _events: &[Box<dyn Event>]) -> Result<()> {
613 self.count.fetch_add(1, Ordering::Relaxed);
614 Ok(())
615 }
616 }
617
618 #[tokio::test]
619 async fn test_event_recorder_rejects_filtered_event_before_queueing() {
620 let count = Arc::new(AtomicUsize::new(0));
621 let event_type_filter = Arc::new(EventTypeFilter::Only(HashSet::new()));
622 let mut event_recorder = EventRecorderImpl::with_event_type_filter(
623 Box::new(CountingEventHandler {
624 count: count.clone(),
625 }),
626 event_type_filter.clone(),
627 DEFAULT_FLUSH_INTERVAL_SECONDS,
628 );
629
630 assert!(Arc::ptr_eq(
631 &event_type_filter,
632 &event_recorder.event_type_filter()
633 ));
634
635 event_recorder.record(Box::new(TestEvent {}));
636 event_recorder.close();
637
638 if let Some(handle) = event_recorder.handle.take() {
639 assert!(handle.await.is_ok());
640 }
641 assert_eq!(count.load(Ordering::Relaxed), 0);
642 }
643
644 #[tokio::test]
645 async fn test_event_recorder() {
646 let mut event_recorder = EventRecorderImpl::new(Box::new(TestEventHandlerImpl {}));
647 event_recorder.record(Box::new(TestEvent {}));
648
649 sleep(Duration::from_millis(500)).await;
651
652 event_recorder.close();
654
655 sleep(Duration::from_millis(500)).await;
657
658 if let Some(handle) = event_recorder.handle.take() {
659 assert!(handle.await.is_ok());
660 }
661 }
662
663 struct TestEventHandlerImplShouldPanic {}
664
665 #[async_trait]
666 impl EventHandler for TestEventHandlerImplShouldPanic {
667 async fn handle(&self, events: &[Box<dyn Event>]) -> Result<()> {
668 let event = events
669 .first()
670 .unwrap()
671 .as_any()
672 .downcast_ref::<TestEvent>()
673 .unwrap();
674
675 assert_eq!(
677 event.json_payload().unwrap(),
678 "{\"procedure_id\": \"should_panic\"}"
679 );
680 assert_eq!(event.event_type(), "should_panic");
681 Ok(())
682 }
683 }
684
685 #[tokio::test]
686 async fn test_event_recorder_should_panic() {
687 let mut event_recorder =
688 EventRecorderImpl::new(Box::new(TestEventHandlerImplShouldPanic {}));
689
690 event_recorder.record(Box::new(TestEvent {}));
691
692 sleep(Duration::from_millis(500)).await;
694
695 event_recorder.close();
697
698 sleep(Duration::from_millis(500)).await;
700
701 if let Some(handle) = event_recorder.handle.take() {
702 assert!(handle.await.unwrap_err().is_panic());
703 }
704 }
705
706 #[derive(Debug)]
707 struct TestEventA {}
708
709 impl Event for TestEventA {
710 fn event_type(&self) -> &str {
711 "A"
712 }
713
714 fn as_any(&self) -> &dyn Any {
715 self
716 }
717 }
718
719 #[derive(Debug)]
720 struct TestEventB {}
721
722 impl Event for TestEventB {
723 fn table_name(&self) -> &str {
724 "table_B"
725 }
726
727 fn event_type(&self) -> &str {
728 "B"
729 }
730
731 fn as_any(&self) -> &dyn Any {
732 self
733 }
734 }
735
736 #[derive(Debug)]
737 struct TestEventC {}
738
739 impl Event for TestEventC {
740 fn table_name(&self) -> &str {
741 "table_C"
742 }
743
744 fn event_type(&self) -> &str {
745 "C"
746 }
747
748 fn as_any(&self) -> &dyn Any {
749 self
750 }
751 }
752
753 #[test]
754 fn test_group_events_by_type() {
755 let events: Vec<Box<dyn Event>> = vec![
756 Box::new(TestEventA {}),
757 Box::new(TestEventB {}),
758 Box::new(TestEventA {}),
759 Box::new(TestEventC {}),
760 Box::new(TestEventB {}),
761 Box::new(TestEventC {}),
762 Box::new(TestEventA {}),
763 ];
764
765 let event_groups = group_events_by_type(&events);
766 assert_eq!(event_groups.len(), 3);
767 assert_eq!(event_groups.get("A").unwrap().len(), 3);
768 assert_eq!(event_groups.get("B").unwrap().len(), 2);
769 assert_eq!(event_groups.get("C").unwrap().len(), 2);
770 }
771
772 #[test]
773 fn test_build_row_inserts_request() {
774 let events: Vec<Box<dyn Event>> = vec![
775 Box::new(TestEventA {}),
776 Box::new(TestEventB {}),
777 Box::new(TestEventA {}),
778 Box::new(TestEventC {}),
779 Box::new(TestEventB {}),
780 Box::new(TestEventC {}),
781 Box::new(TestEventA {}),
782 ];
783
784 let event_groups = group_events_by_type(&events);
785 assert_eq!(event_groups.len(), 3);
786 assert_eq!(event_groups.get("A").unwrap().len(), 3);
787 assert_eq!(event_groups.get("B").unwrap().len(), 2);
788 assert_eq!(event_groups.get("C").unwrap().len(), 2);
789
790 for (event_type, events) in event_groups {
791 let row_inserts_request = build_row_inserts_request(&events).unwrap();
792 if event_type == "A" {
793 assert_eq!(row_inserts_request.inserts.len(), 1);
794 assert_eq!(
795 row_inserts_request.inserts[0].table_name,
796 DEFAULT_EVENTS_TABLE_NAME
797 );
798 assert_eq!(
799 row_inserts_request.inserts[0]
800 .rows
801 .as_ref()
802 .unwrap()
803 .rows
804 .len(),
805 3
806 );
807 } else if event_type == "B" {
808 assert_eq!(row_inserts_request.inserts.len(), 1);
809 assert_eq!(row_inserts_request.inserts[0].table_name, "table_B");
810 assert_eq!(
811 row_inserts_request.inserts[0]
812 .rows
813 .as_ref()
814 .unwrap()
815 .rows
816 .len(),
817 2
818 );
819 } else if event_type == "C" {
820 assert_eq!(row_inserts_request.inserts.len(), 1);
821 assert_eq!(row_inserts_request.inserts[0].table_name, "table_C");
822 assert_eq!(
823 row_inserts_request.inserts[0]
824 .rows
825 .as_ref()
826 .unwrap()
827 .rows
828 .len(),
829 2
830 );
831 } else {
832 panic!("Unexpected event type: {}", event_type);
833 }
834 }
835 }
836}