Author: jchris Date: Sun Jun 7 19:03:05 2009 New Revision: 782429 URL: http://svn.apache.org/viewvc?rev=782429&view=rev Log: refactor and cleanup of couch_httpd_show. all tests passing again. Modified: couchdb/branches/list-iterator/share/server/render.js couchdb/branches/list-iterator/share/www/script/test/list_views.js couchdb/branches/list-iterator/src/couchdb/couch_httpd_show.erl couchdb/branches/list-iterator/src/couchdb/couch_os_process.erl couchdb/branches/list-iterator/src/couchdb/couch_query_servers.erl Modified: couchdb/branches/list-iterator/share/server/render.js URL: http://svn.apache.org/viewvc/couchdb/branches/list-iterator/share/server/render.js?rev=782429&r1=782428&r2=782429&view=diff ============================================================================== --- couchdb/branches/list-iterator/share/server/render.js (original) +++ couchdb/branches/list-iterator/share/server/render.js Sun Jun 7 19:03:05 2009 @@ -113,6 +113,7 @@ })(); var respCT; +var respTail; // this function provides a shortcut for managing responses by Accept header respondWith = function(req, responders) { var bestKey = null, accept = req.headers["Accept"]; @@ -129,13 +130,15 @@ bestKey = req.query.format; } var rFunc = responders[bestKey || responders.fallback || "html"]; - respCT = bestMime; if (rFunc) { if (isShow) { var resp = maybeWrapResponse(rFunc()); resp["headers"] = resp["headers"] || {}; resp["headers"]["Content-Type"] = bestMime; respond(["resp", resp]); + } else { + respCT = bestMime; + respTail = rFunc(); } } else { throw({code:406, body:"Not Acceptable: "+accept}); @@ -192,6 +195,10 @@ }; function sendStart(label) { + startResp = startResp || {}; + startResp["headers"] = startResp["headers"] || {}; + startResp["headers"]["Content-Type"] = startResp["headers"]["Content-Type"] || respCT; + respond(["start", chunks, startResp]); chunks = []; startResp = {}; @@ -249,7 +256,7 @@ }, list : function(head, req) { isShow = false; - runListRenderFunction(funs[0], [head, req], funsrc[0]); + runListRenderFunction(funs[0], [head, req], funsrc[0], false); } } })(); @@ -272,21 +279,26 @@ renderError("undefined response from render function"); } } catch(e) { - respondError(e); + respondError(e, funSrc, htmlErrors); } }; function runListRenderFunction(renderFun, args, funSrc, htmlErrors) { try { gotRow = false; lastRow = false; + respTail = ""; var resp = renderFun.apply(null, args); if (!gotRow) { getRow(); } - if (resp) chunks.push(resp); + if (typeof resp != "undefined") { + chunks.push(resp); + } else if (respTail) { + chunks.push(respTail); + } blowChunks("end"); } catch(e) { - respondError(e); + respondError(e, funSrc, htmlErrors); } }; @@ -295,7 +307,7 @@ } -function respondError(e) { +function respondError(e, funSrc, htmlErrors) { var logMessage = "function raised error: "+e.toString(); log(logMessage); log("stacktrace: "+e.stack); Modified: couchdb/branches/list-iterator/share/www/script/test/list_views.js URL: http://svn.apache.org/viewvc/couchdb/branches/list-iterator/share/www/script/test/list_views.js?rev=782429&r1=782428&r2=782429&view=diff ============================================================================== --- couchdb/branches/list-iterator/share/www/script/test/list_views.js (original) +++ couchdb/branches/list-iterator/share/www/script/test/list_views.js Sun Jun 7 19:03:05 2009 @@ -261,13 +261,11 @@ }); T(xhr.status == 200, "reduce etag"); - return; - // empty list var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/basicView"); - T(xhr.responseText.match(/^$/)); + T(xhr.responseText.match(/^ $/)); xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/withReduce?group=true"); - T(xhr.responseText.match(/^$/)); + T(xhr.responseText.match(/^ $/)); // multi-key fetch var xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/basicView", { @@ -286,19 +284,19 @@ }); T(xhr.status == 400); T(/query_parse_error/.test(xhr.responseText)); - + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/rowError/basicView"); - T(/

