@@ -57,8 +57,8 @@ pub use pool::*;
57
57
/// `GroupByHashExec`. It does NOT track and limit memory used internally by
58
58
/// other operators such as `DataSourceExec` or the `RecordBatch`es that flow
59
59
/// between operators. Furthermore, operators should not reserve memory for the
60
- /// batches they produce. Instead, if a parent operator needs to hold batches
61
- /// from its children in memory for an extended period, it is the parent
60
+ /// batches they produce. Instead, if a consumer operator needs to hold batches
61
+ /// from its producers in memory for an extended period, it is the consumer
62
62
/// operator's responsibility to reserve the necessary memory for those batches.
63
63
///
64
64
/// In order to avoid allocating memory until the OS or the container system
@@ -98,6 +98,67 @@ pub use pool::*;
98
98
/// operator will spill the intermediate buffers to disk, and release memory
99
99
/// from the memory pool, and continue to retry memory reservation.
100
100
///
101
+ /// # Related Structs
102
+ ///
103
+ /// To better understand memory management in DataFusion, here are the key structs
104
+ /// and their relationships:
105
+ ///
106
+ /// - [`MemoryConsumer`]: A named allocation traced by a particular operator. If an
107
+ /// execution is parallelized, and there are multiple partitions of the same
108
+ /// operator, each partition will have a separate `MemoryConsumer`.
109
+ /// - `SharedRegistration`: A registration of a `MemoryConsumer` with a `MemoryPool`.
110
+ /// `SharedRegistration` and `MemoryPool` have a many-to-one relationship. `MemoryPool`
111
+ /// implementation can decide how to allocate memory based on the registered consumers.
112
+ /// (e.g. `FairSpillPool` will try to share available memory evenly among all registered
113
+ /// consumers)
114
+ /// - [`MemoryReservation`]: Each `MemoryConsumer`/operator can have multiple
115
+ /// `MemoryReservation`s for different internal data structures. The relationship
116
+ /// between `MemoryConsumer` and `MemoryReservation` is one-to-many. This design
117
+ /// enables cleaner operator implementations:
118
+ /// - Different `MemoryReservation`s can be used for different purposes
119
+ /// - `MemoryReservation` follows RAII principles - to release a reservation,
120
+ /// simply drop the `MemoryReservation` object. When all `MemoryReservation`s
121
+ /// for a `SharedRegistration` are dropped, the `SharedRegistration` is dropped
122
+ /// when its reference count reaches zero, automatically unregistering the
123
+ /// `MemoryConsumer` from the `MemoryPool`.
124
+ ///
125
+ /// ## Relationship Diagram
126
+ ///
127
+ /// ```text
128
+ /// ┌──────────────────┐ ┌──────────────────┐
129
+ /// │MemoryReservation │ │MemoryReservation │
130
+ /// └───┬──────────────┘ └──────────────────┘ ......
131
+ /// │belongs to │
132
+ /// │ ┌───────────────────────┘ │ │
133
+ /// │ │ │ │
134
+ /// ▼ ▼ ▼ ▼
135
+ /// ┌────────────────────────┐ ┌────────────────────────┐
136
+ /// │ SharedRegistration │ │ SharedRegistration │
137
+ /// │ ┌────────────────┐ │ │ ┌────────────────┐ │
138
+ /// │ │ │ │ │ │ │ │
139
+ /// │ │ MemoryConsumer │ │ │ │ MemoryConsumer │ │
140
+ /// │ │ │ │ │ │ │ │
141
+ /// │ └────────────────┘ │ │ └────────────────┘ │
142
+ /// └────────────┬───────────┘ └────────────┬───────────┘
143
+ /// │ │
144
+ /// │ register│into
145
+ /// │ │
146
+ /// └─────────────┐ ┌──────────────┘
147
+ /// │ │
148
+ /// ▼ ▼
149
+ /// ╔═══════════════════════════════════════════════════╗
150
+ /// ║ ║
151
+ /// ║ MemoryPool ║
152
+ /// ║ ║
153
+ /// ╚═══════════════════════════════════════════════════╝
154
+ /// ```
155
+ ///
156
+ /// For example, there are two parallel partitions of an operator X: each partition
157
+ /// corresponds to a `MemoryConsumer` in the above diagram. Inside each partition of
158
+ /// operator X, there are typically several `MemoryReservation`s - one for each
159
+ /// internal data structure that needs memory tracking (e.g., 1 reservation for the hash
160
+ /// table, and 1 reservation for buffered input, etc.).
161
+ ///
101
162
/// # Implementing `MemoryPool`
102
163
///
103
164
/// You can implement a custom allocation policy by implementing the
0 commit comments