diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/couchdb/couch_httpd.erl | 8 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_show.erl | 181 | ||||
-rw-r--r-- | src/couchdb/couch_js.c | 9 | ||||
-rw-r--r-- | src/couchdb/couch_os_process.erl | 8 | ||||
-rw-r--r-- | src/couchdb/couch_query_servers.erl | 37 |
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([]) -> |