11use std:: collections:: HashMap ;
2+ use std:: fmt;
23use std:: fs:: { self , File , OpenOptions } ;
34use std:: io:: { self , BufWriter , Read , Seek , Write } ;
45use std:: ops:: Deref ;
56use std:: path:: { Path , PathBuf } ;
67use std:: sync:: { Arc , RwLock , Weak } ;
7- use std:: { fmt, result} ;
88
99use common:: StableDeref ;
1010use fs4:: FileExt ;
@@ -21,6 +21,7 @@ use crate::directory::{
2121 AntiCallToken , Directory , DirectoryLock , FileHandle , Lock , OwnedBytes , TerminatingWrite ,
2222 WatchCallback , WatchHandle , WritePtr ,
2323} ;
24+ #[ cfg( unix) ]
2425use crate :: Advice ;
2526
2627pub type ArcBytes = Arc < dyn Deref < Target = [ u8 ] > + Send + Sync + ' static > ;
@@ -33,10 +34,7 @@ pub(crate) fn make_io_err(msg: String) -> io::Error {
3334
3435/// Returns `None` iff the file exists, can be read, but is empty (and hence
3536/// cannot be mmapped)
36- fn open_mmap (
37- full_path : & Path ,
38- madvice_opt : Option < Advice > ,
39- ) -> result:: Result < Option < Mmap > , OpenReadError > {
37+ fn open_mmap ( full_path : & Path ) -> Result < Option < Mmap > , OpenReadError > {
4038 let file = File :: open ( full_path) . map_err ( |io_err| {
4139 if io_err. kind ( ) == io:: ErrorKind :: NotFound {
4240 OpenReadError :: FileDoesNotExist ( full_path. to_path_buf ( ) )
@@ -59,9 +57,7 @@ fn open_mmap(
5957 . map ( Some )
6058 . map_err ( |io_err| OpenReadError :: wrap_io_error ( io_err, full_path. to_path_buf ( ) ) )
6159 } ?;
62- if let ( Some ( mmap) , Some ( madvice) ) = ( & mmap_opt, madvice_opt) {
63- let _ = mmap. advise ( madvice) ;
64- }
60+
6561 Ok ( mmap_opt)
6662}
6763
@@ -83,18 +79,25 @@ pub struct CacheInfo {
8379struct MmapCache {
8480 counters : CacheCounters ,
8581 cache : HashMap < PathBuf , WeakArcBytes > ,
82+ #[ cfg( unix) ]
8683 madvice_opt : Option < Advice > ,
8784}
8885
8986impl MmapCache {
90- fn new ( madvice_opt : Option < Advice > ) -> MmapCache {
87+ fn new ( ) -> MmapCache {
9188 MmapCache {
9289 counters : CacheCounters :: default ( ) ,
9390 cache : HashMap :: default ( ) ,
94- madvice_opt,
91+ #[ cfg( unix) ]
92+ madvice_opt : None ,
9593 }
9694 }
9795
96+ #[ cfg( unix) ]
97+ fn set_advice ( & mut self , madvice : Advice ) {
98+ self . madvice_opt = Some ( madvice) ;
99+ }
100+
98101 fn get_info ( & self ) -> CacheInfo {
99102 let paths: Vec < PathBuf > = self . cache . keys ( ) . cloned ( ) . collect ( ) ;
100103 CacheInfo {
@@ -115,6 +118,16 @@ impl MmapCache {
115118 }
116119 }
117120
121+ fn open_mmap_impl ( & self , full_path : & Path ) -> Result < Option < Mmap > , OpenReadError > {
122+ let mmap_opt = open_mmap ( full_path) ?;
123+ #[ cfg( unix) ]
124+ if let ( Some ( mmap) , Some ( madvice) ) = ( mmap_opt. as_ref ( ) , self . madvice_opt ) {
125+ // We ignore madvise errors.
126+ let _ = mmap. advise ( madvice) ;
127+ }
128+ Ok ( mmap_opt)
129+ }
130+
118131 // Returns None if the file exists but as a len of 0 (and hence is not mmappable).
119132 fn get_mmap ( & mut self , full_path : & Path ) -> Result < Option < ArcBytes > , OpenReadError > {
120133 if let Some ( mmap_weak) = self . cache . get ( full_path) {
@@ -125,7 +138,7 @@ impl MmapCache {
125138 }
126139 self . cache . remove ( full_path) ;
127140 self . counters . miss += 1 ;
128- let mmap_opt = open_mmap ( full_path , self . madvice_opt ) ?;
141+ let mmap_opt = self . open_mmap_impl ( full_path ) ?;
129142 Ok ( mmap_opt. map ( |mmap| {
130143 let mmap_arc: ArcBytes = Arc :: new ( mmap) ;
131144 let mmap_weak = Arc :: downgrade ( & mmap_arc) ;
@@ -160,13 +173,9 @@ struct MmapDirectoryInner {
160173}
161174
162175impl MmapDirectoryInner {
163- fn new (
164- root_path : PathBuf ,
165- temp_directory : Option < TempDir > ,
166- madvice_opt : Option < Advice > ,
167- ) -> MmapDirectoryInner {
176+ fn new ( root_path : PathBuf , temp_directory : Option < TempDir > ) -> MmapDirectoryInner {
168177 MmapDirectoryInner {
169- mmap_cache : RwLock :: new ( MmapCache :: new ( madvice_opt ) ) ,
178+ mmap_cache : RwLock :: new ( MmapCache :: new ( ) ) ,
170179 _temp_directory : temp_directory,
171180 watcher : FileWatcher :: new ( & root_path. join ( * META_FILEPATH ) ) ,
172181 root_path,
@@ -185,12 +194,8 @@ impl fmt::Debug for MmapDirectory {
185194}
186195
187196impl MmapDirectory {
188- fn new (
189- root_path : PathBuf ,
190- temp_directory : Option < TempDir > ,
191- madvice_opt : Option < Advice > ,
192- ) -> MmapDirectory {
193- let inner = MmapDirectoryInner :: new ( root_path, temp_directory, madvice_opt) ;
197+ fn new ( root_path : PathBuf , temp_directory : Option < TempDir > ) -> MmapDirectory {
198+ let inner = MmapDirectoryInner :: new ( root_path, temp_directory) ;
194199 MmapDirectory {
195200 inner : Arc :: new ( inner) ,
196201 }
@@ -206,29 +211,33 @@ impl MmapDirectory {
206211 Ok ( MmapDirectory :: new (
207212 tempdir. path ( ) . to_path_buf ( ) ,
208213 Some ( tempdir) ,
209- None ,
210214 ) )
211215 }
212216
217+ /// Opens a MmapDirectory in a directory, with a given access pattern.
218+ ///
219+ /// This is only supported on unix platforms.
220+ #[ cfg( unix) ]
221+ pub fn open_with_madvice (
222+ directory_path : impl AsRef < Path > ,
223+ madvice : Advice ,
224+ ) -> Result < MmapDirectory , OpenDirectoryError > {
225+ let dir = Self :: open_impl_to_avoid_monomorphization ( directory_path. as_ref ( ) ) ?;
226+ dir. inner . mmap_cache . write ( ) . unwrap ( ) . set_advice ( madvice) ;
227+ Ok ( dir)
228+ }
229+
213230 /// Opens a MmapDirectory in a directory.
214231 ///
215232 /// Returns an error if the `directory_path` does not
216233 /// exist or if it is not a directory.
217- pub fn open < P : AsRef < Path > > ( directory_path : P ) -> Result < MmapDirectory , OpenDirectoryError > {
218- Self :: open_with_access_pattern_impl ( directory_path. as_ref ( ) , None )
219- }
220-
221- /// Opens a MmapDirectory in a directory, with a given access pattern.
222- pub fn open_with_madvice < P : AsRef < Path > > (
223- directory_path : P ,
224- madvice : Advice ,
225- ) -> Result < MmapDirectory , OpenDirectoryError > {
226- Self :: open_with_access_pattern_impl ( directory_path. as_ref ( ) , Some ( madvice) )
234+ pub fn open ( directory_path : impl AsRef < Path > ) -> Result < MmapDirectory , OpenDirectoryError > {
235+ Self :: open_impl_to_avoid_monomorphization ( directory_path. as_ref ( ) )
227236 }
228237
229- fn open_with_access_pattern_impl (
238+ #[ inline( never) ]
239+ fn open_impl_to_avoid_monomorphization (
230240 directory_path : & Path ,
231- madvice_opt : Option < Advice > ,
232241 ) -> Result < MmapDirectory , OpenDirectoryError > {
233242 if !directory_path. exists ( ) {
234243 return Err ( OpenDirectoryError :: DoesNotExist ( PathBuf :: from (
@@ -256,7 +265,7 @@ impl MmapDirectory {
256265 directory_path,
257266 ) ) ) ;
258267 }
259- Ok ( MmapDirectory :: new ( canonical_path, None , madvice_opt ) )
268+ Ok ( MmapDirectory :: new ( canonical_path, None ) )
260269 }
261270
262271 /// Joins a relative_path to the directory `root_path`
@@ -365,7 +374,7 @@ pub(crate) fn atomic_write(path: &Path, content: &[u8]) -> io::Result<()> {
365374}
366375
367376impl Directory for MmapDirectory {
368- fn get_file_handle ( & self , path : & Path ) -> result :: Result < Arc < dyn FileHandle > , OpenReadError > {
377+ fn get_file_handle ( & self , path : & Path ) -> Result < Arc < dyn FileHandle > , OpenReadError > {
369378 debug ! ( "Open Read {:?}" , path) ;
370379 let full_path = self . resolve_path ( path) ;
371380
@@ -388,7 +397,7 @@ impl Directory for MmapDirectory {
388397
389398 /// Any entry associated with the path in the mmap will be
390399 /// removed before the file is deleted.
391- fn delete ( & self , path : & Path ) -> result :: Result < ( ) , DeleteError > {
400+ fn delete ( & self , path : & Path ) -> Result < ( ) , DeleteError > {
392401 let full_path = self . resolve_path ( path) ;
393402 fs:: remove_file ( full_path) . map_err ( |e| {
394403 if e. kind ( ) == io:: ErrorKind :: NotFound {
0 commit comments