-
Notifications
You must be signed in to change notification settings - Fork 2.2k
fix(enrichment tables): preserve memory enrichment table state on reload #25547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
6583fd7
58b908e
04110a3
0e0952c
0044cc7
a696cb7
664d2ae
bf3173f
d36e743
ed83146
1ed0732
4ab2ce3
f4cb301
e9f9738
961e72f
79eb2b1
2fdd859
b05daa4
12939a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Fixed an issue where memory enrichment table state could be lost or detached from the sink component on configuration reload. | ||
|
|
||
| authors: esensar Quad9DNS |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -142,6 +142,25 @@ impl Memory { | |
| } | ||
| } | ||
|
|
||
| /// Creates a new [Memory] based on the provided config and previous state. | ||
| pub fn from_previous_state( | ||
| config: MemoryConfig, | ||
| prev_state: Box<dyn std::any::Any + Send + Sync>, | ||
| ) -> Self { | ||
| if let Ok(prev_memory) = prev_state.downcast::<Memory>() { | ||
| Self { | ||
| config, | ||
| read_handle_factory: prev_memory.read_handle_factory, | ||
| read_handle: prev_memory.read_handle, | ||
| write_handle: prev_memory.write_handle, | ||
| expired_items_sender: prev_memory.expired_items_sender, | ||
| expired_items_receiver: prev_memory.expired_items_receiver, | ||
| } | ||
| } else { | ||
| Self::new(config) | ||
| } | ||
| } | ||
|
|
||
| pub(super) fn get_read_handle(&self) -> &evmap::ReadHandle<String, MemoryEntry> { | ||
| self.read_handle | ||
| .get_or(|| self.read_handle_factory.handle()) | ||
|
|
@@ -382,9 +401,15 @@ impl Table for Memory { | |
| Vec::new() | ||
| } | ||
|
|
||
| /// Doesn't need reload, data is written directly | ||
| /// Has to be reloaded always, because a new component is created to insert data into it | ||
| fn needs_reload(&self) -> bool { | ||
| false | ||
| true | ||
|
Comment on lines
405
to
+406
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
With the default Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| fn extract_state(&self) -> Option<Box<dyn std::any::Any + Send + Sync>> { | ||
| let writer = self.write_handle.lock().expect("mutex poisoned"); | ||
| self.flush(writer); | ||
| Some(Box::new(self.clone())) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -465,6 +490,7 @@ mod tests { | |
|
|
||
| use super::*; | ||
| use crate::{ | ||
| config::EnrichmentTableConfig, | ||
| enrichment_tables::memory::{ | ||
| config::MemorySourceConfig, internal_events::InternalMetricsConfig, | ||
| }, | ||
|
|
@@ -501,6 +527,43 @@ mod tests { | |
| ); | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn extract_state_preserves_data() { | ||
| let memory = Memory::new(Default::default()); | ||
| memory.handle_value(ObjectMap::from([("test_key".into(), Value::from(5))])); | ||
|
|
||
| let condition = Condition::Equals { | ||
| field: "key", | ||
| value: Value::from("test_key"), | ||
| }; | ||
|
|
||
| let expected = ObjectMap::from([ | ||
| ("key".into(), Value::from("test_key")), | ||
| ("ttl".into(), Value::from(memory.config.ttl)), | ||
| ("value".into(), Value::from(5)), | ||
| ]); | ||
| assert_eq!( | ||
| Ok(expected.clone()), | ||
| memory.find_table_row( | ||
| Case::Sensitive, | ||
| std::slice::from_ref(&condition), | ||
| None, | ||
| None, | ||
| None | ||
| ) | ||
| ); | ||
|
|
||
| // Now build a new table using old state | ||
| let new_memory = MemoryConfig::default() | ||
| .build(&Default::default(), memory.extract_state()) | ||
| .await | ||
| .unwrap(); | ||
| assert_eq!( | ||
| Ok(expected), | ||
| new_memory.find_table_row(Case::Sensitive, &[condition], None, None, None) | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn calculates_ttl() { | ||
| let ttl = 100; | ||
|
|
@@ -1023,7 +1086,7 @@ mod tests { | |
| export_expired_items: false, | ||
| source_key: "test".to_string(), | ||
| }); | ||
| let memory = memory_config.get_or_build_memory().await; | ||
| let memory = memory_config.get_or_build_memory(None).await; | ||
| memory.handle_value(ObjectMap::from([("test_key".into(), Value::from(5))])); | ||
|
|
||
| let mut events: Vec<Event> = run_and_assert_source_compliance( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.