Skip to content
This repository has been archived by the owner on Sep 4, 2019. It is now read-only.

Commit

Permalink
Fix a minor bug in Dets
Browse files Browse the repository at this point in the history
If a Dets table had been properly closed but the space management data
could not been read, it was not possible to repair the file.
  • Loading branch information
uabboli committed Oct 10, 2011
1 parent a5abe96 commit 30c169c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 31 deletions.
87 changes: 57 additions & 30 deletions lib/stdlib/src/dets.erl
Expand Up @@ -2475,20 +2475,35 @@ fopen2(Fname, Tab) ->
%% Fd is not always closed upon error, but exit is soon called.
{ok, Fd, FH} = read_file_header(Fname, Acc, Ram),
Mod = FH#fileheader.mod,
case Mod:check_file_header(FH, Fd) of
{error, not_closed} ->
io:format(user,"dets: file ~p not properly closed, "
"repairing ...~n", [Fname]),
Do = case Mod:check_file_header(FH, Fd) of
{ok, Head1, ExtraInfo} ->
Head2 = Head1#head{filename = Fname},
try Mod:init_freelist(Head2, ExtraInfo) of
Ftab ->
{ok, Head1#head{freelists = Ftab}}
catch
throw:_ ->
{repair, " has bad free lists, repairing ..."}
end;
{error, not_closed} ->
M = " not properly closed, repairing ...",
{repair, M};
Else ->
Else
end,
case Do of
{repair, Mess} ->
io:format(user, "dets: file ~p~s~n", [Fname, Mess]),
Version = default,
case fsck(Fd, Tab, Fname, FH, default, default, Version) of
ok ->
fopen2(Fname, Tab);
Error ->
throw(Error)
end;
{ok, Head, ExtraInfo} ->
{ok, Head} ->
open_final(Head, Fname, Acc, Ram, ?DEFAULT_CACHE,
Tab, ExtraInfo, false);
Tab, false);
{error, Reason} ->
throw({error, {Reason, Fname}})
end;
Expand Down Expand Up @@ -2520,12 +2535,13 @@ fopen_existing_file(Tab, OpenArgs) ->
V9 = (Version =:= 9) or (Version =:= default),
MinF = (MinSlots =:= default) or (MinSlots =:= FH#fileheader.min_no_slots),
MaxF = (MaxSlots =:= default) or (MaxSlots =:= FH#fileheader.max_no_slots),
Do = case (FH#fileheader.mod):check_file_header(FH, Fd) of
Mod = (FH#fileheader.mod),
Wh = case Mod:check_file_header(FH, Fd) of
{ok, Head, true} when Rep =:= force, Acc =:= read_write,
FH#fileheader.version =:= 9,
FH#fileheader.no_colls =/= undefined,
MinF, MaxF, V9 ->
{compact, Head};
{compact, Head, true};
{ok, _Head, _Extra} when Rep =:= force, Acc =:= read ->
throw({error, {access_mode, Fname}});
{ok, Head, need_compacting} when Acc =:= read ->
Expand Down Expand Up @@ -2555,6 +2571,19 @@ fopen_existing_file(Tab, OpenArgs) ->
{error, Reason} ->
throw({error, {Reason, Fname}})
end,
Do = case Wh of
{Tag, Hd, Extra} when Tag =:= final; Tag =:= compact ->
Hd1 = Hd#head{filename = Fname},
try Mod:init_freelist(Hd1, Extra) of
Ftab ->
{Tag, Hd#head{freelists = Ftab}}
catch
throw:_ ->
{repair, " has bad free lists, repairing ..."}
end;
Else ->
Else
end,
case Do of
_ when FH#fileheader.type =/= Type ->
throw({error, {type_mismatch, Fname}});
Expand All @@ -2563,8 +2592,7 @@ fopen_existing_file(Tab, OpenArgs) ->
{compact, SourceHead} ->
io:format(user, "dets: file ~p is now compacted ...~n", [Fname]),
{ok, NewSourceHead} = open_final(SourceHead, Fname, read, false,
?DEFAULT_CACHE, Tab, true,
Debug),
?DEFAULT_CACHE, Tab, Debug),
case catch compact(NewSourceHead) of
ok ->
erlang:garbage_collect(),
Expand All @@ -2584,9 +2612,9 @@ fopen_existing_file(Tab, OpenArgs) ->
Version, OpenArgs);
_ when FH#fileheader.version =/= Version, Version =/= default ->
throw({error, {version_mismatch, Fname}});
{final, H, EI} ->
{final, H} ->
H1 = H#head{auto_save = Auto},
open_final(H1, Fname, Acc, Ram, CacheSz, Tab, EI, Debug)
open_final(H1, Fname, Acc, Ram, CacheSz, Tab, Debug)
end.

do_repair(Fd, Tab, Fname, FH, MinSlots, MaxSlots, Version, OpenArgs) ->
Expand All @@ -2600,19 +2628,16 @@ do_repair(Fd, Tab, Fname, FH, MinSlots, MaxSlots, Version, OpenArgs) ->
end.

%% -> {ok, head()} | throw(Error)
open_final(Head, Fname, Acc, Ram, CacheSz, Tab, ExtraInfo, Debug) ->
open_final(Head, Fname, Acc, Ram, CacheSz, Tab, Debug) ->
Head1 = Head#head{access = Acc,
ram_file = Ram,
filename = Fname,
name = Tab,
cache = dets_utils:new_cache(CacheSz)},
init_disk_map(Head1#head.version, Tab, Debug),
Mod = Head#head.mod,
Mod:cache_segps(Head1#head.fptr, Fname, Head1#head.next),
Ftab = Mod:init_freelist(Head1, ExtraInfo),
(Head1#head.mod):cache_segps(Head1#head.fptr, Fname, Head1#head.next),
check_growth(Head1),
NewHead = Head1#head{freelists = Ftab},
{ok, NewHead}.
{ok, Head1}.

%% -> {ok, head()} | throw(Error)
fopen_init_file(Tab, OpenArgs) ->
Expand Down Expand Up @@ -3241,18 +3266,20 @@ view(FileName) ->
case catch read_file_header(FileName, read, false) of
{ok, Fd, FH} ->
Mod = FH#fileheader.mod,
case Mod:check_file_header(FH, Fd) of
{ok, H0, ExtraInfo} ->
Ftab = Mod:init_freelist(H0, ExtraInfo),
{_Bump, Base} = constants(FH, FileName),
H = H0#head{freelists=Ftab, base = Base},
v_free_list(H),
Mod:v_segments(H),
file:close(Fd);
X ->
file:close(Fd),
X
end;
try
case Mod:check_file_header(FH, Fd) of
{ok, H0, ExtraInfo} ->
Ftab = Mod:init_freelist(H0, ExtraInfo),
{_Bump, Base} = constants(FH, FileName),
H = H0#head{freelists=Ftab, base = Base},
v_free_list(H),
Mod:v_segments(H),
ok;
X ->
X
end
after file:close(Fd)
end;
X ->
X
end.
Expand Down
4 changes: 3 additions & 1 deletion lib/stdlib/test/dets_SUITE.erl
Expand Up @@ -1568,8 +1568,10 @@ repair(Config, V) ->
?line FileSize = dets:info(TabRef, memory),
?line ok = dets:close(TabRef),
crash(Fname, FileSize+20),
?line {error, {bad_freelists, Fname}} =
%% Used to return bad_freelists, but that changed in OTP-9622
?line {ok, TabRef} =
dets:open_file(TabRef, [{file,Fname},{version,V}]),
?line ok = dets:close(TabRef),
?line file:delete(Fname),

%% File not closed, opening with read and read_write access tried.
Expand Down

0 comments on commit 30c169c

Please sign in to comment.