1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! # `buffer_sv2`
//!
//! Handles memory management for Stratum V2 (Sv2) roles.
//!
//! Provides a memory-efficient buffer pool ([`BufferPool`]) that minimizes allocations and
//! deallocations for high-throughput message frame processing in Sv2 roles. [`Slice`] helps
//! minimize memory allocation overhead by reusing large buffers, improving performance and
//! reducing latency. The [`BufferPool`] tracks the usage of memory slices, using atomic operations
//! and shared state tracking to safely manage memory across multiple threads.
//!
//! ## Memory Structure
//!
//! The [`BufferPool`] manages a contiguous block of memory allocated on the heap, divided into
//! fixed-size slots. Memory allocation within this pool operates in three distinct modes:
//!
//! 1. **Back Mode**: By default, memory is allocated sequentially from the back (end) of the buffer
//! pool. This mode continues until the back slots are fully occupied.
//! 2. **Front Mode**: Once the back slots are exhausted, the [`BufferPool`] checks if any slots at
//! the front (beginning) have been freed. If available, it switches to front mode, allocating
//! memory from the front slots.
//! 3. **Alloc Mode**: If both back and front slots are occupied, the [`BufferPool`] enters alloc
//! mode, where it allocates additional memory directly from the system heap. This mode may
//! introduce performance overhead due to dynamic memory allocation.
//!
//! [`BufferPool`] dynamically transitions between these modes based on slot availability,
//! optimizing memory usage and performance.
//!
//! ## Usage
//!
//! When an incoming Sv2 message is received, it is buffered for processing. The [`BufferPool`]
//! attempts to allocate memory from its internal slots, starting in back mode. If the back slots
//! are full, it checks for available front slots to switch to front mode. If no internal slots are
//! free, it resorts to alloc mode, allocating memory from the system heap.
//!
//! For operations requiring dedicated buffers, the [`Slice`] type manages its own memory using
//! [`Vec<u8>`](alloc::vec::Vec). In high-performance scenarios, [`Slice`] can reference externally
//! managed memory from the [`BufferPool`], reducing dynamic memory allocations and increasing
//! performance.
//!
//! ## Slices are scratch space
//!
//! A [`Slice`] handed out by a [`BufferPool`] holds one of its slots until it is dropped. The pool
//! is meant for frames that are decoded and then dropped: a slice kept alive longer keeps its
//! slot, and once every slot is held, each new frame falls back to system memory. Bytes that have
//! to outlive decoding are copied out: cloning a [`Slice`] copies it into memory the clone owns,
//! and the slot is freed as soon as the original is dropped.
//!
//! ### Debug Mode
//! Provides additional tracking for debugging memory management issues.
extern crate alloc;
pub use crateBufferFromSystemMemory;
pub use BufferPool;
pub use Slice;
/// Interface for working with memory buffers.
///
/// Implemented by [`BufferPool`], which hands out slices of preallocated memory, and by
/// [`BufferFromSystemMemory`], which hands out [`Vec<u8>`](alloc::vec::Vec)s. Utilities are
/// provided to reserve writable memory, read back the frame being written, and hand it out.
///
/// The encoders and decoders of the [`codec_sv2` crate](https://crates.io/crates/codec_sv2) write
/// frames through this trait.