Fix sorted=false feature
1. Enable the sorted=false parameter to map views
2. Enhance view_cb to tolerate rows before meta
3. Enhance view_cb to only send meta if no row has been sent
COUCHDB-3060
diff --git a/include/couch_mrview.hrl b/include/couch_mrview.hrl
index 7dc7190..2dfd398 100644
--- a/include/couch_mrview.hrl
+++ b/include/couch_mrview.hrl
@@ -98,7 +98,8 @@
should_close = false,
buffer = [],
bufsize = 0,
- threshold = 1490
+ threshold = 1490,
+ row_sent = false
}).
-record(lacc, {
diff --git a/src/couch_mrview_http.erl b/src/couch_mrview_http.erl
index 191198c..3a9aa33 100644
--- a/src/couch_mrview_http.erl
+++ b/src/couch_mrview_http.erl
@@ -340,6 +340,9 @@
Headers = [],
{ok, Resp} = chttpd:start_delayed_json_response(Acc#vacc.req, 200, Headers),
view_cb({meta, Meta}, Acc#vacc{resp=Resp, should_close=true});
+view_cb({meta, _Meta}, #vacc{row_sent=true}=Acc) ->
+ % sorted=false and meta arrived late, ignore it.
+ {ok, Acc};
view_cb({meta, Meta}, #vacc{}=Acc) ->
% Sending metadata
Parts = case couch_util:get_value(total, Meta) of
@@ -358,10 +361,15 @@
Chunk = [prepend_val(Acc), "{", string:join(Parts, ","), "\r\n"],
{ok, AccOut} = maybe_flush_response(Acc, Chunk, iolist_size(Chunk)),
{ok, AccOut#vacc{prepend=""}};
+view_cb({row, Row}, #vacc{resp=undefined}=Acc) ->
+ % sorted=false and a row arrived before meta, start response.
+ Pre = "{\"rows\":[\r\n",
+ {ok, Resp} = chttpd:start_delayed_json_response(Acc#vacc.req, 200, []),
+ view_cb({row, Row}, Acc#vacc{row_sent=true,resp=Resp, prepend=Pre, should_close=true});
view_cb({row, Row}, Acc) ->
% Adding another row
Chunk = [prepend_val(Acc), row_to_json(Row)],
- maybe_flush_response(Acc, Chunk, iolist_size(Chunk));
+ maybe_flush_response(Acc#vacc{row_sent=true}, Chunk, iolist_size(Chunk));
view_cb(complete, #vacc{resp=undefined}=Acc) ->
% Nothing in view
{ok, Resp} = chttpd:send_json(Acc#vacc.req, 200, {[{rows, []}]}),
@@ -538,6 +546,8 @@
Args#mrargs{conflicts=parse_boolean(Val)};
"callback" ->
Args#mrargs{callback=couch_util:to_binary(Val)};
+ "sorted" ->
+ Args#mrargs{sorted=parse_boolean(Val)};
_ ->
BKey = couch_util:to_binary(Key),
BVal = couch_util:to_binary(Val),
diff --git a/src/couch_mrview_util.erl b/src/couch_mrview_util.erl
index 51e51d8..934dcd3 100644
--- a/src/couch_mrview_util.erl
+++ b/src/couch_mrview_util.erl
@@ -510,6 +510,11 @@
{_, EKDocId1} -> EKDocId1
end,
+ case is_boolean(Args#mrargs.sorted) of
+ true -> ok;
+ _ -> mrverror(<<"Invalid value for `sorted`.">>)
+ end,
+
Args#mrargs{
start_key_docid=SKDocId,
end_key_docid=EKDocId,