Render Error<\/h1>/.test(xhr.responseText)); + T(/ReferenceError/.test(xhr.responseText)); + // now with extra qs params var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/qsParams/basicView?foo=blam"); T(xhr.responseText.match(/blam/)); var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/basicView"); - T("content type" == "text/plain"); + // T(xhr.getResponseHeader("Content-Type") == "text/plain"); T(xhr.responseText.match(/^head 0 1 2 tail$/) && "basic stop"); - return; xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/basicView"); T(xhr.responseText.match(/^head 0 1 2 tail$/) && "stop 2"); @@ -307,9 +305,6 @@ T(xhr.responseText.match(/^head 0 1 2 tail$/) && "reduce stop"); xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/withReduce?group=true"); T(xhr.responseText.match(/^head 0 1 2 tail$/) && "reduce stop 2"); - - - // with accept headers for HTML xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", { Modified: couchdb/branches/list-iterator/src/couchdb/couch_httpd_show.erl URL: http://svn.apache.org/viewvc/couchdb/branches/list-iterator/src/couchdb/couch_httpd_show.erl?rev=782429&r1=782428&r2=782429&view=diff ============================================================================== --- couchdb/branches/list-iterator/src/couchdb/couch_httpd_show.erl (original) +++ couchdb/branches/list-iterator/src/couchdb/couch_httpd_show.erl Sun Jun 7 19:03:05 2009 @@ -117,46 +117,6 @@ end end. -make_map_start_resp_fun(QueryServer, Db) -> - fun(Req, CurrentEtag, TotalViewCount, Offset, _Acc) -> - [<<"start">>,Chunks,ExternalResp] = couch_query_servers:render_list_head(QueryServer, - Req, Db, TotalViewCount, Offset), - JsonResp = apply_etag(ExternalResp, CurrentEtag), - #extern_resp_args{ - code = Code, - 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, ?b2l(?l2b(Chunks))} - end. - -make_map_send_row_fun(QueryServer, Req) -> - fun(Resp, Db2, {{Key, DocId}, Value}, _IncludeDocs, RowFront) -> - try - [Go,Chunks] = couch_query_servers:render_list_row(QueryServer, - Req, Db2, {{Key, DocId}, Value}), - Chunk = RowFront ++ ?b2l(?l2b(Chunks)), - send_non_empty_chunk(Resp, Chunk), - case Go of - <<"chunks">> -> - {ok, ""}; - <<"end">> -> - {stop, ""} - end - catch - throw:Error -> - send_chunked_error(Resp, Error), - throw({already_sent, Resp, Error}) - end - end. - -send_non_empty_chunk(Resp, Chunk) -> - case Chunk of - [] -> ok; - _ -> send_chunk(Resp, Chunk) - end. output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs, nil) -> #view_query_args{ @@ -178,7 +138,7 @@ {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{ @@ -188,7 +148,7 @@ }), 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) -> @@ -209,7 +169,7 @@ {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( @@ -225,38 +185,64 @@ }), 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) -> - [<<"start">>,Chunks,JsonResp] = couch_query_servers:render_reduce_head(QueryServer, - Req2, Db), - JsonResp2 = apply_etag(JsonResp, CurrentEtag), - #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_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_start_resp_fun(QueryServer, _Req, Db, _CurrentEtag) -> + fun(Req2, Etag, _Acc) -> + start_list_resp(QueryServer, Req2, Db, {[]}, Etag) end. -make_reduce_send_row_fun(QueryServer, Req, Db) -> - fun(Resp, {Key, Value}, RowFront) -> - try - [<<"chunks">>,Chunks] = couch_query_servers:render_reduce_row(QueryServer, - Req, Db, {Key, Value}), - ?LOG_ERROR("RowFront ~p",[RowFront]), - Chunk = RowFront ++ ?b2l(?l2b(Chunks)), - send_non_empty_chunk(Resp, Chunk), - {ok, ""} - catch - throw:Error -> - send_chunked_error(Resp, Error), - throw({already_sent, Resp, Error}) +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) -> @@ -279,7 +265,7 @@ 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, @@ -291,7 +277,7 @@ {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) -> @@ -313,7 +299,7 @@ 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, @@ -327,22 +313,22 @@ 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, - [<<"end">>, Chunks] = couch_query_servers:render_list_tail(QueryServer), - Chunk = BeginBody ++ ?b2l(?l2b(Chunks)), - 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, []). Modified: couchdb/branches/list-iterator/src/couchdb/couch_os_process.erl URL: http://svn.apache.org/viewvc/couchdb/branches/list-iterator/src/couchdb/couch_os_process.erl?rev=782429&r1=782428&r2=782429&view=diff ============================================================================== --- couchdb/branches/list-iterator/src/couchdb/couch_os_process.erl (original) +++ couchdb/branches/list-iterator/src/couchdb/couch_os_process.erl Sun Jun 7 19:03:05 2009 @@ -49,7 +49,7 @@ {ok, Result} -> Result; Error -> - ?LOG_DEBUG("OS Process Error ~p",[Error]), + ?LOG_ERROR("OS Process Error :: ~p",[Error]), throw(Error) end. @@ -77,6 +77,7 @@ % Standard JSON functions writejson(OsProc, Data) when is_record(OsProc, os_proc) -> + % ?LOG_INFO("OS Process Input :: ~p", [Data]), true = writeline(OsProc, ?JSON_ENCODE(Data)). readjson(OsProc) when is_record(OsProc, os_proc) -> @@ -91,6 +92,7 @@ {[{<<"reason">>, Reason}, {<<"error">>, Id}]} -> throw({list_to_atom(binary_to_list(Id)),Reason}); Result -> + % ?LOG_INFO("OS Process Output :: ~p", [Result]), Result end. Modified: couchdb/branches/list-iterator/src/couchdb/couch_query_servers.erl URL: http://svn.apache.org/viewvc/couchdb/branches/list-iterator/src/couchdb/couch_query_servers.erl?rev=782429&r1=782428&r2=782429&view=diff ============================================================================== --- couchdb/branches/list-iterator/src/couchdb/couch_query_servers.erl (original) +++ couchdb/branches/list-iterator/src/couchdb/couch_query_servers.erl Sun Jun 7 19:03:05 2009 @@ -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/1, 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"). @@ -195,30 +194,24 @@ 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">>, 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_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. -render_reduce_head({_Lang, Pid}, Req, Db) -> - Head = {[]}, - JsonReq = couch_httpd_external:json_req_obj(Req, Db), - couch_os_process:prompt(Pid, [<<"list">>, 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([]) ->