summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorPaul J. Davis <paul.joseph.davis@gmail.com>2012-01-31 14:34:59 -0500
committerPaul J. Davis <paul.joseph.davis@gmail.com>2012-01-31 14:37:53 -0500
commitf199c336b304b1a9abc03d6898b10dafb7a17ad6 (patch)
tree87d0316775cf5a5642ebfa1e9807d568ebe049d6 /apps
parent6696d6fd42620f87f29f09f03daaf5fbe454e10d (diff)
Fix bug in replicator request piplining
A replication with both an HTTP source and target on the same host and port could end up in a dead lock due to ibrowse replication pipelining when attachments are present on the source. The ibrowse http worker would end up forming a multipart/mime body using anonymous reader functions for attachment stubs. When the attachment stub functions are executed it is possible that they end up assigned to the same ibrowse worker. This is a bit of a long path but then end result is equivalent to calling gen_server:call(self(), Args, infinity) from a gen_server callback. A quick work around for users is to set up a DNA alias (possibly in /etc/hosts) or to use a combination of hostname and ip address so that ibrowse assigns the requests to different pools.
Diffstat (limited to 'apps')
-rw-r--r--apps/couch/src/couch_rep_writer.erl19
1 files changed, 12 insertions, 7 deletions
diff --git a/apps/couch/src/couch_rep_writer.erl b/apps/couch/src/couch_rep_writer.erl
index 40323925..6f557107 100644
--- a/apps/couch/src/couch_rep_writer.erl
+++ b/apps/couch/src/couch_rep_writer.erl
@@ -126,13 +126,18 @@ write_multi_part_doc(#http_db{headers=Headers} = Db, #doc{atts=Atts} = Doc) ->
{"Content-Length", Len} | Headers
]
},
- Result = case couch_rep_httpc:request(Request) of
- {[{<<"error">>, Error}, {<<"reason">>, Reason}]} ->
- {Pos, [RevId | _]} = Doc#doc.revs,
- ErrId = couch_util:to_existing_atom(Error),
- [{Doc#doc.id, couch_doc:rev_to_str({Pos, RevId})}, {ErrId, Reason}];
- _ ->
- []
+ Conn = couch_rep_httpc:spawn_link_worker_process(Request),
+ Result = try
+ case couch_rep_httpc:request(Request) of
+ {[{<<"error">>, Error}, {<<"reason">>, Reason}]} ->
+ {Pos, [RevId | _]} = Doc#doc.revs,
+ ErrId = couch_util:to_existing_atom(Error),
+ [{Doc#doc.id, couch_doc:rev_to_str({Pos, RevId})}, {ErrId, Reason}];
+ _ ->
+ []
+ end
+ after
+ ibrowse:stop_worker_process(Conn)
end,
StreamerPid ! stop,
Result.