summaryrefslogtreecommitdiff
path: root/src/couchdb/couch_db.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couchdb/couch_db.erl')
-rw-r--r--src/couchdb/couch_db.erl41
1 files changed, 38 insertions, 3 deletions
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index c35bb913..e9612b47 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -24,7 +24,6 @@
-export([start_link/3,make_doc/2,set_admins/2,get_admins/1,ensure_full_commit/1]).
-export([init/1,terminate/2,handle_call/3,handle_cast/2,code_change/3,handle_info/2]).
-
-include("couch_db.hrl").
@@ -400,8 +399,14 @@ doc_flush_binaries(Doc, Fd) ->
% written to a different file
SizeAcc + Len;
{_Key, {_Type, Bin}} when is_binary(Bin) ->
+ % we have a new binary to write
SizeAcc + size(Bin);
+ {_Key, {_Type, {Fun, undefined}}} when is_function(Fun) ->
+ % function without a known length
+ % we'll have to alloc as we go with this one, for now, nothing
+ SizeAcc;
{_Key, {_Type, {Fun, Len}}} when is_function(Fun) ->
+ % function to yield binary data with known length
SizeAcc + Len
end
end,
@@ -409,7 +414,6 @@ doc_flush_binaries(Doc, Fd) ->
{ok, OutputStream} = couch_stream:open(Fd),
ok = couch_stream:ensure_buffer(OutputStream, PreAllocSize),
-
NewBins = lists:map(
fun({Key, {Type, BinValue}}) ->
NewBinValue =
@@ -436,6 +440,18 @@ doc_flush_binaries(Doc, Fd) ->
Bin when is_binary(Bin) ->
{ok, StreamPointer} = couch_stream:write(OutputStream, Bin),
{Fd, StreamPointer, size(Bin)};
+ {StreamFun, undefined} when is_function(StreamFun) ->
+ % we will throw an error if the client
+ % sends a chunk larger than this size
+ MaxChunkSize = list_to_integer(couch_config:get("couchdb",
+ "max_attachment_chunk_size","4294967296")),
+ WriterFun = make_writer_fun(OutputStream),
+ % StreamFun(MaxChunkSize, WriterFun)
+ % will call our WriterFun
+ % once for each chunk of the attachment.
+ {ok, {TotalLength, NewStreamPointer}} =
+ StreamFun(MaxChunkSize, WriterFun, {0, nil}),
+ {Fd, NewStreamPointer, TotalLength};
{Fun, Len} when is_function(Fun) ->
{ok, StreamPointer} =
write_streamed_attachment(OutputStream, Fun, Len, nil),
@@ -445,8 +461,27 @@ doc_flush_binaries(Doc, Fd) ->
end, Bins),
{ok, _FinalPos} = couch_stream:close(OutputStream),
-
Doc#doc{attachments = NewBins}.
+
+
+make_writer_fun(Stream) ->
+ % WriterFun({Length, Binary}, State)
+ % WriterFun({0, _Footers}, State)
+ % Called with Length == 0 on the last time.
+ % WriterFun returns NewState.
+ fun
+ ({0, _Footers}, {FinalLen, SpFin}) ->
+ % last block, return the final tuple
+ {ok, {FinalLen, SpFin}};
+ ({Length, Bin}, {Total, nil}) ->
+ % save StreamPointer
+ {ok, StreamPointer} = couch_stream:write(Stream, Bin),
+ {Total+Length, StreamPointer};
+ ({Length, Bin}, {Total, SpAcc}) ->
+ % write the Bin to disk
+ {ok, _Sp} = couch_stream:write(Stream, Bin),
+ {Total+Length, SpAcc}
+ end.
write_streamed_attachment(_Stream, _F, 0, SpAcc) ->
{ok, SpAcc};