1
1
use std:: {
2
2
collections:: { HashMap , HashSet } ,
3
+ fs:: File ,
3
4
io:: Write ,
4
5
path:: { Path , PathBuf } ,
5
6
str,
@@ -65,19 +66,43 @@ use error::ErrorKind;
65
66
/// half finished snapshot file. Deleting the inputs after the rename means that
66
67
/// the worst case is that we have some leftover incremental files which will
67
68
/// be deleted on the next compaction.
69
+ #[ derive( Debug ) ]
68
70
pub struct FsStore {
69
71
root : std:: path:: PathBuf ,
72
+ tmpdir : std:: path:: PathBuf ,
70
73
}
71
74
72
75
impl FsStore {
73
- /// Create an [`FsStore`] from a [`std::path::PathBuf`]
76
+ /// Creates a new [`FsStore`] from a [`Path`].
74
77
///
75
78
/// This will attempt to create the root directory and throw an error if
76
79
/// it does not exist.
77
80
pub fn open < P : AsRef < Path > > ( root : P ) -> Result < Self , std:: io:: Error > {
78
- std:: fs:: create_dir_all ( root. as_ref ( ) ) ?;
81
+ let root = root. as_ref ( ) ;
82
+ std:: fs:: create_dir_all ( root) ?;
79
83
Ok ( Self {
80
- root : root. as_ref ( ) . into ( ) ,
84
+ root : root. into ( ) ,
85
+ tmpdir : root. into ( ) ,
86
+ } )
87
+ }
88
+
89
+ /// Overrides the tmpdir directory used for temporary files.
90
+ ///
91
+ /// The default is to use the root directory passed to [`FsStore::open`].
92
+ ///
93
+ /// The tmpdir used must be on the same mount point as the root directory,
94
+ /// otherwise the store will throw an error on writing data.
95
+ ///
96
+ /// # Errors
97
+ ///
98
+ /// This will attempt to create the tmpdir directory and throw an error if
99
+ /// it does not exist.
100
+ pub fn with_tmpdir < P : AsRef < Path > > ( self , tmpdir : P ) -> Result < Self , std:: io:: Error > {
101
+ let tmpdir = tmpdir. as_ref ( ) ;
102
+ std:: fs:: create_dir_all ( tmpdir) ?;
103
+ Ok ( Self {
104
+ tmpdir : tmpdir. into ( ) ,
105
+ ..self
81
106
} )
82
107
}
83
108
@@ -150,7 +175,7 @@ impl FsStore {
150
175
} ) ?;
151
176
152
177
let chunk_name = SavedChunkName :: new_incremental ( changes) ;
153
- write_chunk ( & self . root , & paths, changes, chunk_name) ?;
178
+ write_chunk ( & self . root , & paths, changes, chunk_name, & self . tmpdir ) ?;
154
179
155
180
Ok ( ( ) )
156
181
}
@@ -170,7 +195,7 @@ impl FsStore {
170
195
// Write the snapshot
171
196
let output_chunk_name = SavedChunkName :: new_snapshot ( doc. get_heads ( ) ) ;
172
197
let chunk = doc. save ( ) ;
173
- write_chunk ( & self . root , & paths, & chunk, output_chunk_name) ?;
198
+ write_chunk ( & self . root , & paths, & chunk, output_chunk_name, & self . tmpdir ) ?;
174
199
175
200
// Remove all the old data
176
201
for incremental in chunks. incrementals . keys ( ) {
@@ -190,17 +215,18 @@ fn write_chunk(
190
215
paths : & DocIdPaths ,
191
216
chunk : & [ u8 ] ,
192
217
name : SavedChunkName ,
218
+ tmpdir : & Path ,
193
219
) -> Result < ( ) , Error > {
194
220
// Write to a temp file and then rename to avoid partial writes
195
- let mut temp_save =
196
- tempfile:: NamedTempFile :: new ( ) . map_err ( |e| Error ( ErrorKind :: CreateTempFile ( e) ) ) ?;
197
- let temp_save_path = temp_save. path ( ) . to_owned ( ) ;
198
- temp_save
199
- . as_file_mut ( )
221
+ let temp_dir =
222
+ tempfile:: TempDir :: new_in ( tmpdir) . map_err ( |e| Error ( ErrorKind :: CreateTempFile ( e) ) ) ?;
223
+ let temp_save_path = temp_dir. path ( ) . join ( name. filename ( ) ) ;
224
+ let mut temp_save_file =
225
+ File :: create ( & temp_save_path) . map_err ( |e| Error ( ErrorKind :: CreateTempFile ( e) ) ) ?;
226
+ temp_save_file
200
227
. write_all ( chunk)
201
228
. map_err ( |e| Error ( ErrorKind :: WriteTempFile ( temp_save_path. clone ( ) , e) ) ) ?;
202
- temp_save
203
- . as_file_mut ( )
229
+ temp_save_file
204
230
. sync_all ( )
205
231
. map_err ( |e| Error ( ErrorKind :: WriteTempFile ( temp_save_path. clone ( ) , e) ) ) ?;
206
232
0 commit comments