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).

Reply via email to