@@ -70,8 +70,10 @@ impl KVStore for FilesystemStore {
70
70
dest_file_path. push ( namespace) ;
71
71
dest_file_path. push ( key) ;
72
72
73
- let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
74
- let inner_lock_ref = Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) ) ;
73
+ let inner_lock_ref = {
74
+ let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
75
+ Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) )
76
+ } ;
75
77
let _guard = inner_lock_ref. read ( ) . unwrap ( ) ;
76
78
77
79
let mut buf = Vec :: new ( ) ;
@@ -103,10 +105,6 @@ impl KVStore for FilesystemStore {
103
105
dest_file_path. push ( namespace) ;
104
106
dest_file_path. push ( key) ;
105
107
106
- let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
107
- let inner_lock_ref = Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) ) ;
108
- let _guard = inner_lock_ref. write ( ) . unwrap ( ) ;
109
-
110
108
let parent_directory = dest_file_path
111
109
. parent ( )
112
110
. ok_or_else ( || {
@@ -132,6 +130,12 @@ impl KVStore for FilesystemStore {
132
130
tmp_file. sync_all ( ) ?;
133
131
}
134
132
133
+ let inner_lock_ref = {
134
+ let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
135
+ Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) )
136
+ } ;
137
+ let _guard = inner_lock_ref. write ( ) . unwrap ( ) ;
138
+
135
139
#[ cfg( not( target_os = "windows" ) ) ]
136
140
{
137
141
fs:: rename ( & tmp_file_path, & dest_file_path) ?;
@@ -186,51 +190,47 @@ impl KVStore for FilesystemStore {
186
190
dest_file_path. push ( namespace) ;
187
191
dest_file_path. push ( key) ;
188
192
189
- let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
190
- let inner_lock_ref = Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) ) ;
191
-
192
- let _guard = inner_lock_ref. write ( ) . unwrap ( ) ;
193
-
194
193
if !dest_file_path. is_file ( ) {
195
194
return Ok ( ( ) ) ;
196
195
}
197
196
198
- fs:: remove_file ( & dest_file_path) ?;
199
- #[ cfg( not( target_os = "windows" ) ) ]
200
197
{
201
- let parent_directory = dest_file_path. parent ( ) . ok_or_else ( || {
202
- let msg =
203
- format ! ( "Could not retrieve parent directory of {}." , dest_file_path. display( ) ) ;
204
- std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidInput , msg)
205
- } ) ?;
206
- let dir_file = fs:: OpenOptions :: new ( ) . read ( true ) . open ( parent_directory) ?;
207
- // The above call to `fs::remove_file` corresponds to POSIX `unlink`, whose changes
208
- // to the inode might get cached (and hence possibly lost on crash), depending on
209
- // the target platform and file system.
210
- //
211
- // In order to assert we permanently removed the file in question we therefore
212
- // call `fsync` on the parent directory on platforms that support it,
213
- dir_file. sync_all ( ) ?;
214
- }
198
+ let inner_lock_ref = {
199
+ let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
200
+ Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) )
201
+ } ;
202
+ let _guard = inner_lock_ref. write ( ) . unwrap ( ) ;
203
+
204
+ fs:: remove_file ( & dest_file_path) ?;
205
+ #[ cfg( not( target_os = "windows" ) ) ]
206
+ {
207
+ let parent_directory = dest_file_path. parent ( ) . ok_or_else ( || {
208
+ let msg =
209
+ format ! ( "Could not retrieve parent directory of {}." , dest_file_path. display( ) ) ;
210
+ std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidInput , msg)
211
+ } ) ?;
212
+ let dir_file = fs:: OpenOptions :: new ( ) . read ( true ) . open ( parent_directory) ?;
213
+ // The above call to `fs::remove_file` corresponds to POSIX `unlink`, whose changes
214
+ // to the inode might get cached (and hence possibly lost on crash), depending on
215
+ // the target platform and file system.
216
+ //
217
+ // In order to assert we permanently removed the file in question we therefore
218
+ // call `fsync` on the parent directory on platforms that support it,
219
+ dir_file. sync_all ( ) ?;
220
+ }
215
221
216
- if dest_file_path. is_file ( ) {
217
- return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , "Removing key failed" ) ) ;
222
+ if dest_file_path. is_file ( ) {
223
+ return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , "Removing key failed" ) ) ;
224
+ }
218
225
}
219
226
220
- if Arc :: strong_count ( & inner_lock_ref) == 2 {
221
- // It's safe to remove the lock entry if we're the only one left holding a strong
222
- // reference. Checking this is necessary to ensure we continue to distribute references to the
223
- // same lock as long as some Readers are around. However, we still want to
224
- // clean up the table when possible.
225
- //
226
- // Note that this by itself is still leaky as lock entries will remain when more Readers/Writers are
227
- // around, but is preferable to doing nothing *or* something overly complex such as
228
- // implementing yet another RAII structure just for this pupose.
229
- outer_lock. remove ( & dest_file_path) ;
230
- }
227
+ {
228
+ // Retake outer lock for the cleanup.
229
+ let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
231
230
232
- // Garbage collect all lock entries that are not referenced anymore.
233
- outer_lock. retain ( |_, v| Arc :: strong_count ( & v) > 1 ) ;
231
+ // Garbage collect all lock entries that are not referenced anymore.
232
+ outer_lock. retain ( |_, v| Arc :: strong_count ( & v) > 1 ) ;
233
+ }
234
234
235
235
Ok ( ( ) )
236
236
}
0 commit comments