summaryrefslogtreecommitdiff
path: root/src/couchdb
diff options
context:
space:
mode:
authorJohn Christopher Anderson <jchris@apache.org>2009-06-14 18:45:49 +0000
committerJohn Christopher Anderson <jchris@apache.org>2009-06-14 18:45:49 +0000
commitcd39ebe7d12d999324ff2cc9842567b34dc4d4c7 (patch)
tree00bde7d855ba9cd07c2e5d0463dfd32c4f0badcc /src/couchdb
parent88fcbd2cdd14fedab900fbf3af3deb5fe15f4390 (diff)
merge list-iterator branch to trunk. changes JavaScript _list API
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@784601 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/couchdb')
-rw-r--r--src/couchdb/couch_httpd.erl8
-rw-r--r--src/couchdb/couch_httpd_show.erl181
-rw-r--r--src/couchdb/couch_js.c9
-rw-r--r--src/couchdb/couch_os_process.erl8
-rw-r--r--src/couchdb/couch_query_servers.erl37
5 files changed, 107 insertions, 136 deletions
diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl
index 457ab519..3417b850 100644
--- a/src/couchdb/couch_httpd.erl
+++ b/src/couchdb/couch_httpd.erl
@@ -177,6 +177,14 @@ handle_request(MochiReq, DefaultFun,
% ?LOG_DEBUG("Minor error in HTTP request: ~p",[Error]),
% ?LOG_DEBUG("Stacktrace: ~p",[erlang:get_stacktrace()]),
send_error(HttpReq, Error);
+ error:badarg ->
+ ?LOG_ERROR("Badarg error in HTTP request",[]),
+ ?LOG_INFO("Stacktrace: ~p",[erlang:get_stacktrace()]),
+ send_error(HttpReq, badarg);
+ error:function_clause ->
+ ?LOG_ERROR("function_clause error in HTTP request",[]),
+ ?LOG_INFO("Stacktrace: ~p",[erlang:get_stacktrace()]),
+ send_error(HttpReq, function_clause);
Tag:Error ->
?LOG_ERROR("Uncaught error in HTTP request: ~p",[{Tag, Error}]),
?LOG_INFO("Stacktrace: ~p",[erlang:get_stacktrace()]),
diff --git a/src/couchdb/couch_httpd_show.erl b/src/couchdb/couch_httpd_show.erl
index 49dd88bc..ef5d41d1 100644
--- a/src/couchdb/couch_httpd_show.erl
+++ b/src/couchdb/couch_httpd_show.erl
@@ -117,47 +117,6 @@ send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req, Db, Keys) ->
end
end.
-make_map_start_resp_fun(QueryServer, Db) ->
- fun(Req, CurrentEtag, TotalViewCount, Offset, _Acc) ->
- ExternalResp = couch_query_servers:render_list_head(QueryServer,
- Req, Db, TotalViewCount, Offset),
- JsonResp = apply_etag(ExternalResp, CurrentEtag),
- #extern_resp_args{
- code = Code,
- data = BeginBody,
- ctype = CType,
- headers = ExtHeaders
- } = couch_httpd_external:parse_external_response(JsonResp),
- JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
- {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders),
- {ok, Resp, binary_to_list(BeginBody)}
- end.
-
-make_map_send_row_fun(QueryServer, Req) ->
- fun(Resp, Db2, {{Key, DocId}, Value}, _IncludeDocs, RowFront) ->
- try
- JsonResp = couch_query_servers:render_list_row(QueryServer,
- Req, Db2, {{Key, DocId}, Value}),
- #extern_resp_args{
- stop = StopIter,
- data = RowBody
- } = couch_httpd_external:parse_external_response(JsonResp),
- case StopIter of
- true -> {stop, ""};
- _ ->
- Chunk = RowFront ++ binary_to_list(RowBody),
- case Chunk of
- [] -> ok;
- _ -> send_chunk(Resp, Chunk)
- end,
- {ok, ""}
- end
- catch
- throw:Error ->
- send_chunked_error(Resp, Error),
- throw({already_sent, Resp, Error})
- end
- end.
output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, nil) ->
#view_query_args{
@@ -179,7 +138,7 @@ output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Quer
{ok, QueryServer} = couch_query_servers:start_view_list(Lang, ListSrc),
StartListRespFun = make_map_start_resp_fun(QueryServer, Db),
- SendListRowFun = make_map_send_row_fun(QueryServer, Req),
+ SendListRowFun = make_map_send_row_fun(QueryServer),
FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, CurrentEtag, Db, RowCount,
#view_fold_helper_funs{
@@ -189,7 +148,7 @@ output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Quer
}),
FoldAccInit = {Limit, SkipCount, undefined, []},
{ok, FoldResult} = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit),
- finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, RowCount)
+ finish_list(Req, QueryServer, CurrentEtag, FoldResult, StartListRespFun, RowCount)
end);
output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, Keys) ->
@@ -210,7 +169,7 @@ output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Quer
{ok, QueryServer} = couch_query_servers:start_view_list(Lang, ListSrc),
StartListRespFun = make_map_start_resp_fun(QueryServer, Db),
- SendListRowFun = make_map_send_row_fun(QueryServer, Req),
+ SendListRowFun = make_map_send_row_fun(QueryServer),
FoldAccInit = {Limit, SkipCount, undefined, []},
{ok, FoldResult} = lists:foldl(
@@ -226,49 +185,64 @@ output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Quer
}),
couch_view:fold(View, {Key, StartDocId}, Dir, FoldlFun, FoldAcc)
end, {ok, FoldAccInit}, Keys),
- finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, RowCount)
+ finish_list(Req, QueryServer, CurrentEtag, FoldResult, StartListRespFun, RowCount)
end).
-make_reduce_start_resp_fun(QueryServer, Req, Db, CurrentEtag) ->
- fun(Req2, _Etag, _Acc) ->
- JsonResp = couch_query_servers:render_reduce_head(QueryServer,
- Req2, Db),
- JsonResp2 = apply_etag(JsonResp, CurrentEtag),
- #extern_resp_args{
- code = Code,
- data = BeginBody,
- ctype = CType,
- headers = ExtHeaders
- } = couch_httpd_external:parse_external_response(JsonResp2),
- JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
- {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders),
- {ok, Resp, binary_to_list(BeginBody)}
+make_map_start_resp_fun(QueryServer, Db) ->
+ fun(Req, Etag, TotalRows, Offset, _Acc) ->
+ Head = {[{<<"total_rows">>, TotalRows}, {<<"offset">>, Offset}]},
+ start_list_resp(QueryServer, Req, Db, Head, Etag)
end.
-make_reduce_send_row_fun(QueryServer, Req, Db) ->
- fun(Resp, {Key, Value}, RowFront) ->
- try
- JsonResp = couch_query_servers:render_reduce_row(QueryServer,
- Req, Db, {Key, Value}),
- #extern_resp_args{
- stop = StopIter,
- data = RowBody
- } = couch_httpd_external:parse_external_response(JsonResp),
- case StopIter of
- true -> {stop, ""};
- _ ->
- Chunk = RowFront ++ binary_to_list(RowBody),
- case Chunk of
- [] -> ok;
- _ -> send_chunk(Resp, Chunk)
- end,
- {ok, ""}
- end
- catch
- throw:Error ->
- send_chunked_error(Resp, Error),
- throw({already_sent, Resp, Error})
+make_reduce_start_resp_fun(QueryServer, _Req, Db, _CurrentEtag) ->
+ fun(Req2, Etag, _Acc) ->
+ start_list_resp(QueryServer, Req2, Db, {[]}, Etag)
+ end.
+
+start_list_resp(QueryServer, Req, Db, Head, Etag) ->
+ [<<"start">>,Chunks,JsonResp] = couch_query_servers:render_list_head(QueryServer,
+ Req, Db, Head),
+ JsonResp2 = apply_etag(JsonResp, Etag),
+ #extern_resp_args{
+ code = Code,
+ ctype = CType,
+ headers = ExtHeaders
+ } = couch_httpd_external:parse_external_response(JsonResp2),
+ JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
+ {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders),
+ {ok, Resp, ?b2l(?l2b(Chunks))}.
+
+make_map_send_row_fun(QueryServer) ->
+ fun(Resp, Db, Row, _IncludeDocs, RowFront) ->
+ send_list_row(Resp, QueryServer, Db, Row, RowFront)
+ end.
+
+make_reduce_send_row_fun(QueryServer, Db) ->
+ fun(Resp, Row, RowFront) ->
+ send_list_row(Resp, QueryServer, Db, Row, RowFront)
+ end.
+
+send_list_row(Resp, QueryServer, Db, Row, RowFront) ->
+ try
+ [Go,Chunks] = couch_query_servers:render_list_row(QueryServer, Db, Row),
+ Chunk = RowFront ++ ?b2l(?l2b(Chunks)),
+ send_non_empty_chunk(Resp, Chunk),
+ case Go of
+ <<"chunks">> ->
+ {ok, ""};
+ <<"end">> ->
+ {stop, stop}
end
+ catch
+ throw:Error ->
+ send_chunked_error(Resp, Error),
+ throw({already_sent, Resp, Error})
+ end.
+
+send_non_empty_chunk(Resp, Chunk) ->
+ case Chunk of
+ [] -> ok;
+ _ -> send_chunk(Resp, Chunk)
end.
output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, nil) ->
@@ -291,7 +265,7 @@ output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Q
CurrentEtag = couch_httpd_view:view_group_etag(Group, {Lang, ListSrc, Accept}),
couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
StartListRespFun = make_reduce_start_resp_fun(QueryServer, Req, Db, CurrentEtag),
- SendListRowFun = make_reduce_send_row_fun(QueryServer, Req, Db),
+ SendListRowFun = make_reduce_send_row_fun(QueryServer, Db),
{ok, GroupRowsFun, RespFun} = couch_httpd_view:make_reduce_fold_funs(Req,
GroupLevel, QueryArgs, CurrentEtag,
@@ -303,7 +277,7 @@ output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Q
{ok, FoldResult} = couch_view:fold_reduce(View, Dir, {StartKey, StartDocId},
{EndKey, EndDocId}, GroupRowsFun, RespFun,
FoldAccInit),
- finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, null)
+ finish_list(Req, QueryServer, CurrentEtag, FoldResult, StartListRespFun, null)
end);
output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, Keys) ->
@@ -325,7 +299,7 @@ output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Q
couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
StartListRespFun = make_reduce_start_resp_fun(QueryServer, Req, Db, CurrentEtag),
- SendListRowFun = make_reduce_send_row_fun(QueryServer, Req, Db),
+ SendListRowFun = make_reduce_send_row_fun(QueryServer, Db),
{ok, GroupRowsFun, RespFun} = couch_httpd_view:make_reduce_fold_funs(Req,
GroupLevel, QueryArgs, CurrentEtag,
@@ -339,33 +313,30 @@ output_reduce_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, Q
couch_view:fold_reduce(View, Dir, {Key, StartDocId},
{Key, EndDocId}, GroupRowsFun, RespFun, FoldAcc)
end, {ok, FoldAccInit}, Keys),
- finish_list(Req, Db, QueryServer, CurrentEtag, FoldResult, StartListRespFun, null)
+ finish_list(Req, QueryServer, CurrentEtag, FoldResult, StartListRespFun, null)
end).
-finish_list(Req, Db, QueryServer, Etag, FoldResult, StartListRespFun, TotalRows) ->
- {Resp, BeginBody} = case FoldResult of
+finish_list(Req, QueryServer, Etag, FoldResult, StartFun, TotalRows) ->
+ case FoldResult of
{_, _, undefined, _} ->
- {ok, Resp2, BeginBody2} = render_head_for_empty_list(StartListRespFun, Req, Etag, TotalRows),
- {Resp2, BeginBody2};
- {_, _, Resp0, _} ->
- {Resp0, ""}
- end,
- JsonTail = couch_query_servers:render_list_tail(QueryServer, Req, Db),
- #extern_resp_args{
- data = Tail
- } = couch_httpd_external:parse_external_response(JsonTail),
- Chunk = BeginBody ++ binary_to_list(Tail),
- case Chunk of
- [] -> ok;
- _ -> send_chunk(Resp, Chunk)
+ {ok, Resp, BeginBody} =
+ render_head_for_empty_list(StartFun, Req, Etag, TotalRows),
+ [<<"end">>, Chunks] = couch_query_servers:render_list_tail(QueryServer),
+ Chunk = BeginBody ++ ?b2l(?l2b(Chunks)),
+ send_non_empty_chunk(Resp, Chunk);
+ {_, _, Resp, stop} ->
+ ok;
+ {_, _, Resp, _} ->
+ [<<"end">>, Chunks] = couch_query_servers:render_list_tail(QueryServer),
+ send_non_empty_chunk(Resp, ?b2l(?l2b(Chunks)))
end,
send_chunk(Resp, []).
render_head_for_empty_list(StartListRespFun, Req, Etag, null) ->
- StartListRespFun(Req, Etag, []);
+ StartListRespFun(Req, Etag, []); % for reduce
render_head_for_empty_list(StartListRespFun, Req, Etag, TotalRows) ->
StartListRespFun(Req, Etag, TotalRows, null, []).
-
+
send_doc_show_response(Lang, ShowSrc, DocId, nil, #httpd{mochi_req=MReq}=Req, Db) ->
% compute etag with no doc
Headers = MReq:get(headers),
@@ -373,7 +344,7 @@ send_doc_show_response(Lang, ShowSrc, DocId, nil, #httpd{mochi_req=MReq}=Req, Db
Accept = proplists:get_value('Accept', Hlist),
CurrentEtag = couch_httpd:make_etag({Lang, ShowSrc, nil, Accept}),
couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
- ExternalResp = couch_query_servers:render_doc_show(Lang, ShowSrc,
+ [<<"resp">>, ExternalResp] = couch_query_servers:render_doc_show(Lang, ShowSrc,
DocId, nil, Req, Db),
JsonResp = apply_etag(ExternalResp, CurrentEtag),
couch_httpd_external:send_external_response(Req, JsonResp)
@@ -387,7 +358,7 @@ send_doc_show_response(Lang, ShowSrc, DocId, #doc{revs=Revs}=Doc, #httpd{mochi_r
CurrentEtag = couch_httpd:make_etag({Lang, ShowSrc, Revs, Accept}),
% We know our etag now
couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
- ExternalResp = couch_query_servers:render_doc_show(Lang, ShowSrc,
+ [<<"resp">>, ExternalResp] = couch_query_servers:render_doc_show(Lang, ShowSrc,
DocId, Doc, Req, Db),
JsonResp = apply_etag(ExternalResp, CurrentEtag),
couch_httpd_external:send_external_response(Req, JsonResp)
diff --git a/src/couchdb/couch_js.c b/src/couchdb/couch_js.c
index 045e6c7f..d95b9db0 100644
--- a/src/couchdb/couch_js.c
+++ b/src/couchdb/couch_js.c
@@ -247,13 +247,13 @@ GC(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
static JSBool
Print(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- uintN i, n;
+ uintN i;
size_t cl, bl;
JSString *str;
jschar *chars;
char *bytes;
- for (i = n = 0; i < argc; i++) {
+ for (i = 0; i < argc; i++) {
str = JS_ValueToString(context, argv[i]);
if (!str)
return JS_FALSE;
@@ -270,9 +270,8 @@ Print(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
fprintf(stdout, "%s%s", i ? " " : "", bytes);
JS_free(context, bytes);
}
- n++;
- if (n)
- fputc('\n', stdout);
+
+ fputc('\n', stdout);
fflush(stdout);
return JS_TRUE;
}
diff --git a/src/couchdb/couch_os_process.erl b/src/couchdb/couch_os_process.erl
index 66853b65..ef2e8bfc 100644
--- a/src/couchdb/couch_os_process.erl
+++ b/src/couchdb/couch_os_process.erl
@@ -53,7 +53,7 @@ prompt(Pid, Data) ->
{ok, Result} ->
Result;
Error ->
- ?LOG_DEBUG("OS Process Error ~p",[Error]),
+ ?LOG_ERROR("OS Process Error :: ~p",[Error]),
throw(Error)
end.
@@ -81,20 +81,22 @@ readline(OsProc, Acc) when is_record(OsProc, os_proc) ->
% Standard JSON functions
writejson(OsProc, Data) when is_record(OsProc, os_proc) ->
+ % ?LOG_DEBUG("OS Process Input :: ~p", [Data]),
true = writeline(OsProc, ?JSON_ENCODE(Data)).
readjson(OsProc) when is_record(OsProc, os_proc) ->
Line = readline(OsProc),
case ?JSON_DECODE(Line) of
- {[{<<"log">>,Msg}]} when is_binary(Msg) ->
+ [<<"log">>, Msg] when is_binary(Msg) ->
% we got a message to log. Log it and continue
- ?LOG_INFO("OS Process Log Message: ~s", [Msg]),
+ ?LOG_INFO("OS Process :: ~s", [Msg]),
readjson(OsProc);
{[{<<"error">>, Id}, {<<"reason">>, Reason}]} ->
throw({list_to_atom(binary_to_list(Id)),Reason});
{[{<<"reason">>, Reason}, {<<"error">>, Id}]} ->
throw({list_to_atom(binary_to_list(Id)),Reason});
Result ->
+ % ?LOG_DEBUG("OS Process Output :: ~p", [Result]),
Result
end.
diff --git a/src/couchdb/couch_query_servers.erl b/src/couchdb/couch_query_servers.erl
index ef2bde3b..5a1dc90a 100644
--- a/src/couchdb/couch_query_servers.erl
+++ b/src/couchdb/couch_query_servers.erl
@@ -18,9 +18,8 @@
-export([init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2,code_change/3,stop/0]).
-export([start_doc_map/2, map_docs/2, stop_doc_map/1]).
-export([reduce/3, rereduce/3,validate_doc_update/5]).
--export([render_doc_show/6,start_view_list/2,render_list_head/5,
- render_list_row/4, render_list_tail/3, render_reduce_head/3,
- render_reduce_row/4]).
+-export([render_doc_show/6, start_view_list/2,
+ render_list_head/4, render_list_row/3, render_list_tail/1]).
% -export([test/0]).
-include("couch_db.hrl").
@@ -183,7 +182,7 @@ render_doc_show(Lang, ShowSrc, DocId, Doc, Req, Db) ->
_ -> {{append_docid(DocId, JsonReqIn)}, couch_doc:to_json_obj(Doc, [revs])}
end,
try couch_os_process:prompt(Pid,
- [<<"show_doc">>, ShowSrc, JsonDoc, JsonReq]) of
+ [<<"show">>, ShowSrc, JsonDoc, JsonReq]) of
FormResp ->
FormResp
after
@@ -195,32 +194,24 @@ start_view_list(Lang, ListSrc) ->
true = couch_os_process:prompt(Pid, [<<"add_fun">>, ListSrc]),
{ok, {Lang, Pid}}.
-render_list_head({_Lang, Pid}, Req, Db, TotalRows, Offset) ->
- Head = {[{<<"total_rows">>, TotalRows}, {<<"offset">>, Offset}]},
+render_list_head({_Lang, Pid}, Req, Db, Head) ->
JsonReq = couch_httpd_external:json_req_obj(Req, Db),
- couch_os_process:prompt(Pid, [<<"list_begin">>, Head, JsonReq]).
+ couch_os_process:prompt(Pid, [<<"list">>, Head, JsonReq]).
-render_list_row({_Lang, Pid}, Req, Db, {{Key, DocId}, Value}) ->
+render_list_row({_Lang, Pid}, Db, {{Key, DocId}, Value}) ->
JsonRow = couch_httpd_view:view_row_obj(Db, {{Key, DocId}, Value}, false),
- JsonReq = couch_httpd_external:json_req_obj(Req, Db),
- couch_os_process:prompt(Pid, [<<"list_row">>, JsonRow, JsonReq]).
+ couch_os_process:prompt(Pid, [<<"list_row">>, JsonRow]);
-render_list_tail({Lang, Pid}, Req, Db) ->
- JsonReq = couch_httpd_external:json_req_obj(Req, Db),
- JsonResp = couch_os_process:prompt(Pid, [<<"list_tail">>, JsonReq]),
+render_list_row({_Lang, Pid}, _, {Key, Value}) ->
+ JsonRow = {[{key, Key}, {value, Value}]},
+ couch_os_process:prompt(Pid, [<<"list_row">>, JsonRow]).
+
+render_list_tail({Lang, Pid}) ->
+ JsonResp = couch_os_process:prompt(Pid, [<<"list_end">>]),
ok = ret_os_process(Lang, Pid),
- JsonResp.
+ JsonResp.
-
-render_reduce_head({_Lang, Pid}, Req, Db) ->
- Head = {[]},
- JsonReq = couch_httpd_external:json_req_obj(Req, Db),
- couch_os_process:prompt(Pid, [<<"list_begin">>, Head, JsonReq]).
-render_reduce_row({_Lang, Pid}, Req, Db, {Key, Value}) ->
- JsonRow = {[{key, Key}, {value, Value}]},
- JsonReq = couch_httpd_external:json_req_obj(Req, Db),
- couch_os_process:prompt(Pid, [<<"list_row">>, JsonRow, JsonReq]).
init([]) ->