@@ -2,7 +2,7 @@ use crate::config::Config;
2
2
use crate :: crates:: Crate ;
3
3
use crate :: experiments:: Experiment ;
4
4
use crate :: prelude:: * ;
5
- use crate :: report:: { compare, ReportWriter } ;
5
+ use crate :: report:: { compare, Comparison , ReportWriter } ;
6
6
use crate :: results:: { EncodedLog , EncodingType , ReadResults } ;
7
7
use flate2:: { write:: GzEncoder , Compression } ;
8
8
use indexmap:: IndexMap ;
@@ -14,77 +14,151 @@ pub struct Archive {
14
14
path : String ,
15
15
}
16
16
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 > (
18
96
db : & DB ,
19
97
ex : & Experiment ,
20
98
crates : & [ Crate ] ,
21
99
dest : & W ,
22
100
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 [ ..] ) ?;
31
108
}
32
109
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
+ ) ;
47
128
continue ;
48
129
}
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
+ }
73
131
}
74
132
}
75
133
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 {
85
135
name : "All the crates" . to_string ( ) ,
86
136
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
+ }
88
162
89
163
for ( comparison, archive) in by_comparison. drain ( ..) {
90
164
let data = archive. into_inner ( ) ?. finish ( ) ?;
0 commit comments