@@ -31,6 +31,7 @@ use anyhow::Context as _;
3131use bytes:: { buf:: BufMut , Bytes , BytesMut } ;
3232use filetime:: FileTime ;
3333use fs:: metadata;
34+ use fs:: File ;
3435use fs_err as fs;
3536use futures:: channel:: mpsc;
3637use futures:: future:: FutureExt ;
@@ -42,15 +43,15 @@ use std::collections::{HashMap, HashSet};
4243use std:: env;
4344use std:: ffi:: OsString ;
4445use std:: future:: Future ;
45- use std:: io:: { self , Write } ;
46+ use std:: io:: { self , BufWriter , Write } ;
4647use std:: marker:: Unpin ;
4748#[ cfg( feature = "dist-client" ) ]
4849use std:: mem;
4950#[ cfg( target_os = "android" ) ]
5051use std:: os:: android:: net:: SocketAddrExt ;
5152#[ cfg( target_os = "linux" ) ]
5253use std:: os:: linux:: net:: SocketAddrExt ;
53- use std:: path:: PathBuf ;
54+ use std:: path:: { Path , PathBuf } ;
5455use std:: pin:: Pin ;
5556use std:: process:: { ExitStatus , Output } ;
5657use std:: sync:: Arc ;
@@ -488,8 +489,14 @@ pub fn start_server(config: &Config, addr: &crate::net::SocketAddr) -> Result<()
488489 crate :: net:: SocketAddr :: Net ( addr) => {
489490 trace ! ( "binding TCP {addr}" ) ;
490491 let l = runtime. block_on ( tokio:: net:: TcpListener :: bind ( addr) ) ?;
491- let srv =
492- SccacheServer :: < _ > :: with_listener ( l, runtime, client, dist_client, storage) ;
492+ let srv = SccacheServer :: < _ > :: with_listener (
493+ l,
494+ runtime,
495+ client,
496+ dist_client,
497+ storage,
498+ config. cache_stats_file . clone ( ) ,
499+ ) ;
493500 Ok ( (
494501 srv. local_addr ( ) . unwrap ( ) ,
495502 Box :: new ( move |f| srv. run ( f) ) as Box < dyn FnOnce ( _) -> _ > ,
@@ -504,8 +511,14 @@ pub fn start_server(config: &Config, addr: &crate::net::SocketAddr) -> Result<()
504511 let _guard = runtime. enter ( ) ;
505512 tokio:: net:: UnixListener :: bind ( path) ?
506513 } ;
507- let srv =
508- SccacheServer :: < _ > :: with_listener ( l, runtime, client, dist_client, storage) ;
514+ let srv = SccacheServer :: < _ > :: with_listener (
515+ l,
516+ runtime,
517+ client,
518+ dist_client,
519+ storage,
520+ config. cache_stats_file . clone ( ) ,
521+ ) ;
509522 Ok ( (
510523 srv. local_addr ( ) . unwrap ( ) ,
511524 Box :: new ( move |f| srv. run ( f) ) as Box < dyn FnOnce ( _) -> _ > ,
@@ -579,6 +592,7 @@ impl<C: CommandCreatorSync> SccacheServer<tokio::net::TcpListener, C> {
579592 client : Client ,
580593 dist_client : DistClientContainer ,
581594 storage : Arc < dyn Storage > ,
595+ cache_stats_file : Option < PathBuf > ,
582596 ) -> Result < Self > {
583597 let addr = crate :: net:: SocketAddr :: with_port ( port) ;
584598 let listener = runtime. block_on ( tokio:: net:: TcpListener :: bind ( addr. as_net ( ) . unwrap ( ) ) ) ?;
@@ -589,6 +603,7 @@ impl<C: CommandCreatorSync> SccacheServer<tokio::net::TcpListener, C> {
589603 client,
590604 dist_client,
591605 storage,
606+ cache_stats_file,
592607 ) )
593608 }
594609}
@@ -600,13 +615,22 @@ impl<A: crate::net::Acceptor, C: CommandCreatorSync> SccacheServer<A, C> {
600615 client : Client ,
601616 dist_client : DistClientContainer ,
602617 storage : Arc < dyn Storage > ,
618+ cache_stats_file : Option < PathBuf > ,
603619 ) -> Self {
604620 // Prepare the service which we'll use to service all incoming TCP
605621 // connections.
606622 let ( tx, rx) = mpsc:: channel ( 1 ) ;
607623 let ( wait, info) = WaitUntilZero :: new ( ) ;
608624 let pool = runtime. handle ( ) . clone ( ) ;
609- let service = SccacheService :: new ( dist_client, storage, & client, pool, tx, info) ;
625+ let service = SccacheService :: new (
626+ dist_client,
627+ storage,
628+ & client,
629+ pool,
630+ tx,
631+ info,
632+ cache_stats_file. clone ( ) ,
633+ ) ;
610634
611635 SccacheServer {
612636 runtime,
@@ -818,6 +842,10 @@ where
818842 /// This field causes [WaitUntilZero] to wait until this struct drops.
819843 #[ allow( dead_code) ]
820844 info : ActiveInfo ,
845+
846+ /// A file that will contain JSON-formatted stats output, written after
847+ /// each compile operation.
848+ cache_stats_file : Option < PathBuf > ,
821849}
822850
823851type SccacheRequest = Message < Request , Body < ( ) > > ;
@@ -857,7 +885,11 @@ where
857885 Request :: Compile ( compile) => {
858886 debug ! ( "handle_client: compile" ) ;
859887 me. stats . lock ( ) . await . compile_requests += 1 ;
860- me. handle_compile ( compile) . await
888+ let resp = me. handle_compile ( compile) . await ;
889+ if let Some ( val) = & me. cache_stats_file {
890+ me. stats . lock ( ) . await . clone ( ) . write ( val) ?
891+ }
892+ resp
861893 }
862894 Request :: GetStats => {
863895 debug ! ( "handle_client: get_stats" ) ;
@@ -916,6 +948,7 @@ where
916948 rt : tokio:: runtime:: Handle ,
917949 tx : mpsc:: Sender < ServerMessage > ,
918950 info : ActiveInfo ,
951+ cache_stats_file : Option < PathBuf > ,
919952 ) -> SccacheService < C > {
920953 SccacheService {
921954 stats : Arc :: default ( ) ,
@@ -927,6 +960,7 @@ where
927960 creator : C :: new ( client) ,
928961 tx,
929962 info,
963+ cache_stats_file,
930964 }
931965 }
932966
@@ -938,6 +972,7 @@ where
938972 let ( _, info) = WaitUntilZero :: new ( ) ;
939973 let client = Client :: new_num ( 1 ) ;
940974 let dist_client = DistClientContainer :: new_disabled ( ) ;
975+ let cache_stats_file = None ;
941976 SccacheService {
942977 stats : Arc :: default ( ) ,
943978 dist_client : Arc :: new ( dist_client) ,
@@ -948,6 +983,7 @@ where
948983 creator : C :: new ( & client) ,
949984 tx,
950985 info,
986+ cache_stats_file,
951987 }
952988 }
953989
@@ -960,6 +996,7 @@ where
960996 let ( tx, _) = mpsc:: channel ( 1 ) ;
961997 let ( _, info) = WaitUntilZero :: new ( ) ;
962998 let client = Client :: new_num ( 1 ) ;
999+ let cache_stats_file = None ;
9631000 SccacheService {
9641001 stats : Arc :: default ( ) ,
9651002 dist_client : Arc :: new ( DistClientContainer :: new_with_state ( DistClientState :: Some (
@@ -981,6 +1018,7 @@ where
9811018 creator : C :: new ( & client) ,
9821019 tx,
9831020 info,
1021+ cache_stats_file,
9841022 }
9851023 }
9861024
@@ -1909,6 +1947,19 @@ impl ServerStats {
19091947 ) ;
19101948 }
19111949 }
1950+
1951+ /// Write stats in JSON format to a file.
1952+ fn write ( & self , path : & Path ) -> Result < ( ) > {
1953+ let file = match File :: create ( path) {
1954+ Ok ( f) => f,
1955+ Err ( e) => {
1956+ debug ! ( "Couldn't open stats file for writing: {}" , e) ;
1957+ return Ok ( ( ) ) ;
1958+ }
1959+ } ;
1960+ let mut writer = BufWriter :: new ( file) ;
1961+ Ok ( serde_json:: to_writer ( & mut writer, self ) ?)
1962+ }
19121963}
19131964
19141965fn set_percentage_stat (
0 commit comments