Extend `enable_database_recovery` behaviour to views directories If config option `enable_database_recovery` set to true then during database deletion all its ddoc's directories that hold view files will be renamed in the same fashion as database file, i.e. with added timestamp and suffix "deleted"
Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/f406dc60 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/f406dc60 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/f406dc60 Branch: refs/heads/master Commit: f406dc60d3af287d2cca001fc539a44fb37b8448 Parents: 9e0cb35 Author: Eric Avdey <[email protected]> Authored: Mon Apr 25 15:02:42 2016 -0300 Committer: Eric Avdey <[email protected]> Committed: Thu Apr 28 13:09:35 2016 -0300 ---------------------------------------------------------------------- src/couch_file.erl | 14 ++++++- test/couch_file_tests.erl | 92 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/f406dc60/src/couch_file.erl ---------------------------------------------------------------------- diff --git a/src/couch_file.erl b/src/couch_file.erl index d2c28d4..8aa4a50 100644 --- a/src/couch_file.erl +++ b/src/couch_file.erl @@ -264,6 +264,18 @@ deleted_filename(Original) -> filename:rootname(Original) ++ Suffix. nuke_dir(RootDelDir, Dir) -> + EnableRecovery = config:get_boolean("couchdb", + "enable_database_recovery", false), + case EnableRecovery of + true -> + rename_file(Dir); + false -> + delete_dir(RootDelDir, Dir) + end. + +delete_dir(RootDelDir, Dir) -> + DeleteAfterRename = config:get_boolean("couchdb", + "delete_after_rename", true), FoldFun = fun(File) -> Path = Dir ++ "/" ++ File, case filelib:is_dir(Path) of @@ -271,7 +283,7 @@ nuke_dir(RootDelDir, Dir) -> ok = nuke_dir(RootDelDir, Path), file:del_dir(Path); false -> - delete(RootDelDir, Path, false) + delete_file(RootDelDir, Path, false, DeleteAfterRename) end end, case file:list_dir(Dir) of http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/f406dc60/test/couch_file_tests.erl ---------------------------------------------------------------------- diff --git a/test/couch_file_tests.erl b/test/couch_file_tests.erl index 8edbaac..62f5844 100644 --- a/test/couch_file_tests.erl +++ b/test/couch_file_tests.erl @@ -346,3 +346,95 @@ make_delete_after_rename_test_case({RootDir, File}, DeleteAfterRename) -> ?_assertNot(FileExistsAfter), ?_assertEqual(ExpectRenamedCount, length(RenamedFiles)) ]. + + +nuke_dir_test_() -> + { + "Nuke directory tests", + { + foreach, + fun() -> + meck:new(config, [passthrough]), + File0 = ?tempfile() ++ ".couch", + RootDir = filename:dirname(File0), + BaseName = filename:basename(File0), + Seed = crypto:rand_uniform(1000000000, 9999999999), + DDocDir = io_lib:format("db.~b_design", [Seed]), + ViewDir = filename:join([RootDir, DDocDir]), + file:make_dir(ViewDir), + File = filename:join([ViewDir, BaseName]), + file:rename(File0, File), + ok = couch_file:init_delete_dir(RootDir), + ok = file:write_file(File, <<>>), + {RootDir, ViewDir} + end, + fun({RootDir, ViewDir}) -> + meck:unload(config), + remove_dir(ViewDir), + Ext = filename:extension(ViewDir), + case filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext) of + [DelDir] -> remove_dir(DelDir); + _ -> ok + end + end, + [ + fun(Cfg) -> + {"enable_database_recovery = false", + make_rename_dir_test_case(Cfg, false)} + end, + fun(Cfg) -> + {"enable_database_recovery = true", + make_rename_dir_test_case(Cfg, true)} + end, + fun(Cfg) -> + {"delete_after_rename = true", + make_delete_dir_test_case(Cfg, true)} + end, + fun(Cfg) -> + {"delete_after_rename = false", + make_delete_dir_test_case(Cfg, false)} + end + ] + } + }. + + +make_rename_dir_test_case({RootDir, ViewDir}, EnableRecovery) -> + meck:expect(config, get_boolean, fun + ("couchdb", "enable_database_recovery", _) -> EnableRecovery; + ("couchdb", "delete_after_rename", _) -> true + end), + DirExistsBefore = filelib:is_dir(ViewDir), + couch_file:nuke_dir(RootDir, ViewDir), + DirExistsAfter = filelib:is_dir(ViewDir), + Ext = filename:extension(ViewDir), + RenamedDirs = filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext), + ExpectRenamedCount = if EnableRecovery -> 1; true -> 0 end, + [ + ?_assert(DirExistsBefore), + ?_assertNot(DirExistsAfter), + ?_assertEqual(ExpectRenamedCount, length(RenamedDirs)) + ]. + +make_delete_dir_test_case({RootDir, ViewDir}, DeleteAfterRename) -> + meck:expect(config, get_boolean, fun + ("couchdb", "enable_database_recovery", _) -> false; + ("couchdb", "delete_after_rename", _) -> DeleteAfterRename + end), + DirExistsBefore = filelib:is_dir(ViewDir), + couch_file:nuke_dir(RootDir, ViewDir), + DirExistsAfter = filelib:is_dir(ViewDir), + Ext = filename:extension(ViewDir), + RenamedDirs = filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext), + RenamedFiles = filelib:wildcard(RootDir ++ "/.delete/*"), + ExpectRenamedCount = if DeleteAfterRename -> 0; true -> 1 end, + [ + ?_assert(DirExistsBefore), + ?_assertNot(DirExistsAfter), + ?_assertEqual(0, length(RenamedDirs)), + ?_assertEqual(ExpectRenamedCount, length(RenamedFiles)) + ]. + +remove_dir(Dir) -> + [file:delete(File) || File <- filelib:wildcard(filename:join([Dir, "*"]))], + file:del_dir(Dir).
