vector_common/internal_event/
cached_event.rs1use std::{
2 collections::HashMap,
3 hash::Hash,
4 sync::{Arc, RwLock},
5};
6
7use derivative::Derivative;
8
9use super::{InternalEventHandle, RegisterInternalEvent};
10
11#[derive(Derivative)]
21#[derivative(Clone(bound = "T: Clone"))]
22pub struct RegisteredEventCache<T, Event: RegisterTaggedInternalEvent> {
23 fixed_tags: T,
24 cache: Arc<
25 RwLock<
26 HashMap<
27 <Event as RegisterTaggedInternalEvent>::Tags,
28 <Event as RegisterInternalEvent>::Handle,
29 >,
30 >,
31 >,
32}
33
34pub trait RegisterTaggedInternalEvent: RegisterInternalEvent {
37 type Tags;
40
41 type Fixed;
44
45 fn register(fixed: Self::Fixed, tags: Self::Tags) -> <Self as RegisterInternalEvent>::Handle;
46}
47
48impl<Event, EventHandle, Data, Tags, FixedTags> RegisteredEventCache<FixedTags, Event>
49where
50 Data: Sized,
51 EventHandle: InternalEventHandle<Data = Data>,
52 Tags: Clone + Eq + Hash,
53 FixedTags: Clone,
54 Event: RegisterInternalEvent<Handle = EventHandle>
55 + RegisterTaggedInternalEvent<Tags = Tags, Fixed = FixedTags>,
56{
57 pub fn new(fixed_tags: FixedTags) -> Self {
60 Self {
61 fixed_tags,
62 cache: Arc::default(),
63 }
64 }
65
66 pub fn emit(&self, tags: &Tags, value: Data) {
74 let read = self.cache.read().unwrap();
75 if let Some(event) = read.get(tags) {
76 event.emit(value);
77 } else {
78 let event = <Event as RegisterTaggedInternalEvent>::register(
79 self.fixed_tags.clone(),
80 tags.clone(),
81 );
82 event.emit(value);
83
84 drop(read);
86 self.cache.write().unwrap().insert(tags.clone(), event);
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 #![allow(unreachable_pub)]
94 use metrics::{counter, Counter};
95
96 use super::*;
97
98 crate::registered_event!(
99 TestEvent {
100 fixed: String,
101 dynamic: String,
102 } => {
103 event: Counter = {
104 counter!("test_event_total", "fixed" => self.fixed, "dynamic" => self.dynamic)
105 },
106 }
107
108 fn emit(&self, count: u64) {
109 self.event.increment(count);
110 }
111
112 fn register(fixed: String, dynamic: String) {
113 crate::internal_event::register(TestEvent {
114 fixed,
115 dynamic,
116 })
117 }
118 );
119
120 #[test]
121 fn test_fixed_tag() {
122 let event: RegisteredEventCache<String, TestEvent> =
123 RegisteredEventCache::new("fixed".to_string());
124
125 for tag in 1..=5 {
126 event.emit(&format!("dynamic{tag}"), tag);
127 }
128 }
129}