@@ -21,7 +21,7 @@ use axum::{
2121 routing:: get,
2222} ;
2323use bytes:: Bytes ;
24- use futures_util:: stream;
24+ use futures_util:: { StreamExt , TryStreamExt , stream} ;
2525use serde:: Deserialize ;
2626use sqlx:: { PgPool , Postgres , Transaction } ;
2727use tokio:: { fs, io:: AsyncReadExt , net:: TcpListener , process:: Command , task:: JoinHandle , time} ;
@@ -36,6 +36,7 @@ const HLS_X264_PRESET: &str = "superfast";
3636const HLS_AUDIO_BITRATE : & str = "96k" ;
3737const OPENER_MAX_DIMENSION : i32 = 640 ;
3838const OPENER_VIDEO_CRF : & str = "27" ;
39+ const PRIVATE_ALIAS_RENAME_CONCURRENCY : usize = 16 ;
3940const HLS_TARGET_SEGMENT_SECONDS : u32 = 1 ;
4041const HLS_FFMPEG_INIT_FILENAME : & str = "init.mp4" ;
4142const HLS_DEFAULT_KEYFRAME_INTERVAL_FRAMES : u32 = 30 ;
@@ -1893,26 +1894,40 @@ async fn promote_private_playback_aliases(
18931894 return Ok ( ( ) ) ;
18941895 }
18951896
1896- let mut ordered = artifacts. to_vec ( ) ;
1897- ordered. sort_by_key ( |artifact| publication_order ( & artifact. object_key ) ) ;
1898- for artifact in ordered {
1899- let source_key = uploaded_artifact_object_key ( request, & artifact. object_key ) ;
1900- let destination_key = durable_artifact_storage_key ( request, & artifact. object_key ) ;
1901- if source_key == destination_key {
1902- continue ;
1903- }
1904- tigris_metadata_rename (
1905- & request. s3 ,
1906- & request. s3_bucket ,
1907- & source_key,
1908- & destination_key,
1909- )
1910- . await
1911- . with_context ( || {
1912- format ! (
1913- "failed to metadata-rename private playback artifact {source_key} to {destination_key}"
1914- )
1915- } ) ?;
1897+ // A typical 1080p asset has hundreds of segments. Renaming those aliases
1898+ // serially kept hls_ready hidden for tens of seconds after FFmpeg had
1899+ // finished. Preserve the publication fence and manifest-last ordering,
1900+ // while allowing independent objects in each tier to move concurrently.
1901+ for order in 0 ..=2 {
1902+ let renames = artifacts
1903+ . iter ( )
1904+ . copied ( )
1905+ . filter ( |artifact| publication_order ( & artifact. object_key ) == order)
1906+ . filter_map ( |artifact| {
1907+ let source_key = uploaded_artifact_object_key ( request, & artifact. object_key ) ;
1908+ let destination_key = durable_artifact_storage_key ( request, & artifact. object_key ) ;
1909+ ( source_key != destination_key) . then_some ( ( source_key, destination_key) )
1910+ } )
1911+ . collect :: < Vec < _ > > ( ) ;
1912+ let s3 = request. s3 . clone ( ) ;
1913+ let bucket = request. s3_bucket . clone ( ) ;
1914+ stream:: iter ( renames)
1915+ . map ( |( source_key, destination_key) | {
1916+ let s3 = s3. clone ( ) ;
1917+ let bucket = bucket. clone ( ) ;
1918+ async move {
1919+ tigris_metadata_rename ( & s3, & bucket, & source_key, & destination_key)
1920+ . await
1921+ . with_context ( || {
1922+ format ! (
1923+ "failed to metadata-rename private playback artifact {source_key} to {destination_key}"
1924+ )
1925+ } )
1926+ }
1927+ } )
1928+ . buffer_unordered ( PRIVATE_ALIAS_RENAME_CONCURRENCY )
1929+ . try_collect :: < Vec < _ > > ( )
1930+ . await ?;
19161931 }
19171932 Ok ( ( ) )
19181933}
0 commit comments