@@ -21,6 +21,7 @@ use crate::file::footer::{decode_footer, decode_metadata};
21
21
use crate :: file:: metadata:: ParquetMetaData ;
22
22
use crate :: file:: page_index:: index:: Index ;
23
23
use crate :: file:: page_index:: index_reader:: { acc_range, decode_column_index, decode_offset_index} ;
24
+ use crate :: file:: FOOTER_SIZE ;
24
25
use bytes:: Bytes ;
25
26
use futures:: future:: BoxFuture ;
26
27
use futures:: FutureExt ;
@@ -53,7 +54,7 @@ impl<F: MetadataFetch> MetadataLoader<F> {
53
54
///
54
55
/// See [`fetch_parquet_metadata`] for the meaning of the individual parameters
55
56
pub async fn load ( mut fetch : F , file_size : usize , prefetch : Option < usize > ) -> Result < Self > {
56
- if file_size < 8 {
57
+ if file_size < FOOTER_SIZE {
57
58
return Err ( ParquetError :: EOF ( format ! (
58
59
"file size of {file_size} is less than footer"
59
60
) ) ) ;
@@ -62,20 +63,22 @@ impl<F: MetadataFetch> MetadataLoader<F> {
62
63
// If a size hint is provided, read more than the minimum size
63
64
// to try and avoid a second fetch.
64
65
let footer_start = if let Some ( size_hint) = prefetch {
66
+ // check for hint smaller than footer
67
+ let size_hint = std:: cmp:: max ( size_hint, FOOTER_SIZE ) ;
65
68
file_size. saturating_sub ( size_hint)
66
69
} else {
67
- file_size - 8
70
+ file_size - FOOTER_SIZE
68
71
} ;
69
72
70
73
let suffix = fetch. fetch ( footer_start..file_size) . await ?;
71
74
let suffix_len = suffix. len ( ) ;
72
75
73
- let mut footer = [ 0 ; 8 ] ;
74
- footer. copy_from_slice ( & suffix[ suffix_len - 8 ..suffix_len] ) ;
76
+ let mut footer = [ 0 ; FOOTER_SIZE ] ;
77
+ footer. copy_from_slice ( & suffix[ suffix_len - FOOTER_SIZE ..suffix_len] ) ;
75
78
76
79
let length = decode_footer ( & footer) ?;
77
80
78
- if file_size < length + 8 {
81
+ if file_size < length + FOOTER_SIZE {
79
82
return Err ( ParquetError :: EOF ( format ! (
80
83
"file size of {} is less than footer + metadata {}" ,
81
84
file_size,
@@ -84,14 +87,14 @@ impl<F: MetadataFetch> MetadataLoader<F> {
84
87
}
85
88
86
89
// Did not fetch the entire file metadata in the initial read, need to make a second request
87
- let ( metadata, remainder) = if length > suffix_len - 8 {
88
- let metadata_start = file_size - length - 8 ;
89
- let meta = fetch. fetch ( metadata_start..file_size - 8 ) . await ?;
90
+ let ( metadata, remainder) = if length > suffix_len - FOOTER_SIZE {
91
+ let metadata_start = file_size - length - FOOTER_SIZE ;
92
+ let meta = fetch. fetch ( metadata_start..file_size - FOOTER_SIZE ) . await ?;
90
93
( decode_metadata ( & meta) ?, None )
91
94
} else {
92
- let metadata_start = file_size - length - 8 - footer_start;
95
+ let metadata_start = file_size - length - FOOTER_SIZE - footer_start;
93
96
94
- let slice = & suffix[ metadata_start..suffix_len - 8 ] ;
97
+ let slice = & suffix[ metadata_start..suffix_len - FOOTER_SIZE ] ;
95
98
(
96
99
decode_metadata ( slice) ?,
97
100
Some ( ( footer_start, suffix. slice ( ..metadata_start) ) ) ,
@@ -273,6 +276,14 @@ mod tests {
273
276
assert_eq ! ( actual. file_metadata( ) . schema( ) , expected) ;
274
277
assert_eq ! ( fetch_count. load( Ordering :: SeqCst ) , 2 ) ;
275
278
279
+ // Metadata hint too small - below footer size
280
+ fetch_count. store ( 0 , Ordering :: SeqCst ) ;
281
+ let actual = fetch_parquet_metadata ( & mut fetch, len, Some ( 7 ) )
282
+ . await
283
+ . unwrap ( ) ;
284
+ assert_eq ! ( actual. file_metadata( ) . schema( ) , expected) ;
285
+ assert_eq ! ( fetch_count. load( Ordering :: SeqCst ) , 2 ) ;
286
+
276
287
// Metadata hint too small
277
288
fetch_count. store ( 0 , Ordering :: SeqCst ) ;
278
289
let actual = fetch_parquet_metadata ( & mut fetch, len, Some ( 10 ) )
0 commit comments