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