Skip to content

Commit 4baa263

Browse files
committed
Move view index files to .view_deleted when db is deleted
Bugzid 86318
1 parent c40b232 commit 4baa263

File tree

3 files changed

+67
-23
lines changed

3 files changed

+67
-23
lines changed

src/couch/src/couch_file.erl

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
-export([append_raw_chunk/2, assemble_file_chunk/1, assemble_file_chunk/2]).
4444
-export([append_term/2, append_term/3, append_term_md5/2, append_term_md5/3]).
4545
-export([write_header/2, read_header/1]).
46-
-export([delete/2, delete/3, nuke_dir/2, init_delete_dir/1]).
46+
-export([delete/2, delete/3, nuke_dir/2, nuke_dir/3, init_delete_dir/1]).
4747

4848
% gen_server callbacks
4949
-export([init/1, terminate/2, code_change/3]).
@@ -264,6 +264,16 @@ rename_file(Original) ->
264264
Else -> Else
265265
end.
266266

267+
rename_dir(RootDelDir, Original, DbName) ->
268+
DbDir = binary_to_list(DbName) ++ "_design",
269+
Deleted_Index_Dir = filename:join([RootDelDir, ".view_recovery", DbDir]),
270+
Now = calendar:local_time(),
271+
filelib:ensure_dir(Deleted_Index_Dir),
272+
case file:rename(Original, Deleted_Index_Dir) of
273+
ok -> file:change_time(Deleted_Index_Dir, Now);
274+
Else -> Else
275+
end.
276+
267277
deleted_filename(Original) ->
268278
{{Y, Mon, D}, {H, Min, S}} = calendar:universal_time(),
269279
Suffix = lists:flatten(
@@ -272,12 +282,20 @@ deleted_filename(Original) ->
272282
++ filename:extension(Original), [Y, Mon, D, H, Min, S])),
273283
filename:rootname(Original) ++ Suffix.
274284

275-
nuke_dir(RootDelDir, Dir) ->
285+
nuke_dir(RootDir, Dir) ->
286+
nuke_dir(RootDir, Dir, []).
287+
nuke_dir(RootDelDir, Dir, Options) ->
276288
EnableRecovery = config:get_boolean("couchdb",
277289
"enable_database_recovery", false),
278290
case EnableRecovery of
279291
true ->
280-
rename_file(Dir);
292+
Context = couch_util:get_value(context, Options, compaction),
293+
case Context =:= delete of
294+
true ->
295+
DbName = couch_util:get_value(db_name, Options),
296+
rename_dir(RootDelDir, Dir, DbName);
297+
false -> rename_file(Dir)
298+
end;
281299
false ->
282300
delete_dir(RootDelDir, Dir)
283301
end.

src/couch/test/couch_file_tests.erl

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -419,32 +419,47 @@ nuke_dir_test_() ->
419419
RootDir = filename:dirname(File0),
420420
BaseName = filename:basename(File0),
421421
Seed = crypto:rand_uniform(1000000000, 9999999999),
422-
DDocDir = io_lib:format("db.~b_design", [Seed]),
422+
DBName0 = io_lib:format("db.~b", [Seed]),
423+
DBName = iolist_to_binary(DBName0),
424+
DDocDir = io_lib:format("~s_design", [DBName0]),
423425
ViewDir = filename:join([RootDir, DDocDir]),
424426
file:make_dir(ViewDir),
425427
File = filename:join([ViewDir, BaseName]),
426428
file:rename(File0, File),
427429
ok = couch_file:init_delete_dir(RootDir),
428430
ok = file:write_file(File, <<>>),
429-
{RootDir, ViewDir}
431+
{RootDir, ViewDir, DBName}
430432
end,
431-
fun({RootDir, ViewDir}) ->
433+
fun({RootDir, ViewDir, _DBName}) ->
432434
meck:unload(config),
433435
remove_dir(ViewDir),
434436
Ext = filename:extension(ViewDir),
435437
case filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext) of
436438
[DelDir] -> remove_dir(DelDir);
437439
_ -> ok
440+
end,
441+
RecDirPaths = RootDir ++ "/.view_recovery" ++ "/*_design",
442+
case filelib:wildcard(RecDirPaths) of
443+
RecDirs -> [remove_dir(Dir) || Dir <- RecDirs];
444+
[] -> ok
438445
end
439446
end,
440447
[
441448
fun(Cfg) ->
442-
{"enable_database_recovery = false",
443-
make_rename_dir_test_case(Cfg, false)}
449+
{"enable_database_recovery = false, context = delete",
450+
make_rename_dir_test_case(Cfg, false, delete)}
451+
end,
452+
fun(Cfg) ->
453+
{"enable_database_recovery = false, context = compaction",
454+
make_rename_dir_test_case(Cfg, false, compaction)}
444455
end,
445456
fun(Cfg) ->
446-
{"enable_database_recovery = true",
447-
make_rename_dir_test_case(Cfg, true)}
457+
{"enable_database_recovery = true, context = delete",
458+
make_rename_dir_test_case(Cfg, true, delete)}
459+
end,
460+
fun(Cfg) ->
461+
{"enable_database_recovery = true, context = compaction",
462+
make_rename_dir_test_case(Cfg, true, compaction)}
448463
end,
449464
fun(Cfg) ->
450465
{"delete_after_rename = true",
@@ -459,24 +474,34 @@ nuke_dir_test_() ->
459474
}.
460475

461476

462-
make_rename_dir_test_case({RootDir, ViewDir}, EnableRecovery) ->
477+
make_rename_dir_test_case({RootDir, ViewDir, DBName}, EnableRecovery, Context) ->
463478
meck:expect(config, get_boolean, fun
464479
("couchdb", "enable_database_recovery", _) -> EnableRecovery;
465480
("couchdb", "delete_after_rename", _) -> true
466481
end),
467482
DirExistsBefore = filelib:is_dir(ViewDir),
468-
couch_file:nuke_dir(RootDir, ViewDir),
483+
484+
couch_file:nuke_dir(
485+
RootDir,
486+
ViewDir,
487+
[{db_name, DBName}, {context, Context}]
488+
),
469489
DirExistsAfter = filelib:is_dir(ViewDir),
470-
Ext = filename:extension(ViewDir),
471-
RenamedDirs = filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext),
490+
RenamedDirs = if Context =:= delete ->
491+
filelib:wildcard(RootDir ++ "/.view_recovery" ++ "/*_design");
492+
true ->
493+
Ext = filename:extension(ViewDir),
494+
filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext)
495+
end,
496+
472497
ExpectRenamedCount = if EnableRecovery -> 1; true -> 0 end,
473498
[
474499
?_assert(DirExistsBefore),
475500
?_assertNot(DirExistsAfter),
476501
?_assertEqual(ExpectRenamedCount, length(RenamedDirs))
477502
].
478503

