aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Bolinder <hasse@erlang.org>2011-10-10 15:44:34 +0200
committerHans Bolinder <hasse@erlang.org>2011-10-10 15:44:34 +0200
commit30c169c79a4602d6f63cc0d6f5ba171cca8c1863 (patch)
treeef0ee464edf4d005de577ced2cad1ead5272e35a
parenta5abe96590ec22779f796fc67e5afbbf99a3a922 (diff)
downloadotp-30c169c79a4602d6f63cc0d6f5ba171cca8c1863.tar.gz
otp-30c169c79a4602d6f63cc0d6f5ba171cca8c1863.tar.bz2
otp-30c169c79a4602d6f63cc0d6f5ba171cca8c1863.zip
Fix a minor bug in Dets
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.
-rw-r--r--lib/stdlib/src/dets.erl87
-rw-r--r--lib/stdlib/test/dets_SUITE.erl4
2 files changed, 60 insertions, 31 deletions
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index fa0641ffd9..7ed9c4b695 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -2475,10 +2475,25 @@ 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 ->
@@ -2486,9 +2501,9 @@ 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;
@@ -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 ->
@@ -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}});
@@ -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(),
@@ -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) ->
@@ -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) ->
@@ -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.
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index b569ed9003..b68d83b12d 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -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.