@@ -2,10 +2,10 @@ use std::str::FromStr;
22use lazy_static:: lazy_static;
33use regex:: Regex ;
44use crate :: archiver:: datakind:: DataKind ;
5- use crate :: archiver:: range:: Range ;
5+ use crate :: archiver:: range:: { Height , Range } ;
66
77lazy_static ! {
8- static ref RE_SINGLE : Regex = Regex :: new( r"^(\d+)\.(\w+)\.(\w+\.)?avro$" ) . unwrap( ) ;
8+ static ref RE_SINGLE : Regex = Regex :: new( r"^(\d+)\.(([a-f0-9]{64})\.)?( \w+)\.(\w+\.)?avro$" ) . unwrap( ) ;
99 static ref RE_RANGE : Regex = Regex :: new( r"^range-(\d+)_(\d+)\.(\w+)\.(\w+\.)?avro$" ) . unwrap( ) ;
1010}
1111
@@ -28,67 +28,70 @@ impl Filenames {
2828
2929 pub fn parse ( filename : String ) -> Option < ( DataKind , Range ) > {
3030 if let Some ( cap) = RE_SINGLE . captures ( filename. as_str ( ) ) {
31- let height = cap. get ( 1 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
32- let kind = DataKind :: from_str ( cap. get ( 2 ) . unwrap ( ) . as_str ( ) ) ;
31+ let height: u64 = cap. get ( 1 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
32+ let hash = cap. get ( 3 ) . map ( |x| x. as_str ( ) . to_string ( ) ) ;
33+ let kind = DataKind :: from_str ( cap. get ( 4 ) . unwrap ( ) . as_str ( ) ) ;
3334 if kind. is_err ( ) {
3435 return None ;
3536 }
36- return Some ( ( kind. unwrap ( ) , Range :: Single ( height) ) ) ;
37+ return Some ( ( kind. unwrap ( ) , Range :: Single ( Height :: new ( height, hash ) ) ) ) ;
3738 }
3839 if let Some ( cap) = RE_RANGE . captures ( filename. as_str ( ) ) {
39- let start = cap. get ( 1 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
40- let end = cap. get ( 2 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
40+ let start: u64 = cap. get ( 1 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
41+ let end: u64 = cap. get ( 2 ) . unwrap ( ) . as_str ( ) . parse ( ) . unwrap ( ) ;
4142 let kind = DataKind :: from_str ( cap. get ( 3 ) . unwrap ( ) . as_str ( ) ) ;
4243 if kind. is_err ( ) {
4344 return None ;
4445 }
45- return Some ( ( kind. unwrap ( ) , Range :: Multiple ( start, end) ) ) ;
46+ return Some ( ( kind. unwrap ( ) , Range :: Multiple ( start. into ( ) , end. into ( ) ) ) ) ;
4647 }
4748 None
4849 }
4950
50- pub fn filename ( & self , kind : & DataKind , range : & Range ) -> String {
51+ pub fn filename ( & self , kind : & DataKind , blocks : & Range ) -> String {
5152 let suffix = match kind {
52- DataKind :: Blocks => match range {
53- Range :: Single ( _) => "block" ,
54- Range :: Multiple ( _, _) => "blocks"
55- } ,
53+ DataKind :: Blocks => if blocks. len ( ) == 1 { "block" } else { "blocks" } ,
5654 DataKind :: Transactions => "txes" ,
5755 DataKind :: TransactionTraces => "traces"
5856 } ;
5957
60- match range {
61- Range :: Single ( height) => {
62- format ! ( "{}.{}.avro" , self . range_padded ( * height ) , suffix )
63- } ,
64- Range :: Multiple ( start , end ) => {
65- format ! ( "range-{}_{} .{}.avro" , self . range_padded( * start ) , self . range_padded ( * end ) , suffix)
58+ if blocks . len ( ) == 1 {
59+ let height = blocks . first_height ( ) ;
60+ if let Some ( hash ) = & height . hash {
61+ format ! ( "{}.{}.{}.avro" , self . range_padded ( blocks . start ( ) ) , hash , suffix )
62+ } else {
63+ format ! ( "{} .{}.avro" , self . range_padded( blocks . start ( ) ) , suffix)
6664 }
65+ } else {
66+ format ! ( "range-{}_{}.{}.avro" , self . range_padded( blocks. start( ) ) , self . range_padded( blocks. end( ) ) , suffix)
6767 }
6868 }
6969
70- pub fn relative_path ( & self , kind : & DataKind , range : & Range ) -> String {
71- match range {
72- Range :: Single ( start) => {
73- format ! ( "{}/{}/{}" ,
74- self . level_1( * start) ,
75- self . level_2( * start) ,
76- self . filename( kind, range)
77- )
78- }
79- Range :: Multiple ( start, _end) => {
80- format ! ( "{}/{}" ,
81- self . level_1( * start) ,
82- self . filename( kind, range)
83- )
84- }
70+ pub fn relative_path ( & self , kind : & DataKind , blocks : & Range ) -> String {
71+ if blocks. len ( ) == 1 {
72+ format ! ( "{}/{}/{}" ,
73+ self . level_1( blocks. start( ) ) ,
74+ self . level_2( blocks. start( ) ) ,
75+ self . filename( kind, blocks)
76+ )
77+ } else {
78+ format ! ( "{}/{}" ,
79+ self . level_1( blocks. start( ) ) ,
80+ self . filename( kind, blocks)
81+ )
8582 }
8683 }
8784
85+ ///
86+ /// Offset is a position in a directory list. Since Dshackle Archive uses a S3-like storage, which sorts files by their name,
87+ /// this is where to start to look for files in a given range.
8888 pub fn offset ( & self , range : & Range ) -> String {
8989 match range {
90- Range :: Single ( start) => self . range_padded ( * start) ,
91- Range :: Multiple ( start, _) => format ! ( "range-{}" , self . range_padded( * start) )
90+ // For a single block, it's just the height
91+ Range :: Single ( start) => self . range_padded ( start. height ) ,
92+ // For a range we use a prefix `range-` only to distinguish them from the single files,
93+ // otherwise they would be mixed and single ranges listed twice, etc.
94+ Range :: Multiple ( start, _) => format ! ( "range-{}" , self . range_padded( start. height) )
9295 }
9396 }
9497
@@ -226,56 +229,56 @@ mod tests {
226229 fn single_block_file ( ) {
227230 let filenames = Filenames :: default ( ) ;
228231 let kind = DataKind :: Blocks ;
229- let range = Range :: Single ( 12000000 ) ;
232+ let range = Range :: Single ( 12000000 . into ( ) ) ;
230233 assert_eq ! ( filenames. filename( & kind, & range) , "012000000.block.avro" ) ;
231234 }
232235
233236 #[ test]
234237 fn single_block_txes_file ( ) {
235238 let filenames = Filenames :: default ( ) ;
236239 let kind = DataKind :: Transactions ;
237- let range = Range :: Single ( 12000000 ) ;
240+ let range = Range :: Single ( 12000000 . into ( ) ) ;
238241 assert_eq ! ( filenames. filename( & kind, & range) , "012000000.txes.avro" ) ;
239242 }
240243
241244 #[ test]
242245 fn single_block_tx_traces_file ( ) {
243246 let filenames = Filenames :: default ( ) ;
244247 let kind = DataKind :: TransactionTraces ;
245- let range = Range :: Single ( 12000000 ) ;
248+ let range = Range :: Single ( 12000000 . into ( ) ) ;
246249 assert_eq ! ( filenames. filename( & kind, & range) , "012000000.traces.avro" ) ;
247250 }
248251
249252 #[ test]
250253 fn single_block_path ( ) {
251254 let filenames = Filenames :: default ( ) ;
252255 let kind = DataKind :: Blocks ;
253- assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12000005 ) ) , "012000000/012000000/012000005.block.avro" ) ;
254- assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12004999 ) ) , "012000000/012004000/012004999.block.avro" ) ;
255- assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12005000 ) ) , "012000000/012005000/012005000.block.avro" ) ;
256- assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12005001 ) ) , "012000000/012005000/012005001.block.avro" ) ;
257- assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12345678 ) ) , "012000000/012345000/012345678.block.avro" ) ;
256+ assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12000005 . into ( ) ) ) , "012000000/012000000/012000005.block.avro" ) ;
257+ assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12004999 . into ( ) ) ) , "012000000/012004000/012004999.block.avro" ) ;
258+ assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12005000 . into ( ) ) ) , "012000000/012005000/012005000.block.avro" ) ;
259+ assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12005001 . into ( ) ) ) , "012000000/012005000/012005001.block.avro" ) ;
260+ assert_eq ! ( filenames. path( & kind, & Range :: Single ( 12345678 . into ( ) ) ) , "012000000/012345000/012345678.block.avro" ) ;
258261 }
259262
260263 #[ test]
261264 fn multi_block_path ( ) {
262265 let filenames = Filenames :: default ( ) ;
263266 let kind = DataKind :: Blocks ;
264- assert_eq ! ( filenames. path( & kind, & Range :: Multiple ( 12000000 , 12000999 ) ) , "012000000/range-012000000_012000999.blocks.avro" ) ;
267+ assert_eq ! ( filenames. path( & kind, & Range :: Multiple ( 12000000 . into ( ) , 12000999 . into ( ) ) ) , "012000000/range-012000000_012000999.blocks.avro" ) ;
265268 }
266269
267270 #[ test]
268271 fn multi_tx_path ( ) {
269272 let filenames = Filenames :: default ( ) ;
270273 let kind = DataKind :: Transactions ;
271- assert_eq ! ( filenames. path( & kind, & Range :: Multiple ( 12000000 , 12000999 ) ) , "012000000/range-012000000_012000999.txes.avro" ) ;
274+ assert_eq ! ( filenames. path( & kind, & Range :: Multiple ( 12000000 . into ( ) , 12000999 . into ( ) ) ) , "012000000/range-012000000_012000999.txes.avro" ) ;
272275 }
273276
274277 #[ test]
275278 fn multi_tx_traces_path ( ) {
276279 let filenames = Filenames :: default ( ) ;
277280 let kind = DataKind :: TransactionTraces ;
278- assert_eq ! ( filenames. path( & kind, & Range :: Multiple ( 12000000 , 12000999 ) ) , "012000000/range-012000000_012000999.traces.avro" ) ;
281+ assert_eq ! ( filenames. path( & kind, & Range :: Multiple ( 12000000 . into ( ) , 12000999 . into ( ) ) ) , "012000000/range-012000000_012000999.traces.avro" ) ;
279282 }
280283
281284 #[ test]
@@ -343,20 +346,59 @@ mod tests {
343346 fn parse_single_block_file ( ) {
344347 let ( kind, range) = Filenames :: parse ( "021625120.block.avro" . to_string ( ) ) . unwrap ( ) ;
345348 assert_eq ! ( kind, DataKind :: Blocks ) ;
346- assert_eq ! ( range, Range :: Single ( 21625120 ) ) ;
349+ assert_eq ! ( range, Range :: Single ( 21625120 . into( ) ) ) ;
350+ assert ! ( range. first_height( ) . hash. is_none( ) ) ;
351+ }
352+
353+ #[ test]
354+ fn parse_single_block_file_with_hash ( ) {
355+ let ( kind, range) = Filenames :: parse ( "021625120.b4e72a78fd2cb0e75768401a92e5258618eec892b7e4edb49b2a592e9a5de5c4.block.avro" . to_string ( ) ) . unwrap ( ) ;
356+ assert_eq ! ( kind, DataKind :: Blocks ) ;
357+ assert_eq ! ( range, Range :: Single ( Height :: new( 21625120 , Some ( "b4e72a78fd2cb0e75768401a92e5258618eec892b7e4edb49b2a592e9a5de5c4" . to_string( ) ) ) ) ) ;
347358 }
348359
349360 #[ test]
350361 fn parse_single_tx_file ( ) {
351362 let ( kind, range) = Filenames :: parse ( "021625139.txes.avro" . to_string ( ) ) . unwrap ( ) ;
352363 assert_eq ! ( kind, DataKind :: Transactions ) ;
353- assert_eq ! ( range, Range :: Single ( 21625139 ) ) ;
364+ assert_eq ! ( range, Range :: Single ( 21625139 . into( ) ) ) ;
365+ assert ! ( range. first_height( ) . hash. is_none( ) ) ;
366+ }
367+
368+ #[ test]
369+ fn parse_single_tx_file_with_hash ( ) {
370+ let ( kind, range) = Filenames :: parse ( "021625139.b4e72a78fd2cb0e75768401a92e5258618eec892b7e4edb49b2a592e9a5de5c4.txes.avro" . to_string ( ) ) . unwrap ( ) ;
371+ assert_eq ! ( kind, DataKind :: Transactions ) ;
372+ assert_eq ! ( range, Range :: Single ( Height :: new( 21625139 , Some ( "b4e72a78fd2cb0e75768401a92e5258618eec892b7e4edb49b2a592e9a5de5c4" . to_string( ) ) ) ) ) ;
354373 }
355374
356375 #[ test]
357376 fn parse_single_tx_traces_file ( ) {
358377 let ( kind, range) = Filenames :: parse ( "021625139.traces.avro" . to_string ( ) ) . unwrap ( ) ;
359378 assert_eq ! ( kind, DataKind :: TransactionTraces ) ;
360- assert_eq ! ( range, Range :: Single ( 21625139 ) ) ;
379+ assert_eq ! ( range, Range :: Single ( 21625139 . into( ) ) ) ;
380+ assert ! ( range. first_height( ) . hash. is_none( ) ) ;
381+ }
382+
383+ #[ test]
384+ fn offset_single_block ( ) {
385+ let filenames = Filenames :: default ( ) ;
386+ let single = Range :: Single ( 12000000 . into ( ) ) ;
387+ assert_eq ! ( filenames. offset( & single) , "012000000" ) ;
388+ }
389+
390+ #[ test]
391+ fn offset_multi_block ( ) {
392+ let filenames = Filenames :: default ( ) ;
393+ let multi = Range :: Multiple ( 12000000 . into ( ) , 12000999 . into ( ) ) ;
394+ assert_eq ! ( filenames. offset( & multi) , "range-012000000" ) ;
395+ }
396+
397+ #[ test]
398+ fn offset_different_for_ranges ( ) {
399+ let filenames = Filenames :: default ( ) ;
400+ let multi = Range :: Multiple ( 12000000 . into ( ) , 12000999 . into ( ) ) ;
401+ let single = multi. first ( ) ;
402+ assert_ne ! ( filenames. offset( & single) , filenames. offset( & multi) ) ;
361403 }
362404}
0 commit comments