@@ -20,14 +20,18 @@ use super::retry::{RetryableError, build_dns_cached_client, create_retry_strateg
2020static DOWNLOADER_CLIENT : Lazy < Client > = Lazy :: new ( build_dns_cached_client) ;
2121
2222// OnceMap to ensure each (url, dest) pair is only downloaded once
23- static DOWNLOAD_ONCE : Lazy < OnceMap < String , ( ) > > = Lazy :: new ( OnceMap :: new) ;
23+ static DOWNLOAD_ONCE : Lazy < OnceMap < ( String , PathBuf ) , ( ) > > = Lazy :: new ( OnceMap :: new) ;
2424
2525// ============ Buffer Pool ============
2626// Reuse decompression buffers to reduce allocation overhead
2727// Similar to Bun's ObjectPool pattern
2828
2929const BUFFER_POOL_MAX_SIZE : usize = 8 ;
3030const BUFFER_POOL_MIN_CAPACITY : usize = 2 * 1024 * 1024 ; // 2MB minimum
31+ const BUFFER_POOL_MAX_CAPACITY : usize = 64 * 1024 * 1024 ; // 64MB maximum
32+ const MIN_ESTIMATED_SIZE : usize = 16 ;
33+ const MAX_ESTIMATED_SIZE : usize = 512 * 1024 * 1024 ; // 512MB
34+ const DECOMPRESSION_RETRY_FACTOR : usize = 4 ;
3135
3236/// Global buffer pool for decompression
3337static BUFFER_POOL : Lazy < Mutex < Vec < Vec < u8 > > > > =
@@ -60,7 +64,7 @@ fn acquire_buffer(required_capacity: usize) -> Vec<u8> {
6064/// Return a buffer to the pool for reuse
6165fn release_buffer ( mut buf : Vec < u8 > ) {
6266 // Only keep buffers that are reasonably sized
63- if buf. capacity ( ) < BUFFER_POOL_MIN_CAPACITY || buf. capacity ( ) > 64 * 1024 * 1024 {
67+ if buf. capacity ( ) < BUFFER_POOL_MIN_CAPACITY || buf. capacity ( ) > BUFFER_POOL_MAX_CAPACITY {
6468 tracing:: trace!(
6569 "buffer pool: dropped (capacity={}, too small or too large)" ,
6670 buf. capacity( )
@@ -123,10 +127,10 @@ fn sanitize_path_for_windows(base: &Path, relative: &Path) -> PathBuf {
123127
124128/// Download and extract a tarball to the destination directory.
125129///
126- /// Uses OnceMap to ensure each URL is only downloaded once,
130+ /// Uses OnceMap to ensure each (url, dest) pair is only downloaded once,
127131/// even when called concurrently from multiple tasks.
128132pub async fn download ( url : & str , dest : & Path ) -> Result < ( ) > {
129- let key = url. to_string ( ) ;
133+ let key = ( url. to_string ( ) , dest . to_path_buf ( ) ) ;
130134
131135 DOWNLOAD_ONCE
132136 . get_or_init ( key, || async {
@@ -219,7 +223,7 @@ fn estimate_uncompressed_size(gzip_data: &[u8]) -> usize {
219223 let last_4 = & gzip_data[ gzip_data. len ( ) - 4 ..] ;
220224 let size = u32:: from_le_bytes ( [ last_4[ 0 ] , last_4[ 1 ] , last_4[ 2 ] , last_4[ 3 ] ] ) as usize ;
221225 // Sanity check: if size is 0 or too small, use a reasonable estimate
222- if !( 16 ..=512 * 1024 * 1024 ) . contains ( & size) {
226+ if !( MIN_ESTIMATED_SIZE ..=MAX_ESTIMATED_SIZE ) . contains ( & size) {
223227 gzip_data. len ( ) * 10
224228 } else {
225229 size
@@ -264,9 +268,8 @@ async fn extract_tarball(gzip_bytes: Bytes, dest: &Path) -> Result<()> {
264268 gzip_len,
265269 estimated_size
266270 ) ;
267- let new_size = estimated_size * 4 ;
268- output. reserve ( new_size - output. len ( ) ) ;
269- unsafe { output. set_len ( new_size) } ;
271+ let new_size = estimated_size * DECOMPRESSION_RETRY_FACTOR ;
272+ output. resize ( new_size, 0 ) ;
270273 decompressor
271274 . gzip_decompress ( & gzip_bytes, & mut output)
272275 . with_context ( || "gzip decompression failed" ) ?
@@ -330,11 +333,11 @@ async fn extract_tarball(gzip_bytes: Bytes, dest: &Path) -> Result<()> {
330333 // First, create all directories (sequential to avoid race conditions)
331334 let mut created_dirs = HashSet :: new ( ) ;
332335 for entry in entries. iter ( ) {
333- if let Some ( parent) = entry. path . parent ( ) {
334- if ! created_dirs. contains ( parent) {
335- fs :: create_dir_all ( parent ) . ok ( ) ;
336- created_dirs . insert ( parent. to_path_buf ( ) ) ;
337- }
336+ if let Some ( parent) = entry. path . parent ( )
337+ && created_dirs. insert ( parent. to_path_buf ( ) )
338+ {
339+ fs :: create_dir_all ( parent)
340+ . with_context ( || format ! ( "Failed to create directory: {}" , parent . display ( ) ) ) ? ;
338341 }
339342 }
340343
@@ -349,7 +352,9 @@ async fn extract_tarball(gzip_bytes: Bytes, dest: &Path) -> Result<()> {
349352 {
350353 use std:: os:: unix:: fs:: PermissionsExt ;
351354 let perms = fs:: Permissions :: from_mode ( entry. mode ) ;
352- fs:: set_permissions ( & entry. path , perms) . ok ( ) ;
355+ fs:: set_permissions ( & entry. path , perms) . with_context ( || {
356+ format ! ( "Failed to set permissions: {}" , entry. path. display( ) )
357+ } ) ?;
353358 }
354359 Ok ( ( ) )
355360 } )
@@ -453,8 +458,7 @@ mod tests {
453458 let url = url. clone ( ) ;
454459 let dest = dest. clone ( ) ;
455460 handles. push ( task:: spawn ( async move {
456- let bytes = download_bytes ( & url) . await . unwrap ( ) ;
457- extract_and_write ( bytes, & dest) . await . unwrap ( ) ;
461+ download ( & url, & dest) . await . unwrap ( ) ;
458462 } ) ) ;
459463 }
460464 for h in handles {
0 commit comments