From d32d766aced9413a7500e17bb670220f38e15205 Mon Sep 17 00:00:00 2001 From: "Damien F. Katz" Date: Thu, 12 Jun 2008 21:32:20 +0000 Subject: fix for problem when view index header data exceeds 2k. git-svn-id: https://svn.apache.org/repos/asf/incubator/couchdb/trunk@667236 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_file.erl | 76 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 22 deletions(-) (limited to 'src/couchdb/couch_file.erl') diff --git a/src/couchdb/couch_file.erl b/src/couchdb/couch_file.erl index d42d0eb6..26831c8c 100644 --- a/src/couchdb/couch_file.erl +++ b/src/couchdb/couch_file.erl @@ -93,7 +93,19 @@ expand(Fd, Bytes) when Bytes > 0 -> %%---------------------------------------------------------------------- append_term(Fd, Term) -> - gen_server:call(Fd, {append_term, Term}). + append_binary(Fd, term_to_binary(Term, [compressed])). + + +%%---------------------------------------------------------------------- +%% Purpose: To append an Erlang binary to the end of the file. +%% Args: Erlang term to serialize and append to the file. +%% Returns: {ok, Pos} where Pos is the file offset to the beginning the +%% serialized term. Use pread_term to read the term back. +%% or {error, Reason}. +%%---------------------------------------------------------------------- + +append_binary(Fd, Bin) -> + gen_server:call(Fd, {append_bin, Bin}). %%---------------------------------------------------------------------- @@ -104,7 +116,18 @@ append_term(Fd, Term) -> %%---------------------------------------------------------------------- pread_term(Fd, Pos) -> - gen_server:call(Fd, {pread_term, Pos}). + {ok, Bin} = pread_binary(Fd, Pos), + {ok, binary_to_term(Bin)}. + +%%---------------------------------------------------------------------- +%% Purpose: Reads a binrary from a file that was written with append_binary +%% Args: Pos, the offset into the file where the term is serialized. +%% Returns: {ok, Term} +%% or {error, Reason}. +%%---------------------------------------------------------------------- + +pread_binary(Fd, Pos) -> + gen_server:call(Fd, {pread_bin, Pos}). %%---------------------------------------------------------------------- @@ -144,30 +167,35 @@ close(Fd) -> write_header(Fd, Prefix, Data) -> - ok = sync(Fd), TermBin = term_to_binary(Data), % the size of all the bytes written to the header, including the md5 signature (16 bytes) FilledSize = size(Prefix) + size(TermBin) + 16, + {TermBin2, FilledSize2} = case FilledSize > ?HEADER_SIZE of true -> % too big! - {error, error_header_too_large}; + {ok, Pos} = append_binary(Fd, TermBin), + PtrBin = term_to_binary({pointer_to_header_data, Pos}), + {PtrBin, size(Prefix) + size(PtrBin) + 16}; false -> - % pad out the header with zeros, then take the md5 hash - PadZeros = <<0:(8*(?HEADER_SIZE - FilledSize))>>, - Sig = erlang:md5([TermBin, PadZeros]), - % now we assemble the final header binary and write to disk - WriteBin = <>, - ?HEADER_SIZE = size(WriteBin), % sanity check - DblWriteBin = [WriteBin, WriteBin], - ok = pwrite(Fd, 0, DblWriteBin), - ok = sync(Fd) - end. + {TermBin, FilledSize} + end, + ok = sync(Fd), + % pad out the header with zeros, then take the md5 hash + PadZeros = <<0:(8*(?HEADER_SIZE - FilledSize2))>>, + Sig = erlang:md5([TermBin2, PadZeros]), + % now we assemble the final header binary and write to disk + WriteBin = <>, + ?HEADER_SIZE = size(WriteBin), % sanity check + DblWriteBin = [WriteBin, WriteBin], + ok = pwrite(Fd, 0, DblWriteBin), + ok = sync(Fd). read_header(Fd, Prefix) -> {ok, Bin} = couch_file:pread(Fd, 0, 2*(?HEADER_SIZE)), <> = Bin, + Result = % read the first header case extract_header(Prefix, Bin1) of {ok, Header1} -> @@ -200,9 +228,14 @@ read_header(Fd, Prefix) -> % return the error, no need to log anything as the caller will be responsible for dealing with the error. {error, Error} end + end, + case Result of + {ok, {pointer_to_header_data, Ptr}} -> + pread_term(Fd, Ptr); + _ -> + Result end. - - + extract_header(Prefix, Bin) -> SizeOfPrefix = size(Prefix), SizeOfTermBin = ?HEADER_SIZE - @@ -300,17 +333,16 @@ handle_call(sync, _From, Fd) -> handle_call({truncate, Pos}, _From, Fd) -> {ok, Pos} = file:position(Fd, Pos), {reply, file:truncate(Fd), Fd}; -handle_call({append_term, Term}, _From, Fd) -> - Bin = term_to_binary(Term, [compressed]), - TermLen = size(Bin), - Bin2 = <>, +handle_call({append_bin, Bin}, _From, Fd) -> + Len = size(Bin), + Bin2 = <>, {ok, Pos} = file:position(Fd, eof), {reply, {file:pwrite(Fd, Pos, Bin2), Pos}, Fd}; -handle_call({pread_term, Pos}, _From, Fd) -> +handle_call({pread_bin, Pos}, _From, Fd) -> {ok, <>} = file:pread(Fd, Pos, 4), {ok, Bin} = file:pread(Fd, Pos + 4, TermLen), - {reply, {ok, binary_to_term(Bin)}, Fd}. + {reply, {ok, Bin}, Fd}. handle_cast(close, Fd) -> -- cgit v1.2.3