1
1
use std:: collections:: HashMap ;
2
+ use std:: fmt;
2
3
use std:: fs:: { self , File , OpenOptions } ;
3
4
use std:: io:: { self , BufWriter , Read , Seek , Write } ;
4
5
use std:: ops:: Deref ;
5
6
use std:: path:: { Path , PathBuf } ;
6
7
use std:: sync:: { Arc , RwLock , Weak } ;
7
- use std:: { fmt, result} ;
8
8
9
9
use common:: StableDeref ;
10
10
use fs4:: FileExt ;
@@ -21,6 +21,7 @@ use crate::directory::{
21
21
AntiCallToken , Directory , DirectoryLock , FileHandle , Lock , OwnedBytes , TerminatingWrite ,
22
22
WatchCallback , WatchHandle , WritePtr ,
23
23
} ;
24
+ #[ cfg( unix) ]
24
25
use crate :: Advice ;
25
26
26
27
pub type ArcBytes = Arc < dyn Deref < Target = [ u8 ] > + Send + Sync + ' static > ;
@@ -33,10 +34,7 @@ pub(crate) fn make_io_err(msg: String) -> io::Error {
33
34
34
35
/// Returns `None` iff the file exists, can be read, but is empty (and hence
35
36
/// 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 > {
40
38
let file = File :: open ( full_path) . map_err ( |io_err| {
41
39
if io_err. kind ( ) == io:: ErrorKind :: NotFound {
42
40
OpenReadError :: FileDoesNotExist ( full_path. to_path_buf ( ) )
@@ -59,9 +57,7 @@ fn open_mmap(
59
57
. map ( Some )
60
58
. map_err ( |io_err| OpenReadError :: wrap_io_error ( io_err, full_path. to_path_buf ( ) ) )
61
59
} ?;
62
- if let ( Some ( mmap) , Some ( madvice) ) = ( & mmap_opt, madvice_opt) {
63
- let _ = mmap. advise ( madvice) ;
64
- }
60
+
65
61
Ok ( mmap_opt)
66
62
}
67
63
@@ -83,18 +79,25 @@ pub struct CacheInfo {
83
79
struct MmapCache {
84
80
counters : CacheCounters ,
85
81
cache : HashMap < PathBuf , WeakArcBytes > ,
82
+ #[ cfg( unix) ]
86
83
madvice_opt : Option < Advice > ,
87
84
}
88
85
89
86
impl MmapCache {
90
- fn new ( madvice_opt : Option < Advice > ) -> MmapCache {
87
+ fn new ( ) -> MmapCache {
91
88
MmapCache {
92
89
counters : CacheCounters :: default ( ) ,
93
90
cache : HashMap :: default ( ) ,
94
- madvice_opt,
91
+ #[ cfg( unix) ]
92
+ madvice_opt : None ,
95
93
}
96
94
}
97
95
96
+ #[ cfg( unix) ]
97
+ fn set_advice ( & mut self , madvice : Advice ) {
98
+ self . madvice_opt = Some ( madvice) ;
99
+ }
100
+
98
101
fn get_info ( & self ) -> CacheInfo {
99
102
let paths: Vec < PathBuf > = self . cache . keys ( ) . cloned ( ) . collect ( ) ;
100
103
CacheInfo {
@@ -115,6 +118,16 @@ impl MmapCache {
115
118
}
116
119
}
117
120
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
+
118
131
// Returns None if the file exists but as a len of 0 (and hence is not mmappable).
119
132
fn get_mmap ( & mut self , full_path : & Path ) -> Result < Option < ArcBytes > , OpenReadError > {
120
133
if let Some ( mmap_weak) = self . cache . get ( full_path) {
@@ -125,7 +138,7 @@ impl MmapCache {
125
138
}
126
139
self . cache . remove ( full_path) ;
127
140
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 ) ?;
129
142
Ok ( mmap_opt. map ( |mmap| {
130
143
let mmap_arc: ArcBytes = Arc :: new ( mmap) ;
131
144
let mmap_weak = Arc :: downgrade ( & mmap_arc) ;
@@ -160,13 +173,9 @@ struct MmapDirectoryInner {
160
173
}
161
174
162
175
impl 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 {
168
177
MmapDirectoryInner {
169
- mmap_cache : RwLock :: new ( MmapCache :: new ( madvice_opt ) ) ,
178
+ mmap_cache : RwLock :: new ( MmapCache :: new ( ) ) ,
170
179
_temp_directory : temp_directory,
171
180
watcher : FileWatcher :: new ( & root_path. join ( * META_FILEPATH ) ) ,
172
181
root_path,
@@ -185,12 +194,8 @@ impl fmt::Debug for MmapDirectory {
185
194
}
186
195
187
196
impl 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) ;
194
199
MmapDirectory {
195
200
inner : Arc :: new ( inner) ,
196
201
}
@@ -206,29 +211,33 @@ impl MmapDirectory {
206
211
Ok ( MmapDirectory :: new (
207
212
tempdir. path ( ) . to_path_buf ( ) ,
208
213
Some ( tempdir) ,
209
- None ,
210
214
) )
211
215
}
212
216
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
+
213
230
/// Opens a MmapDirectory in a directory.
214
231
///
215
232
/// Returns an error if the `directory_path` does not
216
233
/// 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 ( ) )
227
236
}
228
237
229
- fn open_with_access_pattern_impl (
238
+ #[ inline( never) ]
239
+ fn open_impl_to_avoid_monomorphization (
230
240
directory_path : & Path ,
231
- madvice_opt : Option < Advice > ,
232
241
) -> Result < MmapDirectory , OpenDirectoryError > {
233
242
if !directory_path. exists ( ) {
234
243
return Err ( OpenDirectoryError :: DoesNotExist ( PathBuf :: from (
@@ -256,7 +265,7 @@ impl MmapDirectory {
256
265
directory_path,
257
266
) ) ) ;
258
267
}
259
- Ok ( MmapDirectory :: new ( canonical_path, None , madvice_opt ) )
268
+ Ok ( MmapDirectory :: new ( canonical_path, None ) )
260
269
}
261
270
262
271
/// Joins a relative_path to the directory `root_path`
@@ -365,7 +374,7 @@ pub(crate) fn atomic_write(path: &Path, content: &[u8]) -> io::Result<()> {
365
374
}
366
375
367
376
impl 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 > {
369
378
debug ! ( "Open Read {:?}" , path) ;
370
379
let full_path = self . resolve_path ( path) ;
371
380
@@ -388,7 +397,7 @@ impl Directory for MmapDirectory {
388
397
389
398
/// Any entry associated with the path in the mmap will be
390
399
/// removed before the file is deleted.
391
- fn delete ( & self , path : & Path ) -> result :: Result < ( ) , DeleteError > {
400
+ fn delete ( & self , path : & Path ) -> Result < ( ) , DeleteError > {
392
401
let full_path = self . resolve_path ( path) ;
393
402
fs:: remove_file ( full_path) . map_err ( |e| {
394
403
if e. kind ( ) == io:: ErrorKind :: NotFound {
0 commit comments