479-
make_delete_dir_test_case({RootDir, ViewDir}, DeleteAfterRename) ->
504+
make_delete_dir_test_case({RootDir, ViewDir, _DBName}, DeleteAfterRename) ->
480505
meck:expect(config, get_boolean, fun
481506
("couchdb", "enable_database_recovery", _) -> false;
482507
("couchdb", "delete_after_rename", _) -> DeleteAfterRename

src/couch_index/src/couch_index_server.erl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,13 @@ handle_call({async_error, {DbName, _DDocId, Sig}, Error}, _From, State) ->
154154
[gen_server:reply(From, Error) || From <- Waiters],
155155
ets:delete(?BY_SIG, {DbName, Sig}),
156156
{reply, ok, State};
157-
handle_call({reset_indexes, DbName}, _From, State) ->
158-
reset_indexes(DbName, State#st.root_dir),
157+
handle_call({reset_indexes, Options}, _From, State) ->
158+
reset_indexes(Options, State#st.root_dir),
159159
{reply, ok, State}.
160160

161161

162-
handle_cast({reset_indexes, DbName}, State) ->
163-
reset_indexes(DbName, State#st.root_dir),
162+
handle_cast({reset_indexes, Options}, State) ->
163+
reset_indexes(Options, State#st.root_dir),
164164
{noreply, State}.
165165

166166
handle_info({'EXIT', Pid, Reason}, Server) ->
@@ -219,7 +219,8 @@ new_index({Mod, IdxState, DbName, Sig}) ->
219219
end.
220220

221221

222-
reset_indexes(DbName, Root) ->
222+
reset_indexes(Options, Root) ->
223+
DbName = couch_util:get_value(db_name, Options),
223224
% shutdown all the updaters and clear the files, the db got changed
224225
Fun = fun({_, {DDocId, Sig}}) ->
225226
[{_, Pid}] = ets:lookup(?BY_SIG, {DbName, Sig}),
@@ -230,7 +231,7 @@ reset_indexes(DbName, Root) ->
230231
end,
231232
lists:foreach(Fun, ets:lookup(?BY_DB, DbName)),
232233
Path = couch_index_util:index_dir("", DbName),
233-
couch_file:nuke_dir(Root, Path).
234+
couch_file:nuke_dir(Root, Path, Options).
234235

235236

236237
add_to_ets(DbName, Sig, DDocId, Pid) ->
@@ -246,10 +247,10 @@ rem_from_ets(DbName, Sig, DDocId, Pid) ->
246247

247248

248249
handle_db_event(DbName, created, St) ->
249-
gen_server:cast(?MODULE, {reset_indexes, DbName}),
250+
gen_server:cast(?MODULE, {reset_indexes, [{db_name, DbName}, {context, []}]}),
250251
{ok, St};
251252
handle_db_event(DbName, deleted, St) ->
252-
gen_server:cast(?MODULE, {reset_indexes, DbName}),
253+
gen_server:cast(?MODULE, {reset_indexes, [{db_name, DbName}, {context, delete}]}),
253254
{ok, St};
254255
handle_db_event(DbName, {ddoc_updated, DDocId}, St) ->
255256
lists:foreach(fun({_DbName, {_DDocId, Sig}}) ->

0 commit comments

Comments
 (0)