summaryrefslogtreecommitdiff
path: root/apps/couch
diff options
context:
space:
mode:
authorAdam Kocoloski <kocolosk@apache.org>2011-10-26 14:04:54 -0400
committerRobert Newson <robert.newson@cloudant.com>2011-10-31 17:19:27 +0000
commit7c94ebbf91f2c61b109af53cdbae530e79424849 (patch)
tree5f9c955ff5b4edddf29c6dca3299c821db4d8fc1 /apps/couch
parent9f734e042519b9e85260e40330fdcab20412427c (diff)
Fix retrieval of headers larger than 4k
Our headers start with a <<1>> and then four bytes indicating the length of the header and its checksum. When the header is larger than 4090 bytes it will be split across multiple blocks in the file and will need to be reassembled on read. The reassembly consists of stripping out <<0>> from the beginning of each subsequent block in the remove_block_prefixes/2 function. The bug here is that we tell remove_block_prefixes that we're starting 1 byte into the current block instead of 5, so it ends up removing one good byte from the header and injecting one or more random <<0>>s. Headers larger than 4k are very rare and generally require a view group with a huge number of indexes or indexes with fairly large reductions, which explains why this bug has gone undetected until now. Closes COUCHDB-1319.
Diffstat (limited to 'apps/couch')
-rw-r--r--apps/couch/src/couch_file.erl2
-rwxr-xr-xapps/couch/test/etap/011-file-headers.t9
2 files changed, 9 insertions, 2 deletions
diff --git a/apps/couch/src/couch_file.erl b/apps/couch/src/couch_file.erl
index dfc1f822..1985f5eb 100644
--- a/apps/couch/src/couch_file.erl
+++ b/apps/couch/src/couch_file.erl
@@ -528,7 +528,7 @@ load_header(Fd, Block) ->
RawBin = <<RestBlock/binary, Missing/binary>>
end,
<<Md5Sig:16/binary, HeaderBin/binary>> =
- iolist_to_binary(remove_block_prefixes(1, RawBin)),
+ iolist_to_binary(remove_block_prefixes(5, RawBin)),
Md5Sig = couch_util:md5(HeaderBin),
{ok, HeaderBin}.
diff --git a/apps/couch/test/etap/011-file-headers.t b/apps/couch/test/etap/011-file-headers.t
index 4705f629..764b10df 100755
--- a/apps/couch/test/etap/011-file-headers.t
+++ b/apps/couch/test/etap/011-file-headers.t
@@ -22,7 +22,7 @@ main(_) ->
{S1, S2, S3} = now(),
random:seed(S1, S2, S3),
- etap:plan(17),
+ etap:plan(18),
case (catch test()) of
ok ->
etap:end_tests();
@@ -68,6 +68,13 @@ test() ->
etap:is({ok, Size2}, couch_file:bytes(Fd),
"Rewriting the same second header returns the same second size."),
+ couch_file:write_header(Fd, erlang:make_tuple(5000, <<"CouchDB">>)),
+ etap:is(
+ couch_file:read_header(Fd),
+ {ok, erlang:make_tuple(5000, <<"CouchDB">>)},
+ "Headers larger than the block size can be saved (COUCHDB-1319)"
+ ),
+
ok = couch_file:close(Fd),
% Now for the fun stuff. Try corrupting the second header and see