1- use std:: env;
21use std:: fmt:: Write ;
32use std:: net:: SocketAddr ;
43use std:: path:: PathBuf ;
54use std:: str:: FromStr ;
65use std:: sync:: Arc ;
6+ use std:: { env, fs} ;
77
88use anyhow:: { anyhow, Context as _, Error , Result } ;
99use axum:: async_trait;
1010use clap:: { Parser , Subcommand , ValueEnum } ;
1111use docs_rs:: cdn:: CdnBackend ;
1212use docs_rs:: db:: { self , add_path_into_database, Overrides , Pool , PoolClient } ;
1313use docs_rs:: repositories:: RepositoryStatsUpdater ;
14+ use docs_rs:: storage:: { rustdoc_archive_path, source_archive_path, PathNotFoundError } ;
1415use docs_rs:: utils:: {
1516 get_config, get_crate_pattern_and_priority, list_crate_priorities, queue_builder,
16- remove_crate_priority, set_config, set_crate_priority, ConfigName ,
17+ remove_crate_priority, set_config, set_crate_priority, spawn_blocking , ConfigName ,
1718} ;
1819use docs_rs:: {
1920 start_background_metrics_webserver, start_web_server, AsyncStorage , BuildQueue , Config ,
@@ -23,6 +24,7 @@ use docs_rs::{
2324use futures_util:: StreamExt ;
2425use humantime:: Duration ;
2526use once_cell:: sync:: OnceCell ;
27+ use rusqlite:: { Connection , OpenFlags } ;
2628use sentry:: TransactionContext ;
2729use tokio:: runtime:: { Builder , Runtime } ;
2830use tracing_log:: LogTracer ;
@@ -509,6 +511,9 @@ enum DatabaseSubcommand {
509511 /// temporary commant to update the `crates.latest_version_id` field
510512 UpdateLatestVersionId ,
511513
514+ /// temporary command to rebuild a subset of the archive indexes
515+ FixBrokenArchiveIndexes ,
516+
512517 /// Updates Github/Gitlab stats for crates.
513518 UpdateRepositoryFields ,
514519
@@ -567,6 +572,80 @@ impl DatabaseSubcommand {
567572 . context ( "Failed to run database migrations" ) ?
568573 }
569574
575+ Self :: FixBrokenArchiveIndexes => {
576+ let pool = ctx. pool ( ) ?;
577+ let build_queue = ctx. build_queue ( ) ?;
578+ ctx. runtime ( ) ?
579+ . block_on ( async {
580+ let storage = ctx. async_storage ( ) . await ?;
581+ let mut conn = pool. get_async ( ) . await ?;
582+ let mut result_stream = sqlx:: query!(
583+ "
584+ SELECT c.name, r.version, r.release_time
585+ FROM crates c, releases r
586+ WHERE c.id = r.crate_id
587+ ORDER BY r.id
588+ "
589+ )
590+ . fetch ( & mut * conn) ;
591+
592+ while let Some ( row) = result_stream. next ( ) . await {
593+ let row = row?;
594+
595+ println ! (
596+ "checking index for {} {} ({:?})" ,
597+ row. name, row. version, row. release_time
598+ ) ;
599+
600+ for path in & [
601+ rustdoc_archive_path ( & row. name , & row. version ) ,
602+ source_archive_path ( & row. name , & row. version ) ,
603+ ] {
604+ let local_archive_index_filename = match storage
605+ . download_archive_index ( path, 42 )
606+ . await
607+ {
608+ Ok ( path) => path,
609+ Err ( err)
610+ if err. downcast_ref :: < PathNotFoundError > ( ) . is_some ( ) =>
611+ {
612+ continue
613+ }
614+ Err ( err) => return Err ( err) ,
615+ } ;
616+
617+ let count = {
618+ let connection = Connection :: open_with_flags (
619+ & local_archive_index_filename,
620+ OpenFlags :: SQLITE_OPEN_READ_ONLY
621+ | OpenFlags :: SQLITE_OPEN_NO_MUTEX ,
622+ ) ?;
623+ let mut stmt =
624+ connection. prepare ( "SELECT count(*) FROM files" ) ?;
625+
626+ stmt. query_row ( [ ] , |row| Ok ( row. get :: < _ , usize > ( 0 ) ) ) ??
627+ } ;
628+
629+ fs:: remove_file ( & local_archive_index_filename) ?;
630+
631+ if count >= 65000 {
632+ println ! ( "...big index, queueing rebuild" ) ;
633+ spawn_blocking ( {
634+ let build_queue = build_queue. clone ( ) ;
635+ let name = row. name . clone ( ) ;
636+ let version = row. version . clone ( ) ;
637+ move || build_queue. add_crate ( & name, & version, 5 , None )
638+ } )
639+ . await ?;
640+ }
641+ }
642+ }
643+
644+ Ok :: < ( ) , anyhow:: Error > ( ( ) )
645+ } )
646+ . context ( "Failed to queue rebuilds for big documentation sizes" ) ?
647+ }
648+
570649 Self :: UpdateLatestVersionId => {
571650 let pool = ctx. pool ( ) ?;
572651 ctx. runtime ( ) ?
@@ -581,7 +660,7 @@ impl DatabaseSubcommand {
581660 while let Some ( row) = result_stream. next ( ) . await {
582661 let row = row?;
583662
584- println ! ( "handling crate {}" , row. name) ;
663+ println ! ( "handling crate {} " , row. name) ;
585664
586665 db:: update_latest_version_id ( & mut update_conn, row. id ) . await ?;
587666 }
0 commit comments