Repository: couchdb-couch Updated Branches: refs/heads/master 311ba943c -> 2ae31331e
Implement rename_on_delete Sometimes it is usefull to keep deleted db files around. For backup reasons for example. This commit implements the feature. The feature is enabled by specifying `rename_on_delete = true` in `[couchdb]` of the config. Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/2ae31331 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/2ae31331 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/2ae31331 Branch: refs/heads/master Commit: 2ae31331e0b0c42045d5a29b842136ec0b85563d Parents: 311ba94 Author: ILYA Khlopotov <[email protected]> Authored: Wed Aug 12 09:25:30 2015 -0700 Committer: ILYA Khlopotov <[email protected]> Committed: Wed Aug 12 09:25:30 2015 -0700 ---------------------------------------------------------------------- src/couch_server.erl | 22 ++++++++-- test/couch_server_tests.erl | 88 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/2ae31331/src/couch_server.erl ---------------------------------------------------------------------- diff --git a/src/couch_server.erl b/src/couch_server.erl index e1ee3de..fd468c5 100644 --- a/src/couch_server.erl +++ b/src/couch_server.erl @@ -460,9 +460,7 @@ handle_call({delete, DbName, Options}, _From, Server) -> couch_db_plugin:on_delete(DbName, Options), - Async = not lists:member(sync, Options), - - case couch_file:delete(Server#server.root_dir, FullFilepath, Async) of + case delete_db_file(Server#server.root_dir, FullFilepath, Options) of ok -> couch_event:notify(DbName, deleted), {reply, ok, Server2}; @@ -539,3 +537,21 @@ db_closed(Server, Options) -> false -> Server#server{dbs_open=Server#server.dbs_open - 1}; true -> Server end. + +delete_db_file(RootDir, FullFilePath, Options) -> + Async = not lists:member(sync, Options), + RenameOnDelete = config:get_boolean("couchdb", "rename_on_delete", false), + case {Async, RenameOnDelete} of + {_, true} -> + rename_on_delete(FullFilePath); + {Async, false} -> + couch_file:delete(RootDir, FullFilePath, Async) + end. + +rename_on_delete(Original) -> + {{Y,Mon,D}, {H,Min,S}} = calendar:universal_time(), + Suffix = lists:flatten( + io_lib:format(".~w~2.10.0B~2.10.0B." ++ + "~2.10.0B~2.10.0B~2.10.0B.deleted.couch", [Y,Mon,D,H,Min,S])), + Rename = filename:rootname(Original) ++ Suffix, + file:rename(Original, Rename). http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/2ae31331/test/couch_server_tests.erl ---------------------------------------------------------------------- diff --git a/test/couch_server_tests.erl b/test/couch_server_tests.erl new file mode 100644 index 0000000..3df48a3 --- /dev/null +++ b/test/couch_server_tests.erl @@ -0,0 +1,88 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-module(couch_server_tests). + +-include_lib("couch/include/couch_eunit.hrl"). +-include_lib("couch/include/couch_db.hrl"). + +start() -> + Ctx = test_util:start_couch(), + config:set("log", "include_sasl", "false", false), + Ctx. + +setup() -> + DbName = ?tempdb(), + {ok, Db} = couch_db:create(DbName, []), + Db. + +setup(rename) -> + config:set("couchdb", "rename_on_delete", "true", false), + setup(); +setup(_) -> + setup(). + +teardown(Db) -> + (catch couch_db:close(Db)), + (catch file:delete(Db#db.filepath)). + +teardown(rename, Db) -> + config:set("couchdb", "rename_on_delete", "false", false), + teardown(Db); +teardown(_, Db) -> + teardown(Db). + + +delete_db_test_() -> + { + "Test for proper deletion of db file", + { + setup, + fun start/0, fun test_util:stop/1, + [ + make_test_case(rename, [fun should_rename_on_delete/2]), + make_test_case(delete, [fun should_delete/2]) + ] + } + }. + +make_test_case(Mod, Funs) -> + { + lists:flatten(io_lib:format("~s", [Mod])), + {foreachx, fun setup/1, fun teardown/2, [{Mod, Fun} || Fun <- Funs]} + }. + +should_rename_on_delete(_, #db{filepath = Origin, name = DbName}) -> + Renamed = renamed_filename(Origin), + ?_test(begin + ?assert(filelib:is_regular(Origin)), + ?assertMatch(ok, couch_server:delete(DbName, [])), + ?assert(filelib:is_regular(Renamed)), + ?assertNot(filelib:is_regular(Origin)) + end). + +should_delete(_, #db{filepath = Origin, name = DbName}) -> + PossiblyRenamed = renamed_filename(Origin), + ?_test(begin + ?assert(filelib:is_regular(Origin)), + ?assertMatch(ok, couch_server:delete(DbName, [])), + ?assertNot(filelib:is_regular(PossiblyRenamed)), + ?assertNot(filelib:is_regular(Origin)) + end). + + +renamed_filename(Original) -> + {{Y,Mon,D}, {H,Min,S}} = calendar:universal_time(), + Suffix = lists:flatten( + io_lib:format(".~w~2.10.0B~2.10.0B." ++ + "~2.10.0B~2.10.0B~2.10.0B.deleted.couch", [Y,Mon,D,H,Min,S])), + filename:rootname(Original) ++ Suffix.
