1use crate::{
5 Acquisition, Error, Options, Pool, ResourceId, Retirement, Stats,
6 core::{Acquired, Core, Slot, cancellable},
7};
8use base_scheduler::Cancellation;
9use std::{
10 collections::BTreeMap,
11 ops::Deref,
12 sync::{Arc, Weak},
13};
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub struct Admission {
19 pub max_concurrent: usize,
20 pub opening_credit: Option<usize>,
21}
22impl Admission {
23 pub fn concurrent(max_concurrent: usize) -> Self {
24 Self {
25 max_concurrent,
26 opening_credit: None,
27 }
28 }
29}
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
33pub struct UseId(u64);
34
35#[derive(Clone, Copy, Eq, PartialEq)]
36enum Stage {
37 Reserved,
38 Active,
39 Abandoned,
40 Cleaning,
41}
42
43struct MultiSlot<R> {
44 resource: Arc<R>,
45 admission: Admission,
46 uses: BTreeMap<UseId, Stage>,
47 reserved: usize,
48 active: usize,
49 next_use: u64,
50 draining: bool,
51}
52impl<R: Send + Sync> Slot for MultiSlot<R> {
53 type Resource = Arc<R>;
54 type Acquired = (Arc<R>, UseId);
55 fn available(&self) -> bool {
56 !self.draining
57 && self.uses.len() < self.admission.max_concurrent
58 && self
59 .admission
60 .opening_credit
61 .is_none_or(|credit| self.reserved < credit)
62 }
63 fn acquire(&mut self) -> Self::Acquired {
64 let id = UseId(self.next_use);
65 self.next_use = self
66 .next_use
67 .checked_add(1)
68 .expect("multiplex use identifier space exhausted");
69 self.uses.insert(id, Stage::Reserved);
70 self.reserved += 1;
71 (self.resource.clone(), id)
72 }
73 fn uses(&self) -> usize {
74 self.uses.len()
75 }
76 fn draining(&self) -> bool {
77 self.draining
78 }
79 fn drain(&mut self) {
80 self.draining = true;
81 }
82 fn into_resource(self) -> Arc<R> {
83 self.resource
84 }
85}
86
87pub struct MultiplexPool<R: Send + Sync> {
90 core: Arc<Core<MultiSlot<R>>>,
91}
92impl<R: Send + Sync> Clone for MultiplexPool<R> {
93 fn clone(&self) -> Self {
94 Self {
95 core: self.core.clone(),
96 }
97 }
98}
99impl<R: Send + Sync> MultiplexPool<R> {
100 pub fn new(options: Options) -> Result<Self, Error> {
101 Ok(Self {
102 core: Core::new(options)?,
103 })
104 }
105 pub async fn acquire_or_reserve(
106 &self,
107 cancel: &Cancellation,
108 ) -> Result<Acquisition<MultiplexReservation<R>, MultiplexBuildPermit<R>>, Error> {
109 Ok(match self.core.acquire(cancel).await? {
110 Acquired::Existing(id, (resource, use_id)) => {
111 Acquisition::Existing(MultiplexReservation {
112 core: self.core.clone(),
113 id,
114 use_id,
115 resource,
116 pending: true,
117 })
118 }
119 Acquired::Build(id) => Acquisition::Build(MultiplexBuildPermit {
120 core: self.core.clone(),
121 id,
122 pending: true,
123 }),
124 })
125 }
126 pub fn begin_close(&self) {
127 self.core.begin_close();
128 }
129 pub fn stats(&self) -> Stats {
130 self.core.stats()
131 }
132 pub fn prune(&self, retain: usize) -> usize {
133 self.core.prune(retain)
134 }
135 pub fn try_retirement(&self) -> Option<Retirement<Arc<R>>> {
136 self.core.retirements.pop()
137 }
138 pub async fn next_retirement(
139 &self,
140 cancel: &Cancellation,
141 ) -> Result<Option<Retirement<Arc<R>>>, Error> {
142 self.core.next_retirement(cancel).await
143 }
144 pub async fn wait_closed(&self, cancel: &Cancellation) -> Result<(), Error> {
145 self.core.wait_closed(cancel).await
146 }
147}
148impl<R: Send + Sync> Pool for MultiplexPool<R> {
149 type Permit = MultiplexReservation<R>;
150 type BuildPermit = MultiplexBuildPermit<R>;
151 async fn acquire_or_reserve(
152 &self,
153 cancel: &Cancellation,
154 ) -> Result<Acquisition<Self::Permit, Self::BuildPermit>, Error> {
155 self.acquire_or_reserve(cancel).await
156 }
157 fn begin_close(&self) {
158 self.begin_close();
159 }
160 fn stats(&self) -> Stats {
161 self.stats()
162 }
163}
164
165pub struct MultiplexBuildPermit<R: Send + Sync> {
168 core: Arc<Core<MultiSlot<R>>>,
169 id: ResourceId,
170 pending: bool,
171}
172impl<R: Send + Sync> MultiplexBuildPermit<R> {
173 pub fn id(&self) -> ResourceId {
174 self.id
175 }
176 pub fn commit(
180 mut self,
181 resource: R,
182 admission: Admission,
183 ) -> Result<MultiplexResource<R>, Error> {
184 let slot = MultiSlot {
185 resource: Arc::new(resource),
186 admission,
187 uses: BTreeMap::new(),
188 reserved: 0,
189 active: 0,
190 next_use: 0,
191 draining: false,
192 };
193 self.core.commit(self.id, slot)?;
194 self.pending = false;
195 Ok(MultiplexResource {
196 core: Arc::downgrade(&self.core),
197 id: self.id,
198 })
199 }
200}
201impl<R: Send + Sync> Drop for MultiplexBuildPermit<R> {
202 fn drop(&mut self) {
203 if self.pending {
204 self.core.abort_build(self.id);
205 }
206 }
207}
208
209pub struct MultiplexResource<R: Send + Sync> {
213 core: Weak<Core<MultiSlot<R>>>,
214 id: ResourceId,
215}
216impl<R: Send + Sync> Clone for MultiplexResource<R> {
217 fn clone(&self) -> Self {
218 Self {
219 core: self.core.clone(),
220 id: self.id,
221 }
222 }
223}
224impl<R: Send + Sync> MultiplexResource<R> {
225 pub fn id(&self) -> ResourceId {
226 self.id
227 }
228 pub fn retire(&self) -> bool {
229 self.core.upgrade().is_some_and(|core| core.retire(self.id))
230 }
231 pub fn update(&self, admission: Admission) -> bool {
234 let Some(core) = self.core.upgrade() else {
235 return false;
236 };
237 {
238 let mut state = core.lock();
239 let Some(slot) = state.slots.get_mut(&self.id) else {
240 return false;
241 };
242 if slot.draining {
243 return false;
244 }
245 slot.admission = admission;
246 }
247 core.accounting.notify();
248 true
249 }
250 pub fn try_abandoned(&self) -> Option<MultiplexAbandonedUse<R>> {
251 let core = self.core.upgrade()?;
252 let (use_id, resource) = {
253 let mut state = core.lock();
254 let slot = state.slots.get_mut(&self.id)?;
255 let (&use_id, stage) = slot
256 .uses
257 .iter_mut()
258 .find(|(_, stage)| **stage == Stage::Abandoned)?;
259 *stage = Stage::Cleaning;
260 (use_id, slot.resource.clone())
261 };
262 Some(MultiplexAbandonedUse {
263 core,
264 id: self.id,
265 use_id,
266 resource,
267 pending: true,
268 })
269 }
270 pub async fn next_abandoned(
273 &self,
274 cancel: &Cancellation,
275 ) -> Result<Option<MultiplexAbandonedUse<R>>, Error> {
276 loop {
277 cancel.check()?;
278 let Some(core) = self.core.upgrade() else {
279 return Ok(None);
280 };
281 event_listener::listener!(core.accounting.changed => listener);
282 if let Some(abandoned) = self.try_abandoned() {
283 return Ok(Some(abandoned));
284 }
285 if !core.lock().slots.contains_key(&self.id) {
286 return Ok(None);
287 }
288 cancellable(listener, cancel).await?;
289 }
290 }
291}
292
293pub struct MultiplexReservation<R: Send + Sync> {
296 core: Arc<Core<MultiSlot<R>>>,
297 id: ResourceId,
298 use_id: UseId,
299 resource: Arc<R>,
300 pending: bool,
301}
302impl<R: Send + Sync> MultiplexReservation<R> {
303 pub fn id(&self) -> UseId {
304 self.use_id
305 }
306 pub fn resource_id(&self) -> ResourceId {
307 self.id
308 }
309 pub fn activate(mut self) -> Result<MultiplexUse<R>, Error> {
313 let (accepted, retired) = {
314 let mut state = self.core.lock();
315 let closed = state.closed;
316 let slot = state.slots.get_mut(&self.id).unwrap();
317 assert!(slot.uses.remove(&self.use_id) == Some(Stage::Reserved));
318 slot.reserved -= 1;
319 let accepted = !closed
320 && !slot.draining
321 && slot.active < slot.admission.max_concurrent
322 && slot.admission.opening_credit != Some(0);
323 if accepted {
324 slot.uses.insert(self.use_id, Stage::Active);
325 slot.active += 1;
326 if let Some(credit) = &mut slot.admission.opening_credit {
327 *credit -= 1;
328 }
329 }
330 (accepted, self.core.remove_if_drained(&mut state, self.id))
331 };
332 self.pending = false;
333 self.core.enqueue(self.id, retired);
334 if !accepted {
335 return Err(Error::AdmissionChanged);
336 }
337 Ok(MultiplexUse {
338 core: self.core.clone(),
339 id: self.id,
340 use_id: self.use_id,
341 resource: self.resource.clone(),
342 pending: true,
343 })
344 }
345}
346impl<R: Send + Sync> Deref for MultiplexReservation<R> {
347 type Target = R;
348 fn deref(&self) -> &R {
349 &self.resource
350 }
351}
352impl<R: Send + Sync> Drop for MultiplexReservation<R> {
353 fn drop(&mut self) {
354 if !self.pending {
355 return;
356 }
357 let retired = {
358 let mut state = self.core.lock();
359 let slot = state.slots.get_mut(&self.id).unwrap();
360 assert!(slot.uses.remove(&self.use_id) == Some(Stage::Reserved));
361 slot.reserved -= 1;
362 self.core.remove_if_drained(&mut state, self.id)
363 };
364 self.core.enqueue(self.id, retired);
365 }
366}
367
368fn finish<R: Send + Sync>(core: &Core<MultiSlot<R>>, id: ResourceId, use_id: UseId) {
369 let retired = {
370 let mut state = core.lock();
371 let slot = state.slots.get_mut(&id).unwrap();
372 let stage = slot.uses.remove(&use_id).unwrap();
373 assert!(stage == Stage::Active || stage == Stage::Cleaning);
374 slot.active -= 1;
375 core.remove_if_drained(&mut state, id)
376 };
377 core.enqueue(id, retired);
378}
379fn abandon<R: Send + Sync>(core: &Core<MultiSlot<R>>, id: ResourceId, use_id: UseId) {
380 {
381 let mut state = core.lock();
382 let stage = state
383 .slots
384 .get_mut(&id)
385 .unwrap()
386 .uses
387 .get_mut(&use_id)
388 .unwrap();
389 assert!(*stage == Stage::Active || *stage == Stage::Cleaning);
390 *stage = Stage::Abandoned;
391 }
392 core.accounting.notify();
393}
394
395pub struct MultiplexUse<R: Send + Sync> {
399 core: Arc<Core<MultiSlot<R>>>,
400 id: ResourceId,
401 use_id: UseId,
402 resource: Arc<R>,
403 pending: bool,
404}
405impl<R: Send + Sync> MultiplexUse<R> {
406 pub fn id(&self) -> UseId {
407 self.use_id
408 }
409 pub fn resource_id(&self) -> ResourceId {
410 self.id
411 }
412 pub fn complete(mut self) {
413 finish(&self.core, self.id, self.use_id);
414 self.pending = false;
415 }
416}
417impl<R: Send + Sync> Deref for MultiplexUse<R> {
418 type Target = R;
419 fn deref(&self) -> &R {
420 &self.resource
421 }
422}
423impl<R: Send + Sync> Drop for MultiplexUse<R> {
424 fn drop(&mut self) {
425 if self.pending {
426 abandon(&self.core, self.id, self.use_id);
427 }
428 }
429}
430
431pub struct MultiplexAbandonedUse<R: Send + Sync> {
434 core: Arc<Core<MultiSlot<R>>>,
435 id: ResourceId,
436 use_id: UseId,
437 resource: Arc<R>,
438 pending: bool,
439}
440impl<R: Send + Sync> MultiplexAbandonedUse<R> {
441 pub fn id(&self) -> UseId {
442 self.use_id
443 }
444 pub fn resource_id(&self) -> ResourceId {
445 self.id
446 }
447 pub fn complete(mut self) {
448 finish(&self.core, self.id, self.use_id);
449 self.pending = false;
450 }
451}
452impl<R: Send + Sync> Deref for MultiplexAbandonedUse<R> {
453 type Target = R;
454 fn deref(&self) -> &R {
455 &self.resource
456 }
457}
458impl<R: Send + Sync> Drop for MultiplexAbandonedUse<R> {
459 fn drop(&mut self) {
460 if self.pending {
461 abandon(&self.core, self.id, self.use_id);
462 }
463 }
464}