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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//! Types to support memory quota tracking
//!
//! We make these newtypes because we otherwise have a confusing a maze of
//! identical-looking, but supposedly semantically different, [`Account`]s.
//!
//! # Memory tracking architecture in Arti
//!
//! ## Queues
//!
//! The following queues in Arti participate in the memory quota system:
//!
//! * Tor streams ([`StreamAccount`])
//! - inbound data, on its way from the circuit to the stream's user
//! - outbound data, on its way from the stream's user to the circuit
//! * Tor circuits ([`CircuitAccount`])
//! - inbound stream requests, on their way from the circuit to the handling code
//! - inbound data, on its way from the channel
//! * Tor channels ([`ChannelAccount`])
//! - outbound data, on its way from a circuit to the channel
//! (this ought to be accounted to the circuit, TODO #1652)
//!
//! The following data buffers do *not* participate:
//!
//! * Our TLS implementation(s) may have internal buffers.
//! We hope that these buffers will be kept reasonably small,
//! and hooking into them would in any case going be quite hard.
//!
//! * TCP sockets will also buffer data, in the operating system.
//! Hooking into this is not trivial.
//!
//! * Our pluggable transport driver can buffer some data.
//! This should be kept to a minimum for several reasons,
//! so we hope that the buffers are small.
//!
//! * The actual pluggable transport might buffer data.
//! Again, this should be kept to a minimum.
//!
//! ## Overview
//!
//! See the [tor_memquota] crate-level docs for an overview of the memquota system.
//! To summarise:
//!
//! When too much memory is in use, the queue with the oldest data is selected for reclaim.
//! The whole Account relating to the victim queue is torn down.
//! When the victim Account collapses, all its queues collapse too:
//! reading ends give EOF, and writing ends give errors.
//! This will tear down the associated Tor protocol association.
//!
//! All the children Accounts of the victim Account are torn down too.
//! This propagates the collapse to dependent Tor protocol associations.
//!
//! ## Accounting
//!
//! Within Arti we maintain a hierarchy of [`Account`]s.
//! These are wrapped in newtypes, here in `tor_proto::memquota`.
//!
//! * [`ToplevelAccount`]:
//! In a single Arti instance there will be one of these,
//! used for all memory tracking.
//! This is held (shared) by the chanmgr and the circmgr.
//! Unlike the other layer-specific accounts,
//! this is just a type alias for [`MemoryQuotaTracker`].
//! It doesn't support claiming memory directly from it, so it won't be subject to reclaim.
//!
//! * [`ChannelAccount`].
//! Contains (via parentage) everything that goes via a particular Channel.
//! This includes all circuits on the channel, and those circuits' streams.
//!
//! * [`CircuitAccount`].
//! Has the `ChannelAccount` as its parent.
//! So if a queue accounted to a channel is selected for reclaim,
//! that channel, and all of its circuits, will collapse.
//!
//! * [`StreamAccount`].
//! Has the `CircuitAccount` as its parent.
//! So if a queue accounted to a circuit is selected for reclaim,
//! that circuit, and all of its streams, will collapse.
//! If a stream's queue is selected for reclaim, only that stream will collapse.
//! (See [#1661](https://gitlab.torproject.org/tpo/core/arti/-/issues/1661)
//! for discussion of this behaviour.)
//!
//! Thus, killing a single queue will reclaim the memory associated with several other queues.
use ;
use Arc;
use ;
/// An [`Account`], whose type indicates which layer of the stack it's for
//
// Making this a trait rather than ad-hoc output from the derive macro
// makes things more regular, and the documentation easier.
define_derive_deftly!
/// Account for the whole system
///
/// There will typically be only one of these for an entire Arti client or relay.
///
/// This is not really an [`Account`].
/// We don't want anyone to make a Participant from this,
/// because if that Participant were reclaimed, *everything* would be torn down.
///
/// We provide the type alias for consistency/readability at call sites.
///
/// See the [`memquota`](self) module documentation.
pub type ToplevelAccount = ;
/// [`Account`] for a Tor Channel
///
/// Use via the [`SpecificAccount`] impl.
/// See the [`memquota`](self) module documentation.
;
/// [`Account`] for a Tor Circuit
///
/// Use via the [`SpecificAccount`] impl.
/// See the [`memquota`](self) module documentation.
;
/// [`Account`] for a Tor Stream
///
/// Use via the [`SpecificAccount`] impl.
/// See the [`memquota`](self) module documentation.
;