1
1
use std:: collections:: { HashMap , VecDeque } ;
2
- use std:: path:: { Path , PathBuf } ;
3
2
use std:: sync:: Arc ;
4
3
5
4
use futures:: stream:: BoxStream ;
@@ -86,34 +85,29 @@ impl WriteOptions {
86
85
87
86
#[ derive( Debug , Clone ) ]
88
87
struct MountLink {
89
- viewfs_path : PathBuf ,
90
- hdfs_path : PathBuf ,
88
+ viewfs_path : String ,
89
+ hdfs_path : String ,
91
90
protocol : Arc < NamenodeProtocol > ,
92
91
}
93
92
94
93
impl MountLink {
95
94
fn new ( viewfs_path : & str , hdfs_path : & str , protocol : Arc < NamenodeProtocol > ) -> Self {
96
95
// We should never have an empty path, we always want things mounted at root ("/") by default.
97
96
Self {
98
- viewfs_path : PathBuf :: from ( if viewfs_path. is_empty ( ) {
99
- "/"
100
- } else {
101
- viewfs_path
102
- } ) ,
103
- hdfs_path : PathBuf :: from ( if hdfs_path. is_empty ( ) { "/" } else { hdfs_path } ) ,
97
+ viewfs_path : viewfs_path. trim_end_matches ( "/" ) . to_string ( ) ,
98
+ hdfs_path : hdfs_path. trim_end_matches ( "/" ) . to_string ( ) ,
104
99
protocol,
105
100
}
106
101
}
107
102
/// Convert a viewfs path into a name service path if it matches this link
108
- fn resolve ( & self , path : & Path ) -> Option < PathBuf > {
109
- if let Ok ( relative_path) = path. strip_prefix ( & self . viewfs_path ) {
110
- if relative_path. components ( ) . count ( ) == 0 {
111
- Some ( self . hdfs_path . clone ( ) )
112
- } else {
113
- Some ( self . hdfs_path . join ( relative_path) )
114
- }
103
+ fn resolve ( & self , path : & str ) -> Option < String > {
104
+ // Make sure we don't partially match the last component. It either needs to be an exact
105
+ // match to a viewfs path, or needs to match with a trailing slash
106
+ if path == self . viewfs_path {
107
+ Some ( self . hdfs_path . clone ( ) )
115
108
} else {
116
- None
109
+ path. strip_prefix ( & format ! ( "{}/" , self . viewfs_path) )
110
+ . map ( |relative_path| format ! ( "{}/{}" , & self . hdfs_path, relative_path) )
117
111
}
118
112
}
119
113
}
@@ -126,20 +120,12 @@ struct MountTable {
126
120
127
121
impl MountTable {
128
122
fn resolve ( & self , src : & str ) -> ( & MountLink , String ) {
129
- let path = Path :: new ( src) ;
130
123
for link in self . mounts . iter ( ) {
131
- if let Some ( resolved) = link. resolve ( path ) {
132
- return ( link, resolved. to_string_lossy ( ) . into ( ) ) ;
124
+ if let Some ( resolved) = link. resolve ( src ) {
125
+ return ( link, resolved) ;
133
126
}
134
127
}
135
- (
136
- & self . fallback ,
137
- self . fallback
138
- . resolve ( path)
139
- . unwrap ( )
140
- . to_string_lossy ( )
141
- . into ( ) ,
142
- )
128
+ ( & self . fallback , self . fallback . resolve ( src) . unwrap ( ) )
143
129
}
144
130
}
145
131
@@ -246,7 +232,7 @@ impl Client {
246
232
247
233
if let Some ( fallback) = fallback {
248
234
// Sort the mount table from longest viewfs path to shortest. This makes sure more specific paths are considered first.
249
- mounts. sort_by_key ( |m| m. viewfs_path . components ( ) . count ( ) ) ;
235
+ mounts. sort_by_key ( |m| m. viewfs_path . chars ( ) . filter ( |c| * c == '/' ) . count ( ) ) ;
250
236
mounts. reverse ( ) ;
251
237
252
238
Ok ( MountTable { mounts, fallback } )
@@ -719,19 +705,16 @@ pub struct FileStatus {
719
705
720
706
impl FileStatus {
721
707
fn from ( value : HdfsFileStatusProto , base_path : & str ) -> Self {
722
- let mut path = PathBuf :: from ( base_path) ;
723
- if let Ok ( relative_path) = std:: str:: from_utf8 ( & value. path ) {
724
- if !relative_path. is_empty ( ) {
725
- path. push ( relative_path )
726
- }
708
+ let mut path = base_path. trim_end_matches ( "/" ) . to_string ( ) ;
709
+ let relative_path = std:: str:: from_utf8 ( & value. path ) . unwrap ( ) ;
710
+ if !relative_path. is_empty ( ) {
711
+ path. push ( '/' ) ;
712
+ path . push_str ( relative_path ) ;
727
713
}
728
714
729
715
FileStatus {
730
716
isdir : value. file_type ( ) == FileType :: IsDir ,
731
- path : path
732
- . to_str ( )
733
- . map ( |x| x. to_string ( ) )
734
- . unwrap_or ( String :: new ( ) ) ,
717
+ path,
735
718
length : value. length as usize ,
736
719
permission : value. permission . perm as u16 ,
737
720
owner : value. owner ,
@@ -769,10 +752,7 @@ impl From<ContentSummaryProto> for ContentSummary {
769
752
770
753
#[ cfg( test) ]
771
754
mod test {
772
- use std:: {
773
- path:: { Path , PathBuf } ,
774
- sync:: Arc ,
775
- } ;
755
+ use std:: sync:: Arc ;
776
756
777
757
use url:: Url ;
778
758
@@ -837,34 +817,22 @@ mod test {
837
817
let protocol = create_protocol ( "hdfs://127.0.0.1:9000" ) ;
838
818
let link = MountLink :: new ( "/view" , "/hdfs" , protocol) ;
839
819
840
- assert_eq ! (
841
- link. resolve( Path :: new( "/view/dir/file" ) ) . unwrap( ) ,
842
- PathBuf :: from( "/hdfs/dir/file" )
843
- ) ;
844
- assert_eq ! (
845
- link. resolve( Path :: new( "/view" ) ) . unwrap( ) ,
846
- PathBuf :: from( "/hdfs" )
847
- ) ;
848
- assert ! ( link. resolve( Path :: new( "/hdfs/path" ) ) . is_none( ) ) ;
820
+ assert_eq ! ( link. resolve( "/view/dir/file" ) . unwrap( ) , "/hdfs/dir/file" ) ;
821
+ assert_eq ! ( link. resolve( "/view" ) . unwrap( ) , "/hdfs" ) ;
822
+ assert ! ( link. resolve( "/hdfs/path" ) . is_none( ) ) ;
849
823
}
850
824
851
825
#[ test]
852
826
fn test_fallback_link ( ) {
853
827
let protocol = create_protocol ( "hdfs://127.0.0.1:9000" ) ;
854
- let link = MountLink :: new ( "" , "/hdfs" , protocol) ;
828
+ let link = MountLink :: new ( "" , "/hdfs" , Arc :: clone ( & protocol) ) ;
855
829
856
- assert_eq ! (
857
- link. resolve( Path :: new( "/path/to/file" ) ) . unwrap( ) ,
858
- PathBuf :: from( "/hdfs/path/to/file" )
859
- ) ;
860
- assert_eq ! (
861
- link. resolve( Path :: new( "/" ) ) . unwrap( ) ,
862
- PathBuf :: from( "/hdfs" )
863
- ) ;
864
- assert_eq ! (
865
- link. resolve( Path :: new( "/hdfs/path" ) ) . unwrap( ) ,
866
- PathBuf :: from( "/hdfs/hdfs/path" )
867
- ) ;
830
+ assert_eq ! ( link. resolve( "/path/to/file" ) . unwrap( ) , "/hdfs/path/to/file" ) ;
831
+ assert_eq ! ( link. resolve( "/" ) . unwrap( ) , "/hdfs/" ) ;
832
+ assert_eq ! ( link. resolve( "/hdfs/path" ) . unwrap( ) , "/hdfs/hdfs/path" ) ;
833
+
834
+ let link = MountLink :: new ( "" , "" , protocol) ;
835
+ assert_eq ! ( link. resolve( "/" ) . unwrap( ) , "/" ) ;
868
836
}
869
837
870
838
#[ test]
@@ -893,25 +861,25 @@ mod test {
893
861
894
862
// Exact mount path resolves to the exact HDFS path
895
863
let ( link, resolved) = mount_table. resolve ( "/mount1" ) ;
896
- assert_eq ! ( link. viewfs_path, Path :: new ( "/mount1" ) ) ;
864
+ assert_eq ! ( link. viewfs_path, "/mount1" ) ;
897
865
assert_eq ! ( resolved, "/path1/nested" ) ;
898
866
899
867
// Trailing slash is treated the same
900
868
let ( link, resolved) = mount_table. resolve ( "/mount1/" ) ;
901
- assert_eq ! ( link. viewfs_path, Path :: new ( "/mount1" ) ) ;
902
- assert_eq ! ( resolved, "/path1/nested" ) ;
869
+ assert_eq ! ( link. viewfs_path, "/mount1" ) ;
870
+ assert_eq ! ( resolved, "/path1/nested/ " ) ;
903
871
904
872
// Doesn't do partial matches on a directory name
905
873
let ( link, resolved) = mount_table. resolve ( "/mount12" ) ;
906
- assert_eq ! ( link. viewfs_path, Path :: new ( "/" ) ) ;
874
+ assert_eq ! ( link. viewfs_path, "" ) ;
907
875
assert_eq ! ( resolved, "/path4/mount12" ) ;
908
876
909
877
let ( link, resolved) = mount_table. resolve ( "/mount3/file" ) ;
910
- assert_eq ! ( link. viewfs_path, Path :: new ( "/" ) ) ;
878
+ assert_eq ! ( link. viewfs_path, "" ) ;
911
879
assert_eq ! ( resolved, "/path4/mount3/file" ) ;
912
880
913
881
let ( link, resolved) = mount_table. resolve ( "/mount3/nested/file" ) ;
914
- assert_eq ! ( link. viewfs_path, Path :: new ( "/mount3/nested" ) ) ;
882
+ assert_eq ! ( link. viewfs_path, "/mount3/nested" ) ;
915
883
assert_eq ! ( resolved, "/path3/file" ) ;
916
884
}
917
885
}
0 commit comments