@@ -1335,19 +1335,9 @@ get_filestate(FileId, Dirname, ReadFiles, Mode) ->
1335
1335
1336
1336
1337
1337
list_data_files (Dirname , WritingFile , MergingFile ) ->
1338
- % % Get list of {tstamp, filename} for all files in the directory then
1339
- % % reverse sort that list and extract the fully-qualified filename.
1340
1338
Files1 = bitcask_fileops :data_file_tstamps (Dirname ),
1341
- Files2 = bitcask_fileops :data_file_tstamps (Dirname ),
1342
- % TODO: Remove crazy
1343
- if Files1 == Files2 ->
1344
- % % No race, Files1 is a stable list.
1345
- [F || {_Tstamp , F } <- lists :sort (Files1 ),
1346
- F /= WritingFile ,
1347
- F /= MergingFile ];
1348
- true ->
1349
- list_data_files (Dirname , WritingFile , MergingFile )
1350
- end .
1339
+ [F || {_Tstamp , F } <- lists :sort (Files1 ),
1340
+ F /= WritingFile , F /= MergingFile ].
1351
1341
1352
1342
merge_files (# mstate { input_files = [] } = State ) ->
1353
1343
State ;
@@ -1668,7 +1658,16 @@ readable_and_setuid_files(Dirname) ->
1668
1658
% % Filter out files with setuid bit set: they've been marked for
1669
1659
% % deletion by an earlier *successful* merge.
1670
1660
Fs = [F || F <- list_data_files (Dirname , WritingFile , MergingFile )],
1671
- lists :partition (fun (F ) -> not has_pending_delete_bit (F ) end , Fs ).
1661
+
1662
+ WritingFile2 = bitcask_lockops :read_activefile (write , Dirname ),
1663
+ MergingFile2 = bitcask_lockops :read_activefile (merge , Dirname ),
1664
+ case {WritingFile2 , MergingFile2 } of
1665
+ {WritingFile , MergingFile } ->
1666
+ lists :partition (fun (F ) -> not has_pending_delete_bit (F ) end , Fs );
1667
+ _ ->
1668
+ % Changed while fetching file list, retry
1669
+ readable_and_setuid_files (Dirname )
1670
+ end .
1672
1671
1673
1672
% % Internal put - have validated that the file is opened for write
1674
1673
% % and looked up the state at this point
@@ -2049,6 +2048,44 @@ list_data_files_test2() ->
2049
2048
% % Now use the list_data_files to scan the dir
2050
2049
ExpFiles = list_data_files (" /tmp/bc.test.list" , undefined , undefined ).
2051
2050
2051
+ % Test that readable_files will not return the currently active
2052
+ % write or merge file by mistake if they change in between fetching them
2053
+ % and listing the files in the directory.
2054
+ list_data_files_race_test () ->
2055
+ Dir = " /tmp/bc.test.list.race" ,
2056
+ Fname = fun (N ) ->
2057
+ filename :join (Dir , integer_to_list (N ) ++ " .bitcask.data" )
2058
+ end ,
2059
+ WriteFile = fun (N ) ->
2060
+ ok = file :write_file (Fname (N ), <<>>)
2061
+ end ,
2062
+ WriteFiles = fun (S ,E ) ->
2063
+ [WriteFile (N ) || N <- lists :seq (S , E )]
2064
+ end ,
2065
+ os :cmd (" rm -rf " ++ Dir ++ " ; mkdir -p " ++ Dir ),
2066
+ WriteFiles (1 ,5 ),
2067
+ % Faking 4 as merge file, 5 as write file,
2068
+ % then switching to 6 as merge, 7 as write
2069
+ KindN = fun (merge ) -> 4 ; (write ) -> 5 end ,
2070
+ meck :new (bitcask_lockops , [passthrough ]),
2071
+ meck :expect (bitcask_lockops , read_activefile ,
2072
+ fun (Kind , _ ) ->
2073
+ case get ({fake_activefile , Kind }) of
2074
+ undefined ->
2075
+ N = KindN (Kind ),
2076
+ % Next time return file + 2
2077
+ WriteFile (N + 2 ),
2078
+ put ({fake_activefile , Kind }, Fname (N + 2 )),
2079
+ Fname (N );
2080
+ File ->
2081
+ File
2082
+ end
2083
+ end ),
2084
+ ReadFiles = lists :usort (bitcask :readable_files (Dir )),
2085
+ meck :unload (),
2086
+ ? assertEqual ([Fname (N )||N <- lists :seq (1 ,5 )],
2087
+ ReadFiles ).
2088
+
2052
2089
fold_test_ () ->
2053
2090
{timeout , 60 , fun fold_test2 /0 }.
2054
2091
0 commit comments