From 88e4cf2361e7799429f1fce4530ed92deeb85e2a Mon Sep 17 00:00:00 2001 From: Martin Sumner Date: Thu, 27 Sep 2018 15:26:45 +0100 Subject: [PATCH] Add unit test with bad write If a partial write is made at the beginning, the file was not being truncated. Consequently writes would be accepted after it opens, and the those writes would be after the corruption so would never be read in the future. --- src/leveled_cdb.erl | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/leveled_cdb.erl b/src/leveled_cdb.erl index 8081ab2..935d2aa 100644 --- a/src/leveled_cdb.erl +++ b/src/leveled_cdb.erl @@ -1266,6 +1266,8 @@ scan_over_file(Handle, Position, FilterFun, Output, LastKey) -> case saferead_keyvalue(Handle) of false -> leveled_log:log("CDB09", [Position]), + % Bring file back to that position + {ok, Position} = file:position(Handle, {bof, Position}), {eof, Output}; {Key, ValueAsBin, KeyLength, ValueLength} -> NewPosition = case Key of @@ -1315,7 +1317,7 @@ saferead_keyvalue(Handle) -> case read_next_2_integers(Handle) of eof -> false; - {KeyL, ValueL} -> + {KeyL, ValueL} when is_integer(KeyL), is_integer(ValueL) -> case safe_read_next_keybin(Handle, KeyL) of false -> false; @@ -1327,7 +1329,9 @@ saferead_keyvalue(Handle) -> % i.e. value with no CRC {Key, TrueValue, KeyL, ValueL} end - end + end; + _ -> + false end. @@ -1434,7 +1438,7 @@ extract_valueandsize(ValueAsBin) -> %% Note that the endian_flip is required to make the file format compatible %% with CDB read_next_2_integers(Handle) -> - case file:read(Handle,?DWORD_SIZE) of + case file:read(Handle, ?DWORD_SIZE) of {ok, <>} -> {endian_flip(Int1), endian_flip(Int2)}; ReadError -> @@ -2565,6 +2569,20 @@ get_positions_corruption_test() -> ok = cdb_close(P3), file:delete(F2). +badly_written_test() -> + F1 = "../test/badfirstwrite_test.pnd", + file:delete(F1), + {ok, Handle} = file:open(F1, ?WRITE_OPS), + ok = file:pwrite(Handle, 256 * ?DWORD_SIZE, <<1:8/integer>>), + ok = file:close(Handle), + {ok, P1} = cdb_open_writer(F1, #cdb_options{binary_mode=false}), + ok = cdb_put(P1, "Key100", "Value100"), + ?assertMatch({"Key100", "Value100"}, cdb_get(P1, "Key100")), + ok = cdb_close(P1), + {ok, P2} = cdb_open_writer(F1, #cdb_options{binary_mode=false}), + ?assertMatch({"Key100", "Value100"}, cdb_get(P2, "Key100")), + ok = cdb_close(P2), + file:delete(F1). nonsense_coverage_test() ->