@@ -2,7 +2,7 @@ use crate::config::Config;
22use crate :: crates:: Crate ;
33use crate :: experiments:: Experiment ;
44use crate :: prelude:: * ;
5- use crate :: report:: { compare, ReportWriter } ;
5+ use crate :: report:: { compare, Comparison , ReportWriter } ;
66use crate :: results:: { EncodedLog , EncodingType , ReadResults } ;
77use flate2:: { write:: GzEncoder , Compression } ;
88use indexmap:: IndexMap ;
@@ -14,77 +14,151 @@ pub struct Archive {
1414 path : String ,
1515}
1616
17- pub fn write_logs_archives < DB : ReadResults , W : ReportWriter > (
17+ struct LogEntry {
18+ path : String ,
19+ comparison : Comparison ,
20+ log_bytes : Vec < u8 > ,
21+ }
22+
23+ impl LogEntry {
24+ fn header ( & self ) -> TarHeader {
25+ let mut header = TarHeader :: new_gnu ( ) ;
26+ header. set_size ( self . log_bytes . len ( ) as u64 ) ;
27+ header. set_mode ( 0o644 ) ;
28+ header. set_cksum ( ) ;
29+ header
30+ }
31+ }
32+
33+ fn iterate < ' a , DB : ReadResults + ' a > (
34+ db : & ' a DB ,
35+ ex : & ' a Experiment ,
36+ crates : & ' a [ Crate ] ,
37+ config : & ' a Config ,
38+ ) -> impl Iterator < Item = Fallible < LogEntry > > + ' a {
39+ let mut iter = crates
40+ . iter ( )
41+ . filter ( move |krate| !config. should_skip ( krate) )
42+ . map ( move |krate| -> Fallible < Vec < LogEntry > > {
43+ let res1 = db. load_test_result ( ex, & ex. toolchains [ 0 ] , krate) ?;
44+ let res2 = db. load_test_result ( ex, & ex. toolchains [ 1 ] , krate) ?;
45+ let comparison = compare ( config, krate, res1. as_ref ( ) , res2. as_ref ( ) ) ;
46+
47+ ex. toolchains
48+ . iter ( )
49+ . filter_map ( move |tc| {
50+ let log = db
51+ . load_log ( ex, tc, krate)
52+ . and_then ( |c| c. ok_or_else ( || err_msg ( "missing logs" ) ) )
53+ . with_context ( |_| format ! ( "failed to read log of {} on {}" , krate, tc) ) ;
54+
55+ let log_bytes: EncodedLog = match log {
56+ Ok ( l) => l,
57+ Err ( e) => {
58+ crate :: utils:: report_failure ( & e) ;
59+ return None ;
60+ }
61+ } ;
62+
63+ let log_bytes = match log_bytes. to_plain ( ) {
64+ Ok ( it) => it,
65+ Err ( err) => return Some ( Err ( err) ) ,
66+ } ;
67+
68+ let path = format ! (
69+ "{}/{}/{}.txt" ,
70+ comparison,
71+ krate. id( ) ,
72+ tc. to_path_component( ) ,
73+ ) ;
74+ Some ( Ok ( LogEntry {
75+ path,
76+ comparison,
77+ log_bytes,
78+ } ) )
79+ } )
80+ . collect ( )
81+ } ) ;
82+
83+ let mut in_progress = vec ! [ ] . into_iter ( ) ;
84+ std:: iter:: from_fn ( move || loop {
85+ if let Some ( next) = in_progress. next ( ) {
86+ return Some ( Ok ( next) ) ;
87+ }
88+ match iter. next ( ) ? {
89+ Ok ( list) => in_progress = list. into_iter ( ) ,
90+ Err ( err) => return Some ( Err ( err) ) ,
91+ }
92+ } )
93+ }
94+
95+ fn write_all_archive < DB : ReadResults , W : ReportWriter > (
1896 db : & DB ,
1997 ex : & Experiment ,
2098 crates : & [ Crate ] ,
2199 dest : & W ,
22100 config : & Config ,
23- ) -> Fallible < Vec < Archive > > {
24- let mut archives = Vec :: new ( ) ;
25- let mut all = TarBuilder :: new ( GzEncoder :: new ( Vec :: new ( ) , Compression :: default ( ) ) ) ;
26- let mut by_comparison = IndexMap :: new ( ) ;
27-
28- for krate in crates {
29- if config. should_skip ( krate) {
30- continue ;
101+ ) -> Fallible < Archive > {
102+ for i in 1 ..=RETRIES {
103+ let mut all = TarBuilder :: new ( GzEncoder :: new ( Vec :: new ( ) , Compression :: default ( ) ) ) ;
104+ for entry in iterate ( db, ex, crates, config) {
105+ let entry = entry?;
106+ let mut header = entry. header ( ) ;
107+ all. append_data ( & mut header, & entry. path , & entry. log_bytes [ ..] ) ?;
31108 }
32109
33- let res1 = db. load_test_result ( ex, & ex. toolchains [ 0 ] , krate) ?;
34- let res2 = db. load_test_result ( ex, & ex. toolchains [ 1 ] , krate) ?;
35- let comparison = compare ( config, krate, res1. as_ref ( ) , res2. as_ref ( ) ) ;
36-
37- for tc in & ex. toolchains {
38- let log = db
39- . load_log ( ex, tc, krate)
40- . and_then ( |c| c. ok_or_else ( || err_msg ( "missing logs" ) ) )
41- . with_context ( |_| format ! ( "failed to read log of {} on {}" , krate, tc) ) ;
42-
43- let log_bytes: EncodedLog = match log {
44- Ok ( l) => l,
45- Err ( e) => {
46- crate :: utils:: report_failure ( & e) ;
110+ let data = all. into_inner ( ) ?. finish ( ) ?;
111+ let len = data. len ( ) ;
112+ match dest. write_bytes_once (
113+ "logs-archives/all.tar.gz" ,
114+ data,
115+ & "application/gzip" . parse ( ) . unwrap ( ) ,
116+ EncodingType :: Plain ,
117+ ) {
118+ Ok ( ( ) ) => break ,
119+ Err ( e) => {
120+ if i == RETRIES {
121+ return Err ( e) ;
122+ } else {
123+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 2 ) ) ;
124+ warn ! (
125+ "retry ({}/{}) writing logs-archives/all.tar.gz ({} bytes)" ,
126+ i, RETRIES , len,
127+ ) ;
47128 continue ;
48129 }
49- } ;
50-
51- let log_bytes = log_bytes. to_plain ( ) ?;
52- let log_bytes = log_bytes. as_slice ( ) ;
53-
54- let path = format ! (
55- "{}/{}/{}.txt" ,
56- comparison,
57- krate. id( ) ,
58- tc. to_path_component( ) ,
59- ) ;
60-
61- let mut header = TarHeader :: new_gnu ( ) ;
62- header. set_size ( log_bytes. len ( ) as u64 ) ;
63- header. set_mode ( 0o644 ) ;
64- header. set_cksum ( ) ;
65-
66- all. append_data ( & mut header, & path, log_bytes) ?;
67- by_comparison
68- . entry ( comparison)
69- . or_insert_with ( || {
70- TarBuilder :: new ( GzEncoder :: new ( Vec :: new ( ) , Compression :: default ( ) ) )
71- } )
72- . append_data ( & mut header, & path, log_bytes) ?;
130+ }
73131 }
74132 }
75133
76- let data = all. into_inner ( ) ?. finish ( ) ?;
77- dest. write_bytes (
78- "logs-archives/all.tar.gz" ,
79- data,
80- & "application/gzip" . parse ( ) . unwrap ( ) ,
81- EncodingType :: Plain ,
82- ) ?;
83-
84- archives. push ( Archive {
134+ Ok ( Archive {
85135 name : "All the crates" . to_string ( ) ,
86136 path : "logs-archives/all.tar.gz" . to_string ( ) ,
87- } ) ;
137+ } )
138+ }
139+
140+ const RETRIES : usize = 4 ;
141+
142+ pub fn write_logs_archives < DB : ReadResults , W : ReportWriter > (
143+ db : & DB ,
144+ ex : & Experiment ,
145+ crates : & [ Crate ] ,
146+ dest : & W ,
147+ config : & Config ,
148+ ) -> Fallible < Vec < Archive > > {
149+ let mut archives = Vec :: new ( ) ;
150+ let mut by_comparison = IndexMap :: new ( ) ;
151+
152+ archives. push ( write_all_archive ( db, ex, crates, dest, config) ?) ;
153+
154+ for entry in iterate ( db, ex, crates, config) {
155+ let entry = entry?;
156+
157+ by_comparison
158+ . entry ( entry. comparison )
159+ . or_insert_with ( || TarBuilder :: new ( GzEncoder :: new ( Vec :: new ( ) , Compression :: default ( ) ) ) )
160+ . append_data ( & mut entry. header ( ) , & entry. path , & entry. log_bytes [ ..] ) ?;
161+ }
88162
89163 for ( comparison, archive) in by_comparison. drain ( ..) {
90164 let data = archive. into_inner ( ) ?. finish ( ) ?;
0 commit comments