summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien F. Katz <damien@apache.org>2009-01-15 23:12:56 +0000
committerDamien F. Katz <damien@apache.org>2009-01-15 23:12:56 +0000
commit1c13d302c9bfa4e6532fab6fd9c210acd64b962f (patch)
tree1682cbb16823542101fd0d36184e3a863677223b
parent369dfbc2babdc2db0e5a07736b763bc06c5b9914 (diff)
Support for streaming attachment writes.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@734849 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/couchdb/couch_db.erl21
-rw-r--r--src/couchdb/couch_httpd.erl5
-rw-r--r--src/couchdb/couch_httpd_db.erl10
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,