1515) ]
1616
1717use std:: {
18+ cell:: RefCell ,
19+ collections:: { HashMap , VecDeque } ,
1820 io,
1921 num:: NonZero ,
22+ rc:: Rc ,
2023 task:: { Poll , Waker } ,
2124 time:: Duration ,
2225} ;
@@ -101,7 +104,10 @@ impl<K, R> PushEntry<K, R> {
101104pub struct Proactor {
102105 driver : Driver ,
103106 buffer_pool : BufferPoolState ,
104- extra_pools : Vec < BufferPoolRoot > ,
107+ extra_pools : HashMap < u16 , BufferPoolRoot > ,
108+ pending_extra_pool_releases : Rc < RefCell < VecDeque < u16 > > > ,
109+ free_extra_bgids : VecDeque < u16 > ,
110+ next_extra_bgid : u16 ,
105111}
106112
107113enum BufferPoolState {
@@ -115,6 +121,8 @@ enum BufferPoolState {
115121}
116122
117123impl BufferPoolState {
124+ const DEFAULT_BUFFER_GROUP : u16 = 1 ;
125+
118126 fn get ( & mut self , driver : & mut Driver ) -> io:: Result < BufferPool > {
119127 loop {
120128 match self {
@@ -130,6 +138,8 @@ impl BufferPoolState {
130138 * num_of_bufs,
131139 * buffer_len,
132140 * flags,
141+ Self :: DEFAULT_BUFFER_GROUP ,
142+ None ,
133143 ) ?) ;
134144 }
135145 BufferPoolState :: Init ( root) => return Ok ( root. get_pool ( ) ) ,
@@ -143,7 +153,7 @@ impl Drop for Proactor {
143153 if let BufferPoolState :: Init ( buffer_pool) = & mut self . buffer_pool {
144154 _ = unsafe { buffer_pool. release ( & mut self . driver ) } ;
145155 }
146- for pool in & mut self . extra_pools {
156+ for ( _ , mut pool) in self . extra_pools . drain ( ) {
147157 _ = unsafe { pool. release ( & mut self . driver ) } ;
148158 }
149159 }
@@ -172,10 +182,45 @@ impl Proactor {
172182 buffer_len : builder. buffer_pool_buffer_len ,
173183 flags : builder. buffer_pool_flag ,
174184 } ,
175- extra_pools : Vec :: new ( ) ,
185+ extra_pools : HashMap :: new ( ) ,
186+ pending_extra_pool_releases : Rc :: default ( ) ,
187+ free_extra_bgids : VecDeque :: new ( ) ,
188+ next_extra_bgid : BufferPoolState :: DEFAULT_BUFFER_GROUP + 1 ,
176189 } )
177190 }
178191
192+ fn alloc_extra_bgid ( & mut self ) -> io:: Result < u16 > {
193+ if let Some ( buffer_group) = self . free_extra_bgids . pop_front ( ) {
194+ return Ok ( buffer_group) ;
195+ }
196+
197+ let buffer_group = self . next_extra_bgid ;
198+ self . next_extra_bgid = buffer_group
199+ . checked_add ( 1 )
200+ . ok_or_else ( || io:: Error :: other ( "no buffer group id available" ) ) ?;
201+
202+ Ok ( buffer_group)
203+ }
204+
205+ fn release_extra_bgid ( & mut self , buffer_group : u16 ) {
206+ self . free_extra_bgids . push_back ( buffer_group) ;
207+ }
208+
209+ fn release_unused_extra_pools ( & mut self ) -> io:: Result < ( ) > {
210+ while let Some ( buffer_group) = { self . pending_extra_pool_releases . borrow_mut ( ) . pop_front ( ) }
211+ {
212+ let Some ( mut root) = self . extra_pools . remove ( & buffer_group) else {
213+ continue ;
214+ } ;
215+
216+ unsafe { root. release ( & mut self . driver ) ? } ;
217+
218+ self . release_extra_bgid ( buffer_group)
219+ }
220+
221+ Ok ( ( ) )
222+ }
223+
179224 /// Get a default [`Extra`] for underlying driver.
180225 pub fn default_extra ( & self ) -> Extra {
181226 Extra :: new ( & self . driver )
@@ -295,6 +340,7 @@ impl Proactor {
295340 /// You need to call [`Proactor::pop`] to get the pushed
296341 /// operations.
297342 pub fn poll ( & mut self , timeout : Option < Duration > ) -> io:: Result < ( ) > {
343+ self . release_unused_extra_pools ( ) ?;
298344 self . driver . poll ( timeout)
299345 }
300346
@@ -477,11 +523,29 @@ impl Proactor {
477523 buffer_size : usize ,
478524 flags : u16 ,
479525 ) -> io:: Result < BufferPool > {
526+ self . release_unused_extra_pools ( ) ?;
480527 let alloc = BufferAlloc :: new :: < A > ( ) ;
481- let root =
482- BufferPoolRoot :: new ( & mut self . driver , alloc, num_of_bufs, buffer_size, flags) ?;
528+ let buffer_group = self . alloc_extra_bgid ( ) ?;
529+ let release_queue = Rc :: downgrade ( & self . pending_extra_pool_releases ) ;
530+ let root = match BufferPoolRoot :: new (
531+ & mut self . driver ,
532+ alloc,
533+ num_of_bufs,
534+ buffer_size,
535+ flags,
536+ buffer_group,
537+ Some ( release_queue) ,
538+ ) {
539+ Ok ( root) => root,
540+ Err ( err) => {
541+ self . release_extra_bgid ( buffer_group) ;
542+ return Err ( err) ;
543+ }
544+ } ;
545+
483546 let pool = root. get_pool ( ) ;
484- self . extra_pools . push ( root) ;
547+ self . extra_pools . insert ( buffer_group, root) ;
548+
485549 Ok ( pool)
486550 }
487551}
0 commit comments