falco_plugin/source/
event_batch.rs

1use falco_event::events::EventToBytes;
2
3/// # An object that describes a batch of events
4///
5/// This is only available by reference, not by ownership, since the data needs to outlive
6/// the plugin API call and is stored elsewhere (in a wrapper struct that's not exposed to
7/// plugin developers)
8#[derive(Debug)]
9pub struct EventBatch<'a> {
10    alloc: &'a bumpalo::Bump,
11    pointers: bumpalo::collections::Vec<'a, *const u8>,
12}
13
14impl EventBatch<'_> {
15    pub(super) fn new(alloc: &bumpalo::Bump) -> EventBatch<'_> {
16        let pointers = bumpalo::collections::Vec::new_in(alloc);
17        EventBatch { alloc, pointers }
18    }
19
20    /// # Add an event to a batch
21    ///
22    /// The event can be any type, but please note that the framework may have different
23    /// opinions on this. For example, only source plugins with the `syscall` source can generate
24    /// events other than [`source::PluginEvent`](`crate::source::PluginEvent`)
25    ///
26    /// **Note**: to generate such events, you may use
27    /// the [`source::SourcePluginInstance::plugin_event`](`crate::source::SourcePluginInstance::plugin_event`)
28    /// helper method.
29    pub fn add(&mut self, event: impl EventToBytes) -> std::io::Result<()> {
30        let mut event_buf =
31            bumpalo::collections::Vec::with_capacity_in(event.binary_size(), self.alloc);
32        event.write(&mut event_buf)?;
33        self.pointers.push(event_buf.as_ptr());
34        // SAFETY: Don't drop the Vec. The memory must stay in the bump allocator
35        // until this batch is processed by Falco. It will be reclaimed when
36        // the arena is reset before the next batch.
37        std::mem::forget(event_buf);
38        Ok(())
39    }
40
41    /// # Reserve space for a specific number of events
42    ///
43    /// If your plugin knows it's going to generate a specific number of events
44    /// in a particular batch, it can call this method to preallocate some space
45    /// and save a bit of overhead.
46    ///
47    /// The passed value is only a hint, the actual batch can be smaller or larger
48    /// than the reserved size, but that mostly defeats the purpose of reserving
49    /// space
50    pub fn reserve(&mut self, num_events: usize) {
51        self.pointers.reserve(num_events);
52    }
53
54    pub(super) fn get_events(&self) -> &[*const u8] {
55        self.pointers.as_slice()
56    }
57}