@@ -133,7 +133,7 @@ pub fn print_unknown_user_agents(path: &str, opts: &Options) {
133
133
} ) ;
134
134
}
135
135
136
- pub fn count_line ( times : & mut TimeMap , line : String ) {
136
+ pub fn count_line ( times : & mut TimeMap , line : & str ) {
137
137
let r: request:: Request = serde_json:: from_str ( & line) . unwrap ( ) ;
138
138
139
139
if duplicate_request ( & r) {
@@ -158,11 +158,25 @@ pub fn count_line(times: &mut TimeMap, line: String) {
158
158
}
159
159
}
160
160
161
- pub fn stream_stats ( stream : Box < dyn BufRead > , opts : & Options ) -> TimeMap {
161
+ pub fn stream_stats < ' a > ( mut stream : Box < dyn BufRead + ' a > , opts : & Options ) -> TimeMap {
162
162
let mut times = TimeMap :: default ( ) ;
163
163
let mut lineno = 0 ;
164
164
165
- stream. lines ( ) . for_each ( |line| {
165
+ let mut line = String :: with_capacity ( 1024 * 1024 ) ;
166
+
167
+ loop {
168
+ line. clear ( ) ;
169
+ match stream. read_line ( & mut line) {
170
+ Ok ( 0 ) => break ,
171
+ Ok ( _) => { }
172
+ Err ( e) => {
173
+ if opts. verbose {
174
+ eprintln ! ( "Failed to read line:\n {}" , e) ;
175
+ }
176
+ continue ;
177
+ }
178
+ }
179
+
166
180
if opts. verbose {
167
181
lineno += 1 ;
168
182
if lineno % 100_000 == 0 {
@@ -171,17 +185,8 @@ pub fn stream_stats(stream: Box<dyn BufRead>, opts: &Options) -> TimeMap {
171
185
}
172
186
}
173
187
174
- match line {
175
- Ok ( l) => {
176
- count_line ( & mut times, l) ;
177
- }
178
- Err ( e) => {
179
- if opts. verbose {
180
- eprintln ! ( "Failed to read line:\n {}" , e) ;
181
- }
182
- }
183
- }
184
- } ) ;
188
+ count_line ( & mut times, line. as_str ( ) ) ;
189
+ }
185
190
186
191
if opts. verbose {
187
192
println ! ( ) ;
@@ -195,3 +200,45 @@ pub fn file_stats(path: &str, opts: &Options) -> TimeMap {
195
200
let file_stream = file:: reader ( path, opts) ;
196
201
stream_stats ( file_stream, opts)
197
202
}
203
+
204
+
205
+ #[ cfg( test) ]
206
+ mod tests {
207
+ extern crate test;
208
+
209
+ use super :: * ;
210
+ use std:: fs:: File ;
211
+ use std:: io:: BufReader ;
212
+ use test:: Bencher ;
213
+
214
+ #[ test]
215
+ fn test_stream_stats ( ) {
216
+ let file = File :: open ( "test/sample_500.log" ) . unwrap ( ) ;
217
+ let reader = BufReader :: new ( file) ;
218
+ let opts = Options {
219
+ verbose : false ,
220
+ unknown : false ,
221
+ paths : vec ! [ ] ,
222
+ } ;
223
+ let times = stream_stats ( Box :: new ( reader) , & opts) ;
224
+ assert_eq ! ( times. len( ) , 45 ) ;
225
+ }
226
+
227
+ #[ bench]
228
+ fn bench_stream_stats_sample_500 ( b : & mut Bencher ) {
229
+ let mut logs = Vec :: new ( ) ;
230
+ File :: open ( "test/sample_500.log" )
231
+ . unwrap ( )
232
+ . read_to_end ( & mut logs)
233
+ . unwrap ( ) ;
234
+ let opts = Options {
235
+ verbose : false ,
236
+ unknown : false ,
237
+ paths : vec ! [ ] ,
238
+ } ;
239
+ b. iter ( || {
240
+ let reader = Box :: new ( BufReader :: new ( logs. as_slice ( ) ) ) ;
241
+ stream_stats ( reader, & opts) ;
242
+ } ) ;
243
+ }
244
+ }
0 commit comments