From 1c13d302c9bfa4e6532fab6fd9c210acd64b962f Mon Sep 17 00:00:00 2001 From: "Damien F. Katz" Date: Thu, 15 Jan 2009 23:12:56 +0000 Subject: Support for streaming attachment writes. git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@734849 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_db.erl | 21 +++++++++++++++++++-- src/couchdb/couch_httpd.erl | 5 ++++- src/couchdb/couch_httpd_db.erl | 10 +++++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl index 3011d744..b3102044 100644 --- a/src/couchdb/couch_db.erl +++ b/src/couchdb/couch_db.erl @@ -400,7 +400,9 @@ doc_flush_binaries(Doc, Fd) -> % written to a different file SizeAcc + Len; {_Key, {_Type, Bin}} when is_binary(Bin) -> - SizeAcc + size(Bin) + SizeAcc + size(Bin); + {_Key, {_Type, {Fun, Len}}} when is_function(Fun) -> + SizeAcc + Len end end, 0, Bins), @@ -433,7 +435,11 @@ doc_flush_binaries(Doc, Fd) -> {Fd, NewStreamPointer, Len}; Bin when is_binary(Bin) -> {ok, StreamPointer} = couch_stream:write(OutputStream, Bin), - {Fd, StreamPointer, size(Bin)} + {Fd, StreamPointer, size(Bin)}; + {Fun, Len} when is_function(Fun) -> + {ok, StreamPointer} = + write_streamed_attachment(OutputStream, Fun, Len, nil), + {Fd, StreamPointer, Len} end, {Key, {Type, NewBinValue}} end, Bins), @@ -441,6 +447,17 @@ doc_flush_binaries(Doc, Fd) -> {ok, _FinalPos} = couch_stream:close(OutputStream), Doc#doc{attachments = NewBins}. + +write_streamed_attachment(_Stream, _F, 0, SpAcc) -> + {ok, SpAcc}; +write_streamed_attachment(Stream, F, LenLeft, nil) -> + Bin = F(), + {ok, StreamPointer} = couch_stream:write(Stream, Bin), + write_streamed_attachment(Stream, F, LenLeft - size(Bin), StreamPointer); +write_streamed_attachment(Stream, F, LenLeft, SpAcc) -> + Bin = F(), + {ok, _} = couch_stream:write(Stream, Bin), + write_streamed_attachment(Stream, F, LenLeft - size(Bin), SpAcc). enum_docs_since_reduce_to_count(Reds) -> couch_btree:final_reduce( diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl index 38c34e17..93062d69 100644 --- a/src/couchdb/couch_httpd.erl +++ b/src/couchdb/couch_httpd.erl @@ -16,7 +16,7 @@ -export([start_link/0, stop/0, handle_request/3]). -export([header_value/2,header_value/3,qs_value/2,qs_value/3,qs/1,path/1]). --export([verify_is_server_admin/1,unquote/1]). +-export([verify_is_server_admin/1,unquote/1,recv/2]). -export([parse_form/1,json_body/1,body/1,doc_etag/1]). -export([primary_header_value/2,partition/1,serve_file/3]). -export([start_chunked_response/3,send_chunk/2]). @@ -244,6 +244,9 @@ unquote(UrlEncodedString) -> parse_form(#httpd{mochi_req=MochiReq}) -> mochiweb_multipart:parse_form(MochiReq). +recv(#httpd{mochi_req=MochiReq}, Len) -> + MochiReq:recv(Len). + body(#httpd{mochi_req=MochiReq}) -> MochiReq:recv_body(?MAX_DOC_SIZE). diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl index 44b6265c..cdebb1e3 100644 --- a/src/couchdb/couch_httpd_db.erl +++ b/src/couchdb/couch_httpd_db.erl @@ -255,7 +255,7 @@ db_req(#httpd{path_parts=[_,<<"_admins">>]}=Req, _Db) -> % Special case to enable using an unencoded slash in the URL of design docs, % as slashes in document IDs must otherwise be URL encoded. -db_req(#httpd{method='GET',mochi_req=MochiReq, path_parts=[DbName,<<"_design/",Name/binary>>|Rest]}=Req, Db) -> +db_req(#httpd{method='GET',mochi_req=MochiReq, path_parts=[DbName,<<"_design/",_/binary>>|_]}=Req, _Db) -> PathFront = "/" ++ binary_to_list(DbName) ++ "/_design", {ok, [PathFront|PathTail]} = regexp:split(MochiReq:get(raw_path),"%2F"), RedirectTo = PathFront ++ "/" ++ mochiweb_util:join(PathTail, "%2F"), @@ -279,7 +279,6 @@ all_docs_view(Req, Db, Keys) -> start_key = StartKey, start_docid = StartDocId, end_key = EndKey, - end_docid = EndDocId, limit = Limit, skip = SkipCount, direction = Dir @@ -590,7 +589,12 @@ db_attachment_req(#httpd{method=Method}=Req, Db, DocId, FileNameParts) _ -> [{FileName, { list_to_binary(couch_httpd:header_value(Req,"Content-Type")), - couch_httpd:body(Req) + case couch_httpd:header_value(Req,"Content-Length") of + undefined -> + throw({bad_request, "Attachment uploads must be fixed length"}); + Length -> + {fun() -> couch_httpd:recv(Req, 0) end, list_to_integer(Length)} + end }}] end, -- cgit v1.2